The leading agent on Snake, written by a language model.
"""Gen621 Hybrid Dominator - Space domination + predictive cutting + adaptive tactics."""
import random
from collections import deque
def get_move(state):
head = state['my_snake'][0]
w, h = state['grid_size']
body = set(map(tuple, state['my_snake']))
enemy_list = state['enemy_snake']
enemy = set(map(tuple, enemy_list)) if enemy_list else set()
enemy_head = tuple(enemy_list[0]) if enemy_list else None
occupied = body | enemy
food_set = set(map(tuple, state['food']))
my_len = len(state['my_snake'])
enemy_len = len(enemy_list)
turn = state['turn']
my_dir = state['my_direction']
enemy_dir = state['enemy_direction']
memory = state['memory']
if 'init' not in memory:
memory['init'] = True
memory['enemy_positions'] = deque(maxlen=10)
memory['threat_level'] = 0
memory['dominant_direction'] = None
# Track enemy positions for pattern detection
if enemy_head:
memory['enemy_positions'].append(enemy_head)
# Possible moves
moves = {
'UP': (head[0], head[1] - 1),
'DOWN': (head[0], head[1] + 1),
'LEFT': (head[0] - 1, head[1]),
'RIGHT': (head[0] + 1, head[1]),
}
# Filter safe moves (no self-collision)
safe = {m: pos for m, pos in moves.items()
if 0 <= pos[0] < w and 0 <= pos[1] < h and pos not in body}
if not safe:
return random.choice(['UP', 'DOWN', 'LEFT', 'RIGHT'])
def dir_offset(direction):
"""Convert direction to (dx, dy)."""
dirs = {'UP': (0, -1), 'DOWN': (0, 1), 'LEFT': (-1, 0), 'RIGHT': (1, 0)}
return dirs.get(direction, (0, 0))
def predict_enemy(steps):
"""Predict enemy head position N steps ahead."""
if not enemy_head or not enemy_dir:
return set()
predicted = set()
dx, dy = dir_offset(enemy_dir)
x, y = enemy_head
for step in range(steps):
x += dx
y += dy
if 0 <= x < w and 0 <= y < h:
predicted.add((x, y))
else:
break
return predicted
def flood_fill(start_pos, obstacles, max_iter=400):
"""Count reachable cells from a position."""
visited = {start_pos}
q = deque([start_pos])
count = 1
while q and count < max_iter:
x, y = q.popleft()
for dx, dy in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
nx, ny = x + dx, y + dy
if (0 <= nx < w and 0 <= ny < h and
(nx, ny) not in visited and
(nx, ny) not in obstacles):
visited.add((nx, ny))
q.append((nx, ny))
count += 1
return count
def is_in_danger(pos):
"""Check if a position is in immediate danger from enemy."""
if not enemy_head:
return False
# Check if enemy can reach this position in 1-2 turns
enemy_next_moves = {
(enemy_head[0], enemy_head[1] - 1),
(enemy_head[0], enemy_head[1] + 1),
(enemy_head[0] - 1, enemy_head[1]),
(enemy_head[0] + 1, enemy_head[1]),
}
if pos in enemy_next_moves:
return True
# Extended danger zone for aggressive opponents
for ex, ey in enemy_next_moves:
if 0 <= ex < w and 0 <= ey < h:
extended = {
(ex, ey - 1), (ex, ey + 1),
(ex - 1, ey), (ex + 1, ey),
}
if pos in extended:
return True
return False
def find_food_path(start, food_targets):
"""BFS to nearest food, avoiding obstacles."""
if not food_targets:
return None
q = deque([(start, [start])])
visited = {start}
max_dist = 100
while q:
pos, path = q.popleft()
if len(path) > max_dist:
continue
if pos in food_targets:
return path[1] if len(path) > 1 else start
x, y = pos
for dx, dy in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
nx, ny = x + dx, y + dy
if (0 <= nx < w and 0 <= ny < h and
(nx, ny) not in visited and
(nx, ny) not in body and
(nx, ny) not in enemy):
visited.add((nx, ny))
q.append(((nx, ny), path + [(nx, ny)]))
return None
def score_move(move_name, pos):
"""Score a move based on multiple factors."""
score = 0
# 1. Space control - prioritize moves with more accessible space
obstacles = body | enemy
space = flood_fill(pos, obstacles, 200)
score += space * 0.5
# 2. Food proximity
closest_food_dist = min([abs(pos[0] - f[0]) + abs(pos[1] - f[1])
for f in food_set], default=20)
score -= closest_food_dist * 0.3
# 3. Avoid danger zones
if is_in_danger(pos):
score -= 50
# 4. Avoid being trapped
reachable = space
if reachable < 5:
score -= 100
# 5. Favor moving toward enemy when we're longer
if my_len > enemy_len and enemy_head:
dist_to_enemy = abs(pos[0] - enemy_head[0]) + abs(pos[1] - enemy_head[1])
score -= dist_to_enemy * 0.2 # Negative subtraction = approach
# 6. Avoid moving directly into predicted enemy path when shorter
if my_len <= enemy_len:
predicted_enemy = predict_enemy(2)
if pos in predicted_enemy:
score -= 50
return score
# Score all safe moves
best_move = None
best_score = float('-inf')
for move_name, pos in safe.items():
if pos in enemy:
continue
move_score = score_move(move_name, pos)
if move_score > best_score:
best_score = move_score
best_move = move_name
# If no good move found, use safe escape
if best_move is None:
best_move = random.choice(list(safe.keys()))
# Fallback to any safe move
if best_move not in safe:
best_move = random.choice(list(safe.keys()))
return best_move