import unittest from time import perf_counter from snakes import SnakeBuilder, get_snake_version from snakes.ApexBattleSnake import ApexBattleSnake from snakes.PrismBattleSnake_GPT_5_6_Sol import PrismBattleSnake_GPT_5_6_Sol from snakes.bitboard import BitBoard from snakes.bitboard_duel_search import BitboardDuelSearch class TestBitBoard(unittest.TestCase): def test_flood_fill_respects_walls(self): board = BitBoard(3, 3) blocked = board.set_to_bits({(1, 0), (1, 1), (1, 2)}) self.assertEqual(board.flood_count(board.idx(0, 1), blocked), 3) self.assertEqual(board.path_distance(board.idx(0, 1), board.idx(2, 1), blocked), None) def test_territory_counts_ties_for_neither_side(self): board = BitBoard(5, 1) self.assertEqual(board.territory(board.idx(0, 0), [board.idx(4, 0)], 0), 0) def test_territory_propagates_through_contested_cells(self): board = BitBoard(5, 3) blocked = board.set_to_bits({(0, 1), (1, 1), (3, 1), (4, 1)}) self.assertEqual(board.territory(board.idx(0, 0), [board.idx(4, 0)], blocked), 0) def test_territory_ignores_enemy_only_disconnected_space_like_apex(self): board = BitBoard(5, 1) blocked = board.set_to_bits({(2, 0)}) self.assertEqual(board.territory(board.idx(0, 0), [board.idx(4, 0)], blocked), 2) def test_nearest_food_returns_shortest_distance(self): board = BitBoard(5, 5) food = board.set_to_bits({(4, 4), (2, 1)}) self.assertEqual(board.nearest_food(board.idx(0, 0), food, 0), (3, board.idx(2, 1))) def test_nearest_food_uses_apex_direction_order_for_ties(self): board = BitBoard(3, 3) food = board.set_to_bits({(1, 2), (0, 1), (2, 1), (1, 0)}) self.assertEqual(board.nearest_food(board.idx(1, 1), food, 0), (1, board.idx(1, 2))) class TestPrismBattleSnake_GPT_5_6_Sol(unittest.TestCase): def test_api_name_and_version_are_exposed(self): snake = PrismBattleSnake_GPT_5_6_Sol() self.assertEqual(snake.name, "PrismBattleSnake") self.assertEqual(snake.version, "1.1.0") self.assertEqual(get_snake_version("PrismBattleSnake_GPT_5_6_Sol"), "1.1.0") self.assertIsInstance(SnakeBuilder.build("PrismBattleSnake_GPT_5_6_Sol"), PrismBattleSnake_GPT_5_6_Sol) def test_bitboard_primitives_match_apex(self): apex = ApexBattleSnake() prism = PrismBattleSnake_GPT_5_6_Sol() blocked = {(1, 0), (1, 1), (3, 2), (3, 3)} self.assertEqual( prism._flood_fill_count((0, 0), blocked, 5, 5), apex._flood_fill_count((0, 0), blocked, 5, 5), ) self.assertEqual( prism._distance_map((0, 0), blocked, 5, 5), apex._distance_map((0, 0), blocked, 5, 5), ) self.assertEqual( prism._path_distance((0, 0), (4, 4), blocked, 5, 5), apex._path_distance((0, 0), (4, 4), blocked, 5, 5), ) def test_mutated_blocked_set_does_not_return_stale_result(self): snake = PrismBattleSnake_GPT_5_6_Sol() blocked: set[tuple[int, int]] = set() open_count = snake._flood_fill_count((1, 1), blocked, 3, 3) blocked.update({(0, 1), (1, 0), (2, 1), (1, 2)}) trapped_count = snake._flood_fill_count((1, 1), blocked, 3, 3) self.assertEqual(open_count, 9) self.assertEqual(trapped_count, 1) def test_bitboard_duel_search_values_length_advantage(self): snake = PrismBattleSnake_GPT_5_6_Sol() my_body = [{"x": 1, "y": 0}, {"x": 0, "y": 0}, {"x": 0, "y": 1}] enemy_body = [{"x": 1, "y": 2}, {"x": 0, "y": 2}] value = snake._minimax_sim( my_body=my_body, enemy_body=enemy_body, food_set=set(), hazard_set=set(), my_health=100, enemy_health=100, hazard_damage=15, hazard_count={}, width=3, height=3, depth=2, alpha=-1e9, beta=1e9, deadline=None, ) self.assertGreater(value, 0) def test_candidate_search_resolves_enemy_reply_on_the_same_turn(self): board = BitBoard(3, 3) search = BitboardDuelSearch( board=board, food=set(), hazards=set(), hazard_count={}, hazard_damage=15, deadline=None, ) my_body = [{"x": 0, "y": 1}, {"x": 0, "y": 0}] enemy_body = [{"x": 2, "y": 1}, {"x": 2, "y": 0}] value, depth = search.search_candidate( my_body=my_body, enemy_body=enemy_body, my_target=(1, 1), my_health=100, enemy_health=100, max_depth=1, previous_hazards=set(), ) self.assertEqual(value, -500.0) self.assertEqual(depth, 1) def test_candidate_search_does_not_advance_our_snake_twice_at_root(self): board = BitBoard(4, 1) search = BitboardDuelSearch( board=board, food=set(), hazards=set(), hazard_count={}, hazard_damage=15, deadline=None, ) my_body = [{"x": 0, "y": 0}] enemy_body = [{"x": 3, "y": 0}] value, depth = search.search_candidate( my_body=my_body, enemy_body=enemy_body, my_target=(1, 0), my_health=100, enemy_health=100, max_depth=1, previous_hazards=set(), ) self.assertEqual(value, 0.0) self.assertEqual(depth, 1) def test_duel_search_keeps_tail_blocked_when_its_snake_eats(self): board = BitBoard(3, 3) search = BitboardDuelSearch( board=board, food={(0, 1)}, hazards=set(), hazard_count={}, hazard_damage=15, deadline=None, ) body = (board.idx(0, 0), board.idx(1, 0), board.idx(1, 1)) advanced = search._advance_body(body, board.idx(0, 1), ate=True) self.assertIn(board.idx(1, 1), advanced) def test_bitboard_duel_search_reuses_transpositions(self): board = BitBoard(5, 5) search = BitboardDuelSearch( board=board, food=set(), hazards=set(), hazard_count={}, hazard_damage=15, deadline=perf_counter() + 1.0, ) my_body = [{"x": 1, "y": 1}, {"x": 1, "y": 0}, {"x": 0, "y": 0}] enemy_body = [{"x": 3, "y": 3}, {"x": 3, "y": 4}, {"x": 4, "y": 4}] search.search_depth(my_body, enemy_body, 100, 100, 3, set()) hits_before = search.cache_hits search.search_depth(my_body, enemy_body, 100, 100, 3, set()) self.assertGreater(search.cache_hits, hits_before) def test_bitboard_duel_search_respects_deadline(self): board = BitBoard(11, 11) search = BitboardDuelSearch( board=board, food=set(), hazards=set(), hazard_count={}, hazard_damage=15, deadline=perf_counter() - 0.001, ) my_body = [{"x": 2, "y": 2}, {"x": 2, "y": 1}, {"x": 2, "y": 0}] enemy_body = [{"x": 8, "y": 8}, {"x": 8, "y": 9}, {"x": 8, "y": 10}] started = perf_counter() _, depth = search.search(my_body, enemy_body, 100, 100, 6, set()) self.assertEqual(depth, 0) self.assertLess(perf_counter() - started, 0.05) if __name__ == "__main__": unittest.main()