The leading agent on Snake Royale, written by a language model.
import random
from collections import deque
def get_move(state):
w, h = state['grid_size']
my_snake = state['my_snake']
my_head = tuple(my_snake[0])
my_length = len(my_snake)
my_index = state['my_index']
snakes = state['snakes']
alive = state.get('alive', [True]*len(snakes))
turn = state.get('turn', 0)
food = {tuple(f) for f in state['food']}
# Build opponent list and obstacles
solid_obstacles = set()
opponents = []
for i, snake in enumerate(snakes):
if not alive[i]: continue
body = snake['body'] if isinstance(snake, dict) else snake
if not body: continue
is_me = (i == my_index)
snake_len = len(body)
if not is_me:
opponents.append({
'id': i,
'len': snake_len,
'head': tuple(body[0]),
'body': [tuple(pt) for pt in body]
})
for pt in body:
solid_obstacles.add(tuple(pt))
directions = {'UP': (0, -1), 'DOWN': (0, 1), 'LEFT': (-1, 0), 'RIGHT': (1, 0)}
def get_neighbors(pt):
nx, ny = pt
for dx, dy in directions.values():
if 0 <= nx + dx < w and 0 <= ny + dy < h:
yield (nx + dx, ny + dy)
# Valid moves
valid_moves = {}
neck = tuple(my_snake[1]) if len(my_snake) > 1 else None
for d_name, (dx, dy) in directions.items():
nx, ny = my_head[0] + dx, my_head[1] + dy
if 0 <= nx < w and 0 <= ny < h:
if (nx, ny) == neck:
continue
if (nx, ny) not in solid_obstacles:
valid_moves[d_name] = (nx, ny)
elif (nx, ny) == tuple(my_snake[-1]) and (nx, ny) not in food:
valid_moves[d_name] = (nx, ny)
if not valid_moves:
for d_name, (dx, dy) in directions.items():
nx, ny = my_head[0] + dx, my_head[1] + dy
if 0 <= nx < w and 0 <= ny < h:
valid_moves[d_name] = (nx, ny)
if not valid_moves:
return "UP"
def get_bfs(starts, avoid_nodes):
dist = {}
q = deque()
for s in starts:
dist[s] = 0
q.append(s)
while q:
curr = q.popleft()
d = dist[curr]
for nxt in get_neighbors(curr):
if nxt not in avoid_nodes and nxt not in dist:
dist[nxt] = d + 1
q.append(nxt)
return dist
# Classify game phase
num_alive = sum(alive)
is_late_game = turn > 350 or num_alive <= 2
is_dominated = my_length > max([opp['len'] for opp in opponents] + [0]) + 2
# Precompute opponent reachability
opp_dists = []
for opp in opponents:
opp_solid = solid_obstacles.copy()
opp_tail = tuple(opp['body'][-1])
if opp_tail in opp_solid:
opp_solid.remove(opp_tail)
my_tail = tuple(my_snake[-1])
if my_tail in opp_solid:
opp_solid.remove(my_tail)
opp_dists.append({
'id': opp['id'],
'len': opp['len'],
'head': opp['head'],
'dist': get_bfs([opp['head']], opp_solid)
})
best_move = None
best_score = -float('inf')
for d_name, next_pos in valid_moves.items():
collision_risk = False
head_to_head_win = False
certain_death = False
weak_snake_nearby = False
# Check collisions with opponents
for opp in opponents:
ox, oy = opp['head']
d = abs(next_pos[0] - ox) + abs(next_pos[1] - oy)
if d == 1:
opp_neck = opp['body'][1] if len(opp['body']) > 1 else None
if next_pos != opp_neck:
if my_length <= opp['len']:
collision_risk = True
else:
head_to_head_win = True
# Extra score for taking weak snakes
if opp['len'] < my_length - 1:
weak_snake_nearby = True
elif d == 0:
certain_death = True
if certain_death:
continue
# Compute my space
my_future_solid = solid_obstacles.copy()
if next_pos not in food:
my_tail = tuple(my_snake[-1])
if my_tail in my_future_solid:
my_future_solid.remove(my_tail)
my_future_solid.add(next_pos)
my_dists = get_bfs([next_pos], my_future_solid)
space = len(my_dists)
# Territory and food scoring
territory = 0
food_score = 0
closest_food_dist = float('inf')
space_advantage = 0
for cell, my_d in my_dists.items():
if cell in food and my_d < closest_food_dist:
closest_food_dist = my_d
my_time = my_d + 1
min_opp_time = float('inf')
min_opp_len = 0
for opp_info in opp_dists:
opp_d = opp_info['dist'].get(cell, float('inf'))
if opp_d < min_opp_time:
min_opp_time = opp_d
min_opp_len = opp_info['len']
elif opp_d == min_opp_time:
min_opp_len = max(min_opp_len, opp_info['len'])
if my_time < min_opp_time:
territory += 1
space_advantage += 1
if cell in food:
food_score += 1000.0 / (my_time + 1)
elif my_time == min_opp_time:
if my_length > min_opp_len:
territory += 0.5
space_advantage += 0.5
if cell in food:
food_score += 500.0 / (my_time + 1)
# Check tail reachability
if next_pos in food:
new_tail = tuple(my_snake[-1])
else:
new_tail = tuple(my_snake[-2]) if len(my_snake) > 1 else tuple(my_snake[0])
tail_reachable = False
for nx, ny in get_neighbors(new_tail):
if (nx, ny) in my_dists or (nx, ny) == next_pos:
tail_reachable = True
break
# Scoring system
score = 0
# Critical: space < length is fatal
if space < my_length:
if tail_reachable:
score -= 1000.0 * (my_length - space)
else:
score -= 50000.0 * (my_length - space)
# Collision risk penalty
if collision_risk:
score -= 10000.0
# Head-to-head wins (especially against weak snakes)
if head_to_head_win:
if weak_snake_nearby:
score += 500.0 # Aggressive hunting bonus
else:
score += 50.0
# Adaptive weighting based on game phase
if is_late_game:
# 1v1: pure aggression and space control
territory_weight = 5.0
closest_food_weight = 3.0
food_score_weight = 1.0
elif is_dominated:
# We're big: hunt weak snakes, control territory
territory_weight = 2.0
closest_food_weight = 1.0
food_score_weight = 0.5
elif num_alive <= 2:
# Few snakes left: focus on direct food + space
territory_weight = 3.0
closest_food_weight = 2.0
food_score_weight = 1.0
else:
# 4-player chaos: balance food and survival
territory_weight = 0.8
closest_food_weight = 4.0
food_score_weight = 1.5
score += territory * territory_weight
score += space * 0.1
score += food_score * food_score_weight
# Food distance penalty
if closest_food_dist != float('inf'):
score -= closest_food_dist * closest_food_weight
# Center bias (stronger in early game)
dist_to_center = abs(next_pos[0] - w/2) + abs(next_pos[1] - h/2)
center_weight = 0.15 if not is_late_game else 0.05
score -= dist_to_center * center_weight
if score > best_score:
best_score = score
best_move = d_name
return best_move if best_move else list(valid_moves.keys())[0]