Files
snake-python/snakes/TemplateSnake.py
T

152 lines
5.0 KiB
Python

import random
class TemplateSnake:
def __init__(self):
self.history = []
def clear_history(self):
self.history = []
def add_to_history(self, data:dict):
self.history.append(data)
def get_history(self):
return self.history
def add_calculations(self, calculations:dict):
self.calculations.append(calculations)
def choose_move(self, game_data:dict):
self.calculations = []
self.eat_the_snake_overwrite = False
self.board_width = game_data['board']['width']
self.board_height = game_data['board']['height']
self.my_snake = game_data['you']
self.other_snakes = [ x for x in game_data['board']['snakes'] if x["id"] != self.my_snake["id"] ]
self.my_head = self.my_snake['head']
self.my_body = self.my_snake["body"]
self.game_type = game_data['game']["ruleset"]["name"]
self.find_safe_positions()
moves = list(self.safe_positions.keys())
if len(moves) > 0:
move = random.choice(moves)
else:
print("No safe positions left - Going to Die")
move = None
self.add_to_history({"turn": game_data["turn"], "data": self.calculations})
return move if move else "up"
def get_possible_moves(self, snake_head):
return {
"up": {
"x": snake_head["x"],
"y": snake_head["y"] + 1
},
"down": {
"x": snake_head["x"],
"y": snake_head["y"] - 1
},
"left": {
"x": snake_head["x"] - 1,
"y": snake_head["y"]
},
"right": {
"x": snake_head["x"] + 1,
"y": snake_head["y"]
}
}
def get_snake_body_without_snake_tail(self, snake:list[dict]):
if len(set((pos["x"], pos["y"]) for pos in snake)) < 3:
return snake
snake.pop()
return snake
def avoid_my_body(self) -> list:
"""
my_body: List of dictionaries of x/y coordinates for every segment of a Battlesnake.
e.g. [ {"x": 0, "y": 0}, {"x": 1, "y": 0}, {"x": 2, "y": 0} ]
possible_moves: List of strings. Moves to pick from.
e.g. ["up", "down", "left", "right"]
return: The list of remaining possible_moves, with the 'neck' direction removed
"""
remove = []
for direction, location in self.safe_positions.items():
if location in self.my_body:
remove.append(direction)
for direction in remove:
del self.safe_positions[direction]
self.add_calculations({"function": "avoid_my_body", "my_body": self.my_body, "safe_positions": self.safe_positions})
def avoid_walls(self):
remove = []
for direction, location in list(self.safe_positions.items()):
x_out_range = (location["x"] < 0 or location["x"] == self.board_width)
y_out_range = (location["y"] < 0 or location["y"] == self.board_height)
if x_out_range or y_out_range:
remove.append(direction)
for direction in remove:
del self.safe_positions[direction]
self.add_calculations({"function": "avoid_walls", "board_width": self.board_width, "board_height": self.board_height, "safe_positions": self.safe_positions})
def avoid_snakes(self):
remove = []
for snake in self.other_snakes:
for direction, location in self.safe_positions.items():
#if self.game_type == "constrictor":
if location in snake["body"]:
remove.append(direction)
#else:
# if location in self.get_snake_body_without_snake_tail(snake["body"]):
# remove.append(direction)
remove = set(remove)
for direction in remove:
del self.safe_positions[direction]
self.add_calculations({"function": "avoid_snakes", "other_snakes": self.other_snakes, "safe_positions": self.safe_positions})
def avoid_get_eaten_by_other_snakes(self):
remove = []
no_way_out = {}
for snake in self.other_snakes:
for direction, location in self.safe_positions.items():
if len(self.safe_positions) > 1:
#TODO: Avoid Draw when heads are by the food
if snake["length"] < self.my_snake["length"] and location in [{"x": v["x"], "y": v["y"]} for k, v in self.get_possible_moves(snake["head"]).items()]:
self.eat_the_snake_overwrite = True
self.kill_the_snake = direction
#TODO: Check if snake on the way to the food here and only remove this pos
elif location in [{"x": v["x"], "y": v["y"]} for k, v in self.get_possible_moves(snake["head"]).items()]:
no_way_out[direction] = location
remove.append(direction)
remove = set(remove)
for direction in remove:
del self.safe_positions[direction]
if len(self.safe_positions) == 0:
self.safe_positions = no_way_out
self.add_calculations({"function": "avoid_get_eaten_by_other_snakes", "other_snakes": self.other_snakes, "safe_positions": self.safe_positions})
def find_safe_positions(self):
self.safe_positions = self.get_possible_moves(self.my_head)
self.add_calculations({"function": "get_possible_moves", "safe_positions": self.safe_positions})
self.avoid_my_body()
self.avoid_walls()
self.avoid_snakes()
self.avoid_get_eaten_by_other_snakes()