import unittest from snakes.UltimateBattleSnake import UltimateBattleSnake from server.GameBoard import GameBoard # ── Helpers ─────────────────────────────────────────────────────────────────── def make_board(game_state: dict) -> GameBoard: snake = UltimateBattleSnake() board = GameBoard( game_id=game_state["game"]["id"], width=game_state["board"]["width"], height=game_state["board"]["height"], ruleset=game_state["game"]["ruleset"], source=game_state["game"].get("source", "custom"), map=game_state["game"].get("map", "standard"), snake_class=snake, ) board.read_game_data(game_state) return board def move(game_state: dict) -> str: return make_board(game_state).snake_neat_make_a_move() def gs( my_body: list[tuple], other_bodies: list[list[tuple]] | None = None, foods: list[tuple] | None = None, hazards: list[tuple] | None = None, my_health: int = 90, my_id: str = "me", enemy_health: int = 90, game_type: str = "standard", game_map: str = "standard", hazard_damage: int = 14, width: int = 11, height: int = 11, turn: int = 20, game_id: str = "test-game", ) -> dict: """Build a minimal valid Battlesnake API game-state dict.""" other_bodies = other_bodies or [] foods = foods or [] hazards = hazards or [] def body_dicts(coords): return [{"x": x, "y": y} for x, y in coords] my_snake = { "id": my_id, "name": "UltimateBattleSnake", "health": my_health, "body": body_dicts(my_body), "head": {"x": my_body[0][0], "y": my_body[0][1]}, "length": len(my_body), "latency": "50", "shout": "", } snakes = [my_snake] for i, body in enumerate(other_bodies): snakes.append({ "id": f"enemy-{i}", "name": f"Enemy{i}", "health": enemy_health, "body": body_dicts(body), "head": {"x": body[0][0], "y": body[0][1]}, "length": len(body), "latency": "60", "shout": "", }) ruleset = { "name": game_type, "version": "v1.0.0", "settings": {"hazardDamagePerTurn": hazard_damage}, } return { "game": {"id": game_id, "ruleset": ruleset, "source": "custom", "map": game_map}, "turn": turn, "board": { "height": height, "width": width, "food": body_dicts(foods), "hazards": body_dicts(hazards), "snakes": snakes, }, "you": my_snake, } # ── Tests: basic safety ─────────────────────────────────────────────────────── class TestWallAndBodyAvoidance(unittest.TestCase): def test_avoids_left_wall(self): """Head at x=0, must not go left.""" result = move(gs( my_body=[(0, 5), (1, 5), (2, 5)], other_bodies=[[(9, 9), (9, 8), (9, 7)]], )) self.assertNotEqual(result, "left") def test_avoids_bottom_wall(self): """Head at y=0, must not go down.""" result = move(gs( my_body=[(5, 0), (5, 1), (5, 2)], other_bodies=[[(9, 9), (9, 8), (9, 7)]], )) self.assertNotEqual(result, "down") def test_avoids_right_wall(self): """Head at x=width-1, must not go right.""" result = move(gs( my_body=[(10, 5), (9, 5), (8, 5)], other_bodies=[[(1, 1), (1, 2), (1, 3)]], )) self.assertNotEqual(result, "right") def test_avoids_top_wall(self): """Head at y=height-1, must not go up.""" result = move(gs( my_body=[(5, 10), (5, 9), (5, 8)], other_bodies=[[(1, 1), (1, 2), (1, 3)]], )) self.assertNotEqual(result, "up") def test_avoids_own_body(self): """Head at (5,5) with body going right — must not go right.""" result = move(gs( my_body=[(5, 5), (6, 5), (7, 5), (8, 5)], other_bodies=[[(1, 1), (1, 2), (1, 3)]], foods=[(5, 9)], )) self.assertNotEqual(result, "right") def test_avoids_enemy_body(self): """Enemy body blocks a direction.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(6, 5), (7, 5), (8, 5), (9, 5), (9, 6), (9, 7)]], )) self.assertNotEqual(result, "right") def test_only_one_safe_move_taken(self): """Boxed in three sides — must take the only open move.""" # Head at (1,1), body wraps up and left, wall below and left result = move(gs( my_body=[(1, 1), (1, 2), (2, 2), (2, 1)], other_bodies=[], foods=[(5, 5)], width=7, height=7, )) # Only right is open (wall at x=0, body above and right closes loop) self.assertEqual(result, "right") def test_no_safe_moves_returns_valid_direction(self): """Even if all moves are fatal, must return a valid direction string.""" result = move(gs( my_body=[(0, 0), (0, 1), (1, 1), (1, 0)], other_bodies=[], )) self.assertIn(result, ("up", "down", "left", "right")) # ── Tests: tail stepping ────────────────────────────────────────────────────── class TestTailStepping(unittest.TestCase): def test_can_step_on_own_tail_when_not_stacked(self): """Snake can chase its own tail when it will vacate.""" # Head at (3,3), body forms a U, tail at (3,2) — stepping down is valid board = make_board(gs( my_body=[(3, 3), (2, 3), (2, 2), (3, 2)], other_bodies=[[(9, 9), (9, 8), (9, 7)]], foods=[(8, 8)], )) snake = board.snake_class safe = snake._legal_moves( my_head={"x": 3, "y": 3}, my_body=[{"x": 3, "y": 3}, {"x": 2, "y": 3}, {"x": 2, "y": 2}, {"x": 3, "y": 2}], other_snakes=[], food_set=set(), is_constrictor=False, width=11, height=11, ) self.assertIn("down", safe) def test_cannot_step_on_stacked_tail(self): """Stacked tail (just ate) must NOT be treated as vacatable.""" result = move(gs( my_body=[(5, 5), (5, 4), (4, 4), (4, 5), (4, 5)], # tail stacked at (4,5) other_bodies=[[(9, 9), (9, 8), (9, 7)]], foods=[(8, 8)], )) # (4,5) is to the left — must not be considered safe snake = UltimateBattleSnake() body = [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 4, "y": 4}, {"x": 4, "y": 5}, {"x": 4, "y": 5}] safe = snake._legal_moves( my_head={"x": 5, "y": 5}, my_body=body, other_snakes=[], food_set=set(), is_constrictor=False, width=11, height=11, ) self.assertNotIn("left", safe) # ── Tests: head-to-head collisions ──────────────────────────────────────────── class TestHeadToHead(unittest.TestCase): def test_avoids_h2h_with_equal_length_enemy(self): """Equal-length head-to-head = both die — must avoid.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(7, 5), (7, 4), (7, 3)]], # enemy same length, head at (7,5) foods=[(0, 0)], )) self.assertNotEqual(result, "right") def test_avoids_h2h_with_larger_enemy(self): """Larger enemy head adjacent — must avoid that square.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(7, 5), (7, 4), (7, 3), (7, 2), (7, 1), (6, 1)]], foods=[(0, 0)], )) self.assertNotEqual(result, "right") def test_can_head_hunt_smaller_enemy(self): """We are clearly bigger — moving toward enemy head should be preferred.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3), (5, 2), (5, 1), (4, 1), (4, 2)], other_bodies=[[(7, 5), (7, 4), (7, 3)]], # enemy at (7,5), we have 7 vs 3 foods=[(0, 0)], )) # Moving right (toward enemy) should be chosen self.assertEqual(result, "right") # ── Tests: food ─────────────────────────────────────────────────────────────── class TestFoodBehavior(unittest.TestCase): def test_chases_food_when_critically_low_health(self): """Health=10, food directly above — must go up.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(9, 9), (9, 8), (9, 7)]], foods=[(5, 6)], my_health=10, )) self.assertEqual(result, "up") def test_chases_nearest_food_when_low_health(self): """Health=15, food to the right — must go right.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(1, 1), (1, 2), (1, 3)]], foods=[(6, 5)], my_health=15, )) self.assertEqual(result, "right") def test_avoids_food_in_dead_end(self): """Food is reachable but leads to a dead end — must choose survival over food.""" # 7x7 board: head at (3,3), food at (3,4) which is a dead end due to enemy blocking result = move(gs( my_body=[(3, 3), (3, 2), (3, 1)], other_bodies=[[(2, 4), (2, 5), (3, 5), (4, 5), (4, 4)]], foods=[(3, 4)], width=7, height=7, )) self.assertNotEqual(result, "up") def test_starvation_penalty_applied_when_food_unreachable_in_time(self): """Health < 40 and food is far away — starvation penalty should steer away from that path.""" snake = UltimateBattleSnake() # Verify the _score_move starvation logic is invoked: # health=20, health_after=19, nearest_food=25 — food unreachable # The penalty should reduce the score of that move noticeably from unittest.mock import patch # Just verify choose_move returns a valid direction without crashing result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(1, 1), (1, 2), (1, 3)]], foods=[(0, 10)], # food far away my_health=20, )) self.assertIn(result, ("up", "down", "left", "right")) # ── Tests: duel mode ────────────────────────────────────────────────────────── class TestDuelMode(unittest.TestCase): def test_duel_smaller_snake_does_not_approach_enemy_head(self): """We are shorter — must not go adjacent to enemy head.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(7, 5), (7, 4), (7, 3), (7, 2), (7, 1), (6, 1)]], foods=[(0, 0)], )) self.assertNotEqual(result, "right") def test_duel_larger_snake_approaches_enemy(self): """We are much bigger — head hunting should prefer moving toward enemy.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3), (4, 3), (4, 4), (4, 5), (4, 6), (5, 6)], other_bodies=[[(7, 5), (7, 4), (7, 3)]], foods=[(0, 0)], )) self.assertEqual(result, "right") def test_duel_encasement_reduces_enemy_space(self): """Prefer move that tightens encasement of trapped enemy.""" result = move(gs( my_body=[(2, 3), (2, 2), (1, 2), (1, 3), (1, 4), (2, 4), (3, 4), (3, 5)], other_bodies=[[(4, 3), (5, 3), (5, 2), (4, 2), (4, 1)]], foods=[(0, 0)], width=7, height=7, )) self.assertEqual(result, "right") def test_duel_food_bias_scale_not_doubled(self): """Food bias in duel mode must not be double-counted vs base scoring.""" snake = UltimateBattleSnake() # Run two moves — one with balanced style, one with aggressive style # Both must return a valid direction (regression: double bias could overflow scoring) import os os.environ["BATTLE_SNAKE_DUEL_STYLE"] = "aggressive" result_agg = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(7, 7), (7, 6), (7, 5)]], foods=[(6, 5)], my_health=50, )) os.environ["BATTLE_SNAKE_DUEL_STYLE"] = "safe" result_safe = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(7, 7), (7, 6), (7, 5)]], foods=[(6, 5)], my_health=50, )) os.environ.pop("BATTLE_SNAKE_DUEL_STYLE", None) self.assertIn(result_agg, ("up", "down", "left", "right")) self.assertIn(result_safe, ("up", "down", "left", "right")) def test_duel_length_growth_bonus_when_eating_crosses_threshold(self): """Eating food that makes us equal to or longer than enemy gets bonus.""" snake = UltimateBattleSnake() # our len=3, enemy len=3, food at (6,5) — eating makes us len=4 > 3 result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(8, 5), (8, 4), (8, 3)]], foods=[(6, 5)], my_health=90, )) # Food is to the right and gives us a length advantage — should prefer right self.assertEqual(result, "right") # ── Tests: constrictor mode ─────────────────────────────────────────────────── class TestConstrictorMode(unittest.TestCase): def test_constrictor_tails_never_vacate(self): """In constrictor mode, enemy tails stay blocked.""" snake = UltimateBattleSnake() enemy_body = [ {"x": 3, "y": 3}, {"x": 3, "y": 2}, {"x": 2, "y": 2}, {"x": 2, "y": 3} ] future_body = [ {"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3} ] blocked = snake._simulation_blocked( future_body=future_body, other_snakes=[{"id": "e", "body": enemy_body, "head": {"x": 3, "y": 3}}], food_set=set(), is_constrictor=True, ) # Enemy tail at (2,3) must still be blocked in constrictor self.assertIn((2, 3), blocked) def test_constrictor_avoids_dead_end_with_buffer(self): """Constrictor dead-end buffer (required_space += max(3, len//6)) keeps snake safe.""" result = move(gs( my_body=[(1, 1), (1, 0), (0, 0), (0, 1)], other_bodies=[[(4, 4), (3, 4), (3, 3), (2, 3), (2, 2), (2, 0), (3, 1)]], game_type="constrictor", width=7, height=7, )) self.assertEqual(result, "up") def test_constrictor_returns_valid_move(self): result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(3, 3), (3, 4), (3, 5)]], game_type="constrictor", )) self.assertIn(result, ("up", "down", "left", "right")) # ── Tests: multi-snake mode ─────────────────────────────────────────────────── class TestMultiSnakeMode(unittest.TestCase): def test_multi_snake_returns_valid_move(self): result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[ [(2, 2), (2, 3), (2, 4)], [(8, 8), (8, 7), (8, 6)], ], foods=[(3, 3), (7, 7)], )) self.assertIn(result, ("up", "down", "left", "right")) def test_multi_avoids_contested_h2h(self): """Must not step into a square two equal-length enemies can both reach.""" result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[ [(7, 5), (7, 4), (7, 3)], # equal length, head at (7,5) — (6,5) is contested [(5, 8), (5, 9), (5, 10)], ], foods=[(0, 0)], )) self.assertNotEqual(result, "right") # ── Tests: hazard ───────────────────────────────────────────────────────────── class TestHazard(unittest.TestCase): def test_reads_hazard_damage_from_ruleset(self): """hazardDamagePerTurn must be read from ruleset.settings.""" board = make_board(gs( my_body=[(5, 5), (5, 4), (5, 3)], hazard_damage=22, )) self.assertEqual(board.snake_class._hazard_damage_per_turn(board), 22) def test_hazard_entry_penalizes_score(self): """Moving into a hazard that was there last turn should score lower than a safe move.""" snake = UltimateBattleSnake() snake.game_board = make_board(gs( my_body=[(5, 5), (5, 4), (5, 3)], hazards=[(6, 5)], # hazard to the right hazard_damage=14, )) snake.previous_hazards = {(6, 5)} # was there last turn too snake._enemy_dmaps = [] snake._enemy_heads = [] snake._base_blocked = set() score_right, _ = snake._score_move( move="right", pos={"x": 6, "y": 5}, my_body=[{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}], my_len=3, my_health=90, other_snakes=[], food_set=set(), hazard_set={(6, 5)}, hazard_damage=14, hazard_count={(6, 5): 1}, previous_hazard_set={(6, 5)}, is_constrictor=False, enemy_attack_map={}, enemy_can_grow={}, total_occupancy=0.05, width=11, height=11, deadline=None, ) score_up, _ = snake._score_move( move="up", pos={"x": 5, "y": 6}, my_body=[{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}], my_len=3, my_health=90, other_snakes=[], food_set=set(), hazard_set={(6, 5)}, hazard_damage=14, hazard_count={(6, 5): 1}, previous_hazard_set={(6, 5)}, is_constrictor=False, enemy_attack_map={}, enemy_can_grow={}, total_occupancy=0.05, width=11, height=11, deadline=None, ) self.assertGreater(score_up, score_right) def test_hazard_will_kill_avoids_fatal_corridor(self): """If the only exit from a hazard corridor costs more health than we have, it is fatal.""" snake = UltimateBattleSnake() # Hazard fills x=0..4, health=10, damage=14 — any step through kills us hazard = {(x, y) for x in range(5) for y in range(11)} blocked: set = set() result = snake._hazard_will_kill( point=(0, 5), hazard_set=hazard, hazard_count={}, blocked=blocked, width=11, height=11, health=10, hazard_damage=14, ) self.assertTrue(result) def test_hazard_will_not_kill_when_exit_is_close(self): """If exit is 1 step away and health > damage, it is survivable.""" snake = UltimateBattleSnake() hazard = {(5, 5)} # single hazard cell blocked: set = set() result = snake._hazard_will_kill( point=(5, 5), hazard_set=hazard, hazard_count={}, blocked=blocked, width=11, height=11, health=50, hazard_damage=14, ) self.assertFalse(result) # ── Tests: enemy_can_grow bug fixes (B1/B2/B4) ─────────────────────────────── class TestEnemyCanGrow(unittest.TestCase): def test_b1_enemy_tail_stays_blocked_when_growing(self): """B1: _simulation_blocked keeps enemy tail blocked when enemy_can_grow=True.""" snake = UltimateBattleSnake() future_body = [ {"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3} ] enemy = { "id": "e", "body": [ {"x": 1, "y": 1}, {"x": 1, "y": 0}, {"x": 0, "y": 0}, {"x": 0, "y": 1}, ], "head": {"x": 1, "y": 1}, } blocked = snake._simulation_blocked( future_body=future_body, other_snakes=[enemy], food_set={(2, 1)}, # food adjacent to enemy head → enemy will grow is_constrictor=False, enemy_can_grow={"e": True}, ) self.assertIn((0, 1), blocked) # tail must remain blocked def test_b1_enemy_tail_vacates_when_not_growing(self): """B1: _simulation_blocked removes enemy tail when enemy_can_grow=False.""" snake = UltimateBattleSnake() future_body = [ {"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3} ] enemy = { "id": "e", "body": [ {"x": 1, "y": 1}, {"x": 1, "y": 0}, {"x": 0, "y": 0}, {"x": 0, "y": 1}, ], "head": {"x": 1, "y": 1}, } blocked = snake._simulation_blocked( future_body=future_body, other_snakes=[enemy], food_set=set(), # no food → enemy won't grow is_constrictor=False, enemy_can_grow={"e": False}, ) self.assertNotIn((0, 1), blocked) # tail must be free def test_b2_attack_map_blocks_enemy_tail_when_growing(self): """B2: _build_enemy_attack_map marks enemy tail as NOT steppable when enemy can grow.""" snake = UltimateBattleSnake() my_snake = { "id": "me", "body": [{"x": 6, "y": 6}, {"x": 6, "y": 5}, {"x": 5, "y": 5}, {"x": 5, "y": 6}], "head": {"x": 6, "y": 6}, } enemy = { "id": "e", "body": [ {"x": 3, "y": 3}, {"x": 3, "y": 2}, {"x": 2, "y": 2}, {"x": 2, "y": 3}, ], "head": {"x": 3, "y": 3}, } # Food at (4,3) — enemy head is adjacent, so enemy can grow → tail at (2,3) won't vacate atk = snake._build_enemy_attack_map( my_snake=my_snake, other_snakes=[enemy], food_set={(4, 3)}, is_constrictor=False, width=11, height=11, enemy_can_grow={"e": True}, ) # (2,3) is enemy tail — enemy moving there would require it to vacate, but it won't self.assertIsNone(atk.get((2, 3))) def test_b4_choose_move_passes_enemy_can_grow_to_attack_map(self): """B4: choose_move must pass enemy_can_grow so attack map is accurate.""" # Regression: enemy adjacent to food, its tail should NOT appear in attack_map result = move(gs( my_body=[(5, 5), (5, 4), (5, 3)], other_bodies=[[(3, 3), (3, 2), (2, 2), (2, 3)]], foods=[(4, 3)], # adjacent to enemy head → enemy can grow )) self.assertIn(result, ("up", "down", "left", "right")) # ── Tests: minimax stacked tail (B6) ───────────────────────────────────────── class TestMinimaxStackedTail(unittest.TestCase): def test_b6_stacked_tail_not_treated_as_vacated_in_minimax(self): """B6: _minimax_sim must keep stacked tails in occupancy.""" snake = UltimateBattleSnake() # Enemy has stacked tail (just ate) — body[-1] == body[-2] my_body = [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}] enemy_body = [ {"x": 7, "y": 5}, {"x": 7, "y": 4}, {"x": 7, "y": 3}, {"x": 7, "y": 3}, # stacked tail ] # The stacked tail is at (7,3) — it should remain in occupancy my_occ = {(s["x"], s["y"]) for s in my_body} if not snake._is_tail_stacked(my_body): my_occ.discard((my_body[-1]["x"], my_body[-1]["y"])) en_occ = {(s["x"], s["y"]) for s in enemy_body} if not snake._is_tail_stacked(enemy_body): en_occ.discard((enemy_body[-1]["x"], enemy_body[-1]["y"])) # Stacked tail IS stacked → must remain in en_occ self.assertIn((7, 3), en_occ) def test_b6_non_stacked_tail_vacated_in_minimax(self): """B6: Non-stacked tail must be removed from minimax occupancy.""" snake = UltimateBattleSnake() enemy_body = [ {"x": 7, "y": 5}, {"x": 7, "y": 4}, {"x": 7, "y": 3}, {"x": 6, "y": 3}, # normal tail at (6,3) ] en_occ = {(s["x"], s["y"]) for s in enemy_body} if not snake._is_tail_stacked(enemy_body): en_occ.discard((enemy_body[-1]["x"], enemy_body[-1]["y"])) self.assertNotIn((6, 3), en_occ) # ── Tests: articulation point ───────────────────────────────────────────────── class TestArticulationPenalty(unittest.TestCase): def test_no_penalty_when_not_cut_vertex(self): """Open center of a board is not a cut vertex — penalty should be 0.""" snake = UltimateBattleSnake() penalty = snake._articulation_penalty( point=(5, 5), blocked=set(), width=11, height=11, required_space=3, ) self.assertEqual(penalty, 0.0) def test_severe_penalty_when_smallest_partition_too_small(self): """Entering a cut vertex that traps us in a tiny partition gets 1500 penalty. Layout (3x3 board, P = point under test): . X . X P X ← only up/down are free; removing P splits top-cell from bottom-cell . X . """ snake = UltimateBattleSnake() # Block left, right and all four corners so (1,2) and (1,0) are isolated pockets blocked = {(0, 1), (2, 1), (0, 0), (2, 0), (0, 2), (2, 2)} penalty = snake._articulation_penalty( point=(1, 1), blocked=blocked, width=3, height=3, required_space=5, # both pockets have size 1 < 5 ) self.assertEqual(penalty, 1500.0) # ── Tests: survival tree ────────────────────────────────────────────────────── class TestSurvivalTree(unittest.TestCase): def test_rollout_bonus_positive_for_open_position(self): """Future rollout should return a positive bonus for an open board.""" snake = UltimateBattleSnake() snake._enemy_dmaps = [] snake._enemy_heads = [] my_body = [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}] safe_moves = {"up": {"x": 5, "y": 6}, "left": {"x": 4, "y": 5}, "right": {"x": 6, "y": 5}} bonus = snake._future_rollout_bonus( move="up", safe_moves=safe_moves, my_body=my_body, other_snakes=[], food_set=set(), is_constrictor=False, width=11, height=11, enemy_can_grow={}, deadline=None, ) self.assertGreater(bonus, 0.0) def test_rollout_bonus_negative_for_trapped_position(self): """Rollout into a tiny pocket should return a negative bonus.""" snake = UltimateBattleSnake() snake._enemy_dmaps = [] snake._enemy_heads = [] # Head at (0,0), body fills (0,1), (1,1), (1,0) — moving up leads to a 1-cell pocket my_body = [ {"x": 0, "y": 0}, {"x": 0, "y": 1}, {"x": 1, "y": 1}, {"x": 1, "y": 0}, ] safe_moves = {"right": {"x": 1, "y": 0}} # only our tail square (will vacate) # Use right if legal, else just test the tree score directly sc = snake._future_position_score( my_body=[ {"x": 0, "y": 1}, {"x": 0, "y": 0}, {"x": 1, "y": 1}, {"x": 1, "y": 0}, ], # after moving up from (0,0) into a tiny space other_snakes=[], food_set=set(), is_constrictor=False, width=3, height=3, enemy_can_grow={}, deadline=None, ) self.assertLess(sc, 0.0) def test_death_veto_prevents_stepping_into_trap(self): """DEATH_VETO must exclude moves the tree identifies as certainly fatal.""" # Head trapped in a corner with only one exit that leads to a dead end result = move(gs( my_body=[(0, 1), (0, 2), (1, 2), (1, 1), (1, 0)], other_bodies=[[(3, 3), (3, 4), (4, 4), (4, 3), (4, 2), (3, 2)]], foods=[], width=5, height=5, )) self.assertIn(result, ("up", "down", "left", "right")) # ── Tests: territory / Voronoi ──────────────────────────────────────────────── class TestTerritory(unittest.TestCase): def test_territory_positive_when_alone(self): """With no enemies, territory score should equal board cells (all ours).""" snake = UltimateBattleSnake() snake._enemy_heads = [] snake._enemy_dmaps = [] score = snake._territory_fast( my_pos=(5, 5), blocked=set(), width=11, height=11, ) self.assertEqual(score, 0) # no enemies → returns 0 (no comparison possible) def test_territory_positive_when_closer_to_center(self): """Snake closer to center should have more territory than enemy stuck in a corner.""" snake = UltimateBattleSnake() enemy_head = (0, 0) snake._enemy_heads = [enemy_head] snake._enemy_dmaps = [snake._distance_map(enemy_head, set(), 11, 11)] score = snake._territory_fast( my_pos=(5, 5), blocked=set(), width=11, height=11, ) self.assertGreater(score, 0) # ── Tests: version ──────────────────────────────────────────────────────────── class TestVersion(unittest.TestCase): def test_version_matches_registry(self): from snakes import SNAKE_REGISTRY, get_snake_version self.assertEqual(UltimateBattleSnake.VERSION, "4.5.0") self.assertEqual(get_snake_version("UltimateBattleSnake"), "4.5.0") self.assertEqual(SNAKE_REGISTRY["UltimateBattleSnake"], "4.5.0") def test_instance_version_matches_class(self): snake = UltimateBattleSnake() self.assertEqual(snake.version, UltimateBattleSnake.VERSION) def test_builder_returns_ultimate_battle_snake(self): from snakes import SnakeBuilder snake = SnakeBuilder.build("UltimateBattleSnake") self.assertIsInstance(snake, UltimateBattleSnake) # ── Tests: C1 — Snail Mode hazard stack counting ───────────────────────────── class TestSnailModeHazardStack(unittest.TestCase): def _base_body(self): return [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}] def _score(self, snake, pos, hazard_set, hazard_count, health=90): snake._enemy_dmaps = [] snake._enemy_heads = [] snake._base_blocked = set() sc, _ = snake._score_move( move="right", pos=pos, my_body=self._base_body(), my_len=3, my_health=health, other_snakes=[], food_set=set(), hazard_set=hazard_set, hazard_damage=14, hazard_count=hazard_count, previous_hazard_set=hazard_set, is_constrictor=False, enemy_attack_map={}, enemy_can_grow={}, total_occupancy=0.05, width=11, height=11, deadline=None, ) return sc def test_stacked_hazard_penalizes_more_than_single(self): """C1: A tile with stack=3 must score lower than the same tile with stack=1.""" snake = UltimateBattleSnake() pos = {"x": 6, "y": 5} pt = (6, 5) score_single = self._score(snake, pos, {pt}, {pt: 1}) score_triple = self._score(snake, pos, {pt}, {pt: 3}) self.assertGreater(score_single, score_triple, "triple-stacked hazard must score lower than single-stack") def test_single_stack_hazard_matches_baseline(self): """C1: stack=1 in hazard_count should behave identically to no entry in dict.""" snake = UltimateBattleSnake() pos = {"x": 6, "y": 5} pt = (6, 5) score_explicit = self._score(snake, pos, {pt}, {pt: 1}) score_default = self._score(snake, pos, {pt}, {}) self.assertAlmostEqual(score_explicit, score_default, places=3, msg="explicit stack=1 and implicit default should produce identical scores") def test_hazard_count_built_from_duplicate_hazard_coords(self): """C1: hazard_count correctly counts multiple entries for the same tile.""" snake = UltimateBattleSnake() hazards = [{"x": 3, "y": 3}, {"x": 3, "y": 3}, {"x": 3, "y": 3}] hazard_set = set() hazard_count: dict = {} for h in hazards: pt = (h["x"], h["y"]) hazard_set.add(pt) hazard_count[pt] = hazard_count.get(pt, 0) + 1 self.assertEqual(hazard_count.get((3, 3)), 3) self.assertEqual(len(hazard_set), 1) # ── Tests: C2 — food eaten on hazard tile → no minimax hazard penalty ──────── class TestHazardFoodMinimax(unittest.TestCase): def _make_body(self, coords): return [{"x": x, "y": y} for x, y in coords] def test_c2_no_hazard_penalty_when_food_eaten(self): """C2: eating food on a hazard tile must not subtract hazard health in minimax.""" snake = UltimateBattleSnake() my_body = self._make_body([(5, 5), (5, 4), (5, 3)]) en_body = self._make_body([(9, 9), (9, 8), (9, 7)]) food_set = {(6, 5)} # food at the hazard tile hazard_set = {(6, 5)} # same tile is hazard hazard_count = {(6, 5): 1} # Healthy snake, one-step minimax: eating the food should give health=100 # C2 means: health after eating = 100 (food resets), no hazard deduction # We can verify by checking the minimax with depth=1 doesn't die of hazard val_with_food = snake._minimax_sim( my_body=my_body, enemy_body=en_body, food_set=food_set, hazard_set=hazard_set, my_health=100, enemy_health=100, hazard_damage=99, hazard_count=hazard_count, # damage=99 would kill if applied width=11, height=11, depth=1, alpha=-1e9, beta=1e9, deadline=None, ) # If C2 is correct, my snake isn't dead from hazard+food, so value should not be -3000 self.assertGreater(val_with_food, -3000.0, "C2: eating food on hazard must not apply hazard damage — snake should survive") def test_c2_score_move_no_health_penalty_with_food(self): """C2: _score_move must not deduct hazard damage when food is eaten on the tile.""" snake = UltimateBattleSnake() snake._enemy_dmaps = [] snake._enemy_heads = [] snake._base_blocked = set() body = self._make_body([(5, 5), (5, 4), (5, 3)]) pt = (6, 5) # Scenario: health=15, hazard_damage=99. Without C2, food+hazard would kill. # With C2 fix, food resets health to 100 and hazard is NOT subtracted. sc_food_on_hazard, _ = snake._score_move( move="right", pos={"x": 6, "y": 5}, my_body=body, my_len=3, my_health=15, other_snakes=[], food_set={pt}, hazard_set={pt}, hazard_damage=99, hazard_count={pt: 1}, previous_hazard_set={pt}, is_constrictor=False, enemy_attack_map={}, enemy_can_grow={}, total_occupancy=0.05, width=11, height=11, deadline=None, ) # Without food, same lethal hazard tile would cause health_after = 15-1-99 = -85 → -10000 sc_no_food_on_hazard, _ = snake._score_move( move="right", pos={"x": 6, "y": 5}, my_body=body, my_len=3, my_health=15, other_snakes=[], food_set=set(), hazard_set={pt}, hazard_damage=99, hazard_count={pt: 1}, previous_hazard_set={pt}, is_constrictor=False, enemy_attack_map={}, enemy_can_grow={}, total_occupancy=0.05, width=11, height=11, deadline=None, ) self.assertGreater(sc_food_on_hazard, sc_no_food_on_hazard, "C2: eating food on hazard must score much higher than entering same hazard without food") # ── Tests: C3 — _hazard_will_kill includes baseline -1/turn ────────────────── class TestHazardWillKillBaseline(unittest.TestCase): def test_c3_baseline_included_borderline_case(self): """C3: with old math (no baseline), health=15, damage=14, 1 step would survive. With C3 fix (baseline included), 15 - 1*(1+14)=0 → fatal.""" snake = UltimateBattleSnake() hazard = {(5, 5)} result = snake._hazard_will_kill( point=(5, 5), hazard_set=hazard, hazard_count={}, blocked=set(), width=11, height=11, health=15, hazard_damage=14, ) self.assertTrue(result, "C3: health=15 damage=14 → 15-(1+14)=0 → fatal (baseline -1/turn must be counted)") def test_c3_survives_when_health_exceeds_total_cost(self): """C3: health=17, damage=14, 1-step exit → 17-(1+14)=2 > 0 → survivable.""" snake = UltimateBattleSnake() hazard = {(5, 5)} result = snake._hazard_will_kill( point=(5, 5), hazard_set=hazard, hazard_count={}, blocked=set(), width=11, height=11, health=17, hazard_damage=14, ) self.assertFalse(result, "C3: health=17 damage=14 → 17-(1+14)=2 > 0 → should survive") def test_c3_stacked_hazard_kills_faster(self): """C3+C1: stack=2 doubles per-step hazard cost, killing snakes that would survive stack=1.""" snake = UltimateBattleSnake() pt = (5, 5) hazard = {pt} # health=20, damage=14, stack=2 → per_step=1+14*2=29 → 20-29=-9 → fatal result_stacked = snake._hazard_will_kill( point=pt, hazard_set=hazard, hazard_count={pt: 2}, blocked=set(), width=11, height=11, health=20, hazard_damage=14, ) # Same health, stack=1 → per_step=15 → 20-15=5 → survivable result_single = snake._hazard_will_kill( point=pt, hazard_set=hazard, hazard_count={pt: 1}, blocked=set(), width=11, height=11, health=20, hazard_damage=14, ) self.assertTrue(result_stacked, "stack=2 should be fatal at health=20") self.assertFalse(result_single, "stack=1 should be survivable at health=20") # ── Tests: C4 — enemy tail vacate in _legal_moves ──────────────────────────── class TestEnemyTailVacate(unittest.TestCase): def test_c4_can_step_on_enemy_tail_when_not_growing(self): """C4: _legal_moves allows moving onto enemy tail if enemy won't grow.""" snake = UltimateBattleSnake() # My head at (5,5), enemy tail at (4,5) — the only open direction besides (6,5) my_body = [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}] enemy = { "id": "e", "head": {"x": 4, "y": 6}, "body": [{"x": 4, "y": 6}, {"x": 4, "y": 7}, {"x": 4, "y": 5}], # tail at (4,5) } my_head = my_body[0] moves = snake._legal_moves( my_head=my_head, my_body=my_body, other_snakes=[enemy], food_set=set(), is_constrictor=False, width=11, height=11, enemy_can_grow={"e": False}, # enemy won't grow ) # (4,5) is the enemy tail and should be accessible accessible = {(v["x"], v["y"]) for v in moves.values()} self.assertIn((4, 5), accessible, "C4: enemy tail that will vacate must be a legal move") def test_c4_cannot_step_on_enemy_tail_when_growing(self): """C4: enemy tail stays blocked when enemy is about to grow.""" snake = UltimateBattleSnake() my_body = [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}] enemy = { "id": "e", "head": {"x": 4, "y": 6}, "body": [{"x": 4, "y": 6}, {"x": 4, "y": 7}, {"x": 4, "y": 5}], } my_head = my_body[0] moves = snake._legal_moves( my_head=my_head, my_body=my_body, other_snakes=[enemy], food_set=set(), is_constrictor=False, width=11, height=11, enemy_can_grow={"e": True}, # enemy will grow — tail stays ) accessible = {(v["x"], v["y"]) for v in moves.values()} self.assertNotIn((4, 5), accessible, "C4: enemy tail that will NOT vacate must stay blocked") def test_c4_constrictor_enemy_tails_always_blocked(self): """C4: in constrictor mode enemy tails never vacate (no growth/food mechanics).""" snake = UltimateBattleSnake() my_body = [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}] enemy = { "id": "e", "head": {"x": 4, "y": 6}, "body": [{"x": 4, "y": 6}, {"x": 4, "y": 7}, {"x": 4, "y": 5}], } my_head = my_body[0] moves = snake._legal_moves( my_head=my_head, my_body=my_body, other_snakes=[enemy], food_set=set(), is_constrictor=True, width=11, height=11, enemy_can_grow={"e": False}, ) accessible = {(v["x"], v["y"]) for v in moves.values()} self.assertNotIn((4, 5), accessible, "C4: constrictor mode — enemy tail always stays blocked") # ── Tests: C5 — mode detection from ruleset + map ──────────────────────────── class TestModeDetection(unittest.TestCase): def test_c5_snail_map_detected(self): """C5: game map 'snail_mode' must be recognised even when ruleset name is 'standard'.""" board = make_board(gs( my_body=[(5, 5), (5, 4), (5, 3)], game_type="standard", game_map="snail_mode", )) snake = UltimateBattleSnake() move = snake.choose_move(board) self.assertIn(move, ("up", "down", "left", "right")) def test_c5_constrictor_ruleset_detected(self): """C5: ruleset name 'constrictor' routes to constrictor mode handler.""" board = make_board(gs( my_body=[(5, 5), (5, 4), (5, 3)], game_type="constrictor", )) snake = UltimateBattleSnake() move = snake.choose_move(board) self.assertIn(move, ("up", "down", "left", "right")) # ── Tests: E1 — probabilistic enemy growth check ───────────────────────────── class TestEnemyCanGrow(unittest.TestCase): def _enemy(self, head:tuple, body:list, health:int=90) -> dict: return { "id": "e", "head": {"x": head[0], "y": head[1]}, "body": [{"x": x, "y": y} for x, y in body], "health": health, } def test_e1_returns_true_when_adjacent_food_accessible(self): """E1: enemy adjacent to reachable food → True.""" snake = UltimateBattleSnake() enemy = self._enemy((5, 5), [(5, 5), (5, 4), (5, 3)]) food_set = {(6, 5)} self.assertTrue(snake._enemy_can_grow_this_turn(enemy, food_set)) def test_e1_returns_false_when_no_adjacent_food(self): """E1: enemy with no adjacent food → False.""" snake = UltimateBattleSnake() enemy = self._enemy((5, 5), [(5, 5), (5, 4), (5, 3)]) food_set = {(9, 9)} self.assertFalse(snake._enemy_can_grow_this_turn(enemy, food_set)) def test_e1_returns_false_when_food_tile_blocked_by_body(self): """E1: food tile occupied by a body segment → enemy can't eat → False.""" snake = UltimateBattleSnake() enemy = self._enemy((5, 5), [(5, 5), (5, 4), (5, 3)]) food_set = {(6, 5)} # Food tile (6,5) is occupied by another snake's body all_occupied = {(6, 5)} self.assertFalse( snake._enemy_can_grow_this_turn(enemy, food_set, all_occupied), "E1: food tile blocked by body → enemy cannot eat → False", ) def test_e1_hungry_eats_even_when_contested(self): """E1: hungry enemy (health < 40) eats adjacent food even when contested.""" snake = UltimateBattleSnake() enemy = self._enemy((5, 5), [(5, 5), (5, 4), (5, 3)], health=20) food_set = {(6, 5)} # Even if occupied set marks food tile as blocked by some body, # a hungry enemy still needs to eat — but if food tile is blocked, they CAN'T eat. # E1 skips blocked tiles regardless of health. all_occupied = {(6, 5)} # Blocked food → False (physical impossibility overrides hunger) self.assertFalse(snake._enemy_can_grow_this_turn(enemy, food_set, all_occupied)) def test_e1_hungry_eats_accessible_food(self): """E1: hungry enemy with accessible food → True.""" snake = UltimateBattleSnake() enemy = self._enemy((5, 5), [(5, 5), (5, 4), (5, 3)], health=15) food_set = {(6, 5)} self.assertTrue(snake._enemy_can_grow_this_turn(enemy, food_set, set())) # ── Tests: E2 — per-turn BFS transposition cache ───────────────────────────── class TestBFSCache(unittest.TestCase): def test_e2_cache_hit_returns_same_result(self): """E2: second call with identical args must return cached value.""" snake = UltimateBattleSnake() snake._bfs_cache = {} snake._bfs_cache_turn = 0 blocked = frozenset([(1, 0), (0, 1)]) result1 = snake._flood_fill_count((0, 0), set(blocked), 11, 11) result2 = snake._flood_fill_count((0, 0), set(blocked), 11, 11) self.assertEqual(result1, result2) def test_e2_cache_populated_after_call(self): """E2: cache dict must contain an entry after the first call.""" snake = UltimateBattleSnake() snake._bfs_cache = {} snake._bfs_cache_turn = 0 snake._flood_fill_count((5, 5), set(), 11, 11) self.assertGreater(len(snake._bfs_cache), 0, "cache must be populated after a call") def test_e2_cache_resets_on_new_turn(self): """E2: cache must clear when turn number changes.""" snake = UltimateBattleSnake() snake._bfs_cache = {"stale": 42} snake._bfs_cache_turn = 0 # Simulate turn change by calling choose_move via make_board with a new turn board = make_board(gs( my_body=[(5, 5), (5, 4), (5, 3)], turn=99, )) snake.choose_move(board) self.assertEqual(snake._bfs_cache_turn, 99, "cache turn must update after choose_move") def test_e2_different_blocked_sets_give_different_results(self): """E2: different blocked sets must not collide in the cache.""" snake = UltimateBattleSnake() snake._bfs_cache = {} r_open = snake._flood_fill_count((5, 5), set(), 11, 11) r_blocked = snake._flood_fill_count((5, 5), {(5, 6), (6, 5), (4, 5), (5, 4)}, 11, 11) self.assertGreater(r_open, r_blocked, "more blocked cells must reduce reachable space") # ── Tests: E3 — Snail Mode trail scoring ───────────────────────────────────── class TestSnailTrailScoring(unittest.TestCase): def _score_snail(self, snake, pos, hazard_set, hazard_count, is_snail=True): snake._enemy_dmaps = [] snake._enemy_heads = [] snake._base_blocked = set() snake._is_snail = is_snail body = [{"x": 5, "y": 5}, {"x": 5, "y": 4}, {"x": 5, "y": 3}] sc, _ = snake._score_move( move="right", pos=pos, my_body=body, my_len=3, my_health=90, other_snakes=[], food_set=set(), hazard_set=hazard_set, hazard_damage=14, hazard_count=hazard_count, previous_hazard_set=hazard_set, is_constrictor=False, enemy_attack_map={}, enemy_can_grow={}, total_occupancy=0.05, width=11, height=11, deadline=None, ) return sc def test_e3_snail_penalises_high_adjacent_hazard_density(self): """E3: move into area surrounded by hazard scores worse in snail mode.""" snake = UltimateBattleSnake() pos = {"x": 6, "y": 5} pt = (6, 5) # Neighbours of (6,5): (7,5),(5,5),(6,6),(6,4) — surround with hazard hazard_neighbors = {(7, 5), (6, 6), (6, 4)} score_with_hazard = self._score_snail(snake, pos, hazard_neighbors, {}, is_snail=True) score_no_hazard = self._score_snail(snake, pos, set(), {}, is_snail=True) self.assertLess(score_with_hazard, score_no_hazard, "E3: move into hazard-dense area must score lower in snail mode") def test_e3_snail_rewards_hazard_free_neighbours(self): """E3: same position scores higher when neighbours are hazard-free vs hazard-filled.""" snake = UltimateBattleSnake() pos = {"x": 6, "y": 5} # No hazard around position — all neighbours are free score_clear = self._score_snail(snake, pos, set(), {}, is_snail=True) # All neighbours are hazard (stacked) — heavy risk hazard_all = {(7, 5), (6, 6), (6, 4)} # 3 of 4 neighbours (4th is own body) score_hazard_ring = self._score_snail(snake, pos, hazard_all, {n: 2 for n in hazard_all}, is_snail=True) self.assertGreater(score_clear, score_hazard_ring, "E3: hazard-free surroundings should score higher than hazard-dense surroundings") def test_e3_snail_scoring_not_applied_outside_snail_mode(self): """E3: snail trail scoring is not applied when _is_snail is False.""" snake = UltimateBattleSnake() pos = {"x": 6, "y": 5} hazard_neighbors = {(7, 5), (6, 6), (6, 4)} score_snail = self._score_snail(snake, pos, hazard_neighbors, {}, is_snail=True) score_normal = self._score_snail(snake, pos, hazard_neighbors, {}, is_snail=False) # In normal mode the snail adjacency penalty is absent — scores should differ self.assertLess(score_snail, score_normal, "E3: snail trail penalty must only apply in snail mode") # ── Tests: GameBoard is_ladder source fix ───────────────────────────────────── class TestGameBoardIsLadder(unittest.TestCase): def _board(self, source: str) -> GameBoard: state = gs(my_body=[(5, 5), (5, 4), (5, 3)]) state["game"]["source"] = source return make_board(state) def test_ladder_source_is_competitive(self): self.assertTrue(self._board("ladder").is_ladder) def test_league_source_is_competitive(self): self.assertTrue(self._board("league").is_ladder) def test_arena_source_is_competitive(self): self.assertTrue(self._board("arena").is_ladder) def test_custom_source_is_not_competitive(self): self.assertFalse(self._board("custom").is_ladder) def test_challenge_source_is_not_competitive(self): self.assertFalse(self._board("challenge").is_ladder) def test_tournament_source_is_not_competitive(self): self.assertFalse(self._board("tournament").is_ladder) if __name__ == "__main__": unittest.main()