use new game board functions
This commit is contained in:
+27
-39
@@ -1,4 +1,5 @@
|
|||||||
from snakes.TemplateSnake import TemplateSnake
|
from snakes.TemplateSnake import TemplateSnake
|
||||||
|
from server.GameBoard import GameBoard
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
class BetterMasterSnake(TemplateSnake):
|
class BetterMasterSnake(TemplateSnake):
|
||||||
@@ -8,47 +9,34 @@ class BetterMasterSnake(TemplateSnake):
|
|||||||
# Definiere die möglichen Bewegungsrichtungen
|
# Definiere die möglichen Bewegungsrichtungen
|
||||||
self.min_safe_area = 2
|
self.min_safe_area = 2
|
||||||
|
|
||||||
def choose_move(self, game_data):
|
def choose_move(self, game_data:GameBoard):
|
||||||
move = None
|
self.game_board = game_data
|
||||||
self.calculations = []
|
self.calculations = []
|
||||||
self.eat_the_snake_overwrite = False
|
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.food_positions = game_data['board']['food']
|
|
||||||
self.game_type = game_data['game']["ruleset"]["name"]
|
|
||||||
|
|
||||||
self.board = game_data['board']
|
|
||||||
|
|
||||||
self.safe_positions = self.find_safe_positions(add_to_calculations=True)
|
self.safe_positions = self.find_safe_positions(add_to_calculations=True)
|
||||||
if self.eat_the_snake_overwrite:
|
if self.eat_the_snake_overwrite:
|
||||||
return self.overwrite_eat_the_other_snake(game_data["turn"])
|
return self.overwrite_eat_the_other_snake(game_data.get_turn())
|
||||||
|
|
||||||
if self.game_type == "constrictor":
|
if game_data.get_type() == "constrictor":
|
||||||
move = self.selected_move_constrictor()
|
move = self.selected_move_constrictor()
|
||||||
else:
|
else:
|
||||||
move = self.selected_move_standard()
|
move = self.selected_move_standard()
|
||||||
|
|
||||||
self.add_to_history({"turn": game_data["turn"], "data": self.calculations})
|
self.add_to_history({"turn": game_data.get_turn(), "data": self.calculations})
|
||||||
return move if move else "up"
|
return move if move else "up"
|
||||||
|
|
||||||
def overwrite_eat_the_other_snake(self, turn:int):
|
def overwrite_eat_the_other_snake(self, turn:int):
|
||||||
self.add_calculations({"function": "eat_the_snake_overwrite", "my_head": self.my_head, "move": self.kill_the_snake, "safe_positions": self.safe_positions})
|
self.add_calculations({"function": "eat_the_snake_overwrite", "my_head": self.game_board.get_my_snake_head(), "move": self.kill_the_snake, "safe_positions": self.safe_positions})
|
||||||
self.add_to_history({"turn": turn, "data": self.calculations})
|
self.add_to_history({"turn": turn, "data": self.calculations})
|
||||||
return self.kill_the_snake
|
return self.kill_the_snake
|
||||||
|
|
||||||
#TODO: How to Fill the Gameboard best?
|
#TODO: How to Fill the Gameboard best?
|
||||||
def selected_move_constrictor(self):
|
def selected_move_constrictor(self):
|
||||||
move = self.move_close_to_body()
|
move = self.move_close_to_body()
|
||||||
self.add_calculations({"function": "move_close_to_body", "my_head": self.my_head, "move": move})
|
self.add_calculations({"function": "move_close_to_body", "my_head": self.game_board.get_my_snake_head(), "move": move})
|
||||||
move = self.ensure_escape_route(move)
|
move = self.ensure_escape_route(move)
|
||||||
self.add_calculations({"function": "ensure_escape_route", "my_head": self.my_head, "move": move, "safe_positions": self.safe_positions})
|
self.add_calculations({"function": "ensure_escape_route", "my_head": self.game_board.get_my_snake_head(), "move": move, "safe_positions": self.safe_positions})
|
||||||
return move
|
return move
|
||||||
|
|
||||||
def selected_move_standard(self, move=None):
|
def selected_move_standard(self, move=None):
|
||||||
@@ -56,50 +44,50 @@ class BetterMasterSnake(TemplateSnake):
|
|||||||
path_to_food = self.find_path_to_food()
|
path_to_food = self.find_path_to_food()
|
||||||
if path_to_food:
|
if path_to_food:
|
||||||
move = self.move_towards(path_to_food[0])
|
move = self.move_towards(path_to_food[0])
|
||||||
self.add_calculations({"function": "move_towards", "my_head": self.my_head, "path_to_food": path_to_food, "move": move})
|
self.add_calculations({"function": "move_towards", "my_head": self.game_board.get_my_snake_head(), "path_to_food": path_to_food, "move": move})
|
||||||
|
|
||||||
if not move or self.would_eating_the_food_kill_the_snake(move):
|
if not move or self.would_eating_the_food_kill_the_snake(move):
|
||||||
move = self.move_close_to_body(move_close_to_tail=True)
|
move = self.move_close_to_body(move_close_to_tail=True)
|
||||||
self.add_calculations({"function": "move_close_to_body", "my_head": self.my_head, "move": move})
|
self.add_calculations({"function": "move_close_to_body", "my_head": self.game_board.get_my_snake_head(), "move": move})
|
||||||
|
|
||||||
# Überprfe, ob der Zug einen Ausweg lässt
|
# Überprfe, ob der Zug einen Ausweg lässt
|
||||||
move = self.ensure_escape_route(move)
|
move = self.ensure_escape_route(move)
|
||||||
self.add_calculations({"function": "ensure_escape_route", "my_head": self.my_head, "move": move, "safe_positions": self.safe_positions})
|
self.add_calculations({"function": "ensure_escape_route", "my_head": self.game_board.get_my_snake_head(), "move": move, "safe_positions": self.safe_positions})
|
||||||
return move
|
return move
|
||||||
|
|
||||||
def find_path_to_food(self):
|
def find_path_to_food(self):
|
||||||
# Exclude own snake's body from obstacles
|
# Exclude own snake's body from obstacles
|
||||||
obstacles = set((part['x'], part['y']) for part in self.my_body)
|
obstacles = set((part['x'], part['y']) for part in self.game_board.get_my_snake_body())
|
||||||
|
|
||||||
for snake in self.other_snakes:
|
for snake in self.game_board.get_other_snakes():
|
||||||
for part in snake['body']:
|
for part in snake['body']:
|
||||||
obstacles.add((part['x'], part['y']))
|
obstacles.add((part['x'], part['y']))
|
||||||
|
|
||||||
other_snakes_other_snake_posible_moves_set = {(d['x'], d['y']) for d in self.other_snake_posible_moves}
|
other_snakes_other_snake_posible_moves_set = {(d['x'], d['y']) for d in self.other_snake_posible_moves}
|
||||||
removed_elements_set = set([(elem['x'], elem['y']) for elem in self.food_positions if (elem['x'], elem['y']) in other_snakes_other_snake_posible_moves_set])
|
removed_elements_set = set([(elem['x'], elem['y']) for elem in self.game_board.get_food() if (elem['x'], elem['y']) in other_snakes_other_snake_posible_moves_set])
|
||||||
obstacles |= removed_elements_set
|
obstacles |= removed_elements_set
|
||||||
|
|
||||||
self.food_positions = [elem for elem in self.food_positions if (elem['x'], elem['y']) not in other_snakes_other_snake_posible_moves_set]
|
self.food_positions = [elem for elem in self.game_board.get_food() if (elem['x'], elem['y']) not in other_snakes_other_snake_posible_moves_set]
|
||||||
|
|
||||||
if len(self.food_positions) > 0:
|
if len(self.food_positions) > 0:
|
||||||
# Choose the closest food source based on the heuristic
|
# Choose the closest food source based on the heuristic
|
||||||
closest_food = min(self.food_positions, key=lambda food: abs(food['x'] - self.my_head['x']) + abs(food['y'] - self.my_head['y']))
|
closest_food = min(self.food_positions, key=lambda food: abs(food['x'] - self.game_board.get_my_snake_head()['x']) + abs(food['y'] - self.game_board.get_my_snake_head()['y']))
|
||||||
|
|
||||||
# Use A* to search for a safe path
|
# Use A* to search for a safe path
|
||||||
return self.a_star_search(self.my_head, closest_food, obstacles)
|
return self.a_star_search(self.game_board.get_my_snake_head(), closest_food, obstacles)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def find_path_to_tail(self):
|
def find_path_to_tail(self):
|
||||||
# Exclude other snake's body from obstacles
|
# Exclude other snake's body from obstacles
|
||||||
obstacles = set((part['x'], part['y']) for part in self.my_body)
|
obstacles = set((part['x'], part['y']) for part in self.game_board.get_my_snake_body())
|
||||||
for snake in self.other_snakes:
|
for snake in self.game_board.get_other_snakes():
|
||||||
for part in snake['body']:
|
for part in snake['body']:
|
||||||
obstacles.add((part['x'], part['y']))
|
obstacles.add((part['x'], part['y']))
|
||||||
|
|
||||||
my_snake_tail = {"x": self.my_body[-1]['x'], "y": self.my_body[-1]['y']}
|
my_snake_tail = {"x": self.game_board.get_my_snake_tail()['x'], "y": self.game_board.get_my_snake_tail()['y']}
|
||||||
|
|
||||||
# Use A* to search for a safe path
|
# Use A* to search for a safe path
|
||||||
path = self.a_star_search(self.my_head, my_snake_tail, obstacles)
|
path = self.a_star_search(self.game_board.get_my_snake_head(), my_snake_tail, obstacles)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def move_towards(self, target):
|
def move_towards(self, target):
|
||||||
@@ -115,8 +103,8 @@ class BetterMasterSnake(TemplateSnake):
|
|||||||
|
|
||||||
def move_close_to_body(self, move_close_to_tail=False):
|
def move_close_to_body(self, move_close_to_tail=False):
|
||||||
# Heuristik, um Positionen nahe dem eigenen Körper zu bevorzugen
|
# Heuristik, um Positionen nahe dem eigenen Körper zu bevorzugen
|
||||||
body_positions = set((part['x'], part['y']) for part in self.my_body)
|
body_positions = set((part['x'], part['y']) for part in self.game_board.get_my_snake_body())
|
||||||
tail_position = (self.my_body[-1]['x'], self.my_body[-1]['y'])
|
tail_position = (self.game_board.get_my_snake_tail()['x'], self.game_board.get_my_snake_tail()['y'])
|
||||||
|
|
||||||
best_move = None
|
best_move = None
|
||||||
max_distance = -1 # Initialize maximum distance
|
max_distance = -1 # Initialize maximum distance
|
||||||
@@ -147,14 +135,14 @@ class BetterMasterSnake(TemplateSnake):
|
|||||||
future_position = self.safe_positions[move]
|
future_position = self.safe_positions[move]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
for move, pos in self.safe_positions.items():
|
for move, pos in self.safe_positions.items():
|
||||||
if self.is_near_tail(pos, (self.my_body[-1]['x'], self.my_body[-1]['y'])):
|
if self.is_near_tail(pos, (self.game_board.get_my_snake_tail()['x'], self.game_board.get_my_snake_tail()['y'])):
|
||||||
self.add_calculations({"function": "ensure_escape_route", "move": move, "is_near_tail": True})
|
self.add_calculations({"function": "ensure_escape_route", "move": move, "is_near_tail": True})
|
||||||
move = self.move_towards(pos)
|
move = self.move_towards(pos)
|
||||||
return move
|
return move
|
||||||
else:
|
else:
|
||||||
path_to_tail = self.find_path_to_tail()
|
path_to_tail = self.find_path_to_tail()
|
||||||
if path_to_tail:
|
if path_to_tail:
|
||||||
self.add_calculations({"function": "move_towards", "my_head": self.my_head, "path_to_tail": path_to_tail, "move": move})
|
self.add_calculations({"function": "move_towards", "my_head": self.game_board.get_my_snake_head(), "path_to_tail": path_to_tail, "move": move})
|
||||||
move = self.move_towards(path_to_tail[0])
|
move = self.move_towards(path_to_tail[0])
|
||||||
|
|
||||||
self.add_calculations({"function": "ensure_escape_route", "move": move, "KeyError": "Snake Coild itself up"})
|
self.add_calculations({"function": "ensure_escape_route", "move": move, "KeyError": "Snake Coild itself up"})
|
||||||
@@ -169,7 +157,7 @@ class BetterMasterSnake(TemplateSnake):
|
|||||||
def a_star_search(self, start, goal, obstacles):
|
def a_star_search(self, start, goal, obstacles):
|
||||||
# Helper functions
|
# Helper functions
|
||||||
def is_position_safe(position):
|
def is_position_safe(position):
|
||||||
return 0 <= position['x'] < self.board_width and 0 <= position['y'] < self.board_height and (position['x'], position['y']) not in obstacles
|
return 0 <= position['x'] < self.game_board.get_width() and 0 <= position['y'] < self.game_board.get_height() and (position['x'], position['y']) not in obstacles
|
||||||
|
|
||||||
def get_neighbors(position):
|
def get_neighbors(position):
|
||||||
neighbors = []
|
neighbors = []
|
||||||
|
|||||||
+13
-23
@@ -1,3 +1,4 @@
|
|||||||
|
from server.GameBoard import GameBoard
|
||||||
import random
|
import random
|
||||||
|
|
||||||
class TemplateSnake:
|
class TemplateSnake:
|
||||||
@@ -16,22 +17,11 @@ class TemplateSnake:
|
|||||||
def add_calculations(self, calculations:dict):
|
def add_calculations(self, calculations:dict):
|
||||||
self.calculations.append(calculations)
|
self.calculations.append(calculations)
|
||||||
|
|
||||||
def choose_move(self, game_data:dict):
|
def choose_move(self, game_data:GameBoard):
|
||||||
|
self.game_board = game_data
|
||||||
self.calculations = []
|
self.calculations = []
|
||||||
self.eat_the_snake_overwrite = False
|
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.food_positions = game_data['board']['food']
|
|
||||||
self.game_type = game_data['game']["ruleset"]["name"]
|
|
||||||
|
|
||||||
self.safe_positions = self.find_safe_positions(add_to_calculations=True)
|
self.safe_positions = self.find_safe_positions(add_to_calculations=True)
|
||||||
moves = list(self.safe_positions.keys())
|
moves = list(self.safe_positions.keys())
|
||||||
if len(moves) > 0:
|
if len(moves) > 0:
|
||||||
@@ -40,7 +30,7 @@ class TemplateSnake:
|
|||||||
print("No safe positions left - Going to Die")
|
print("No safe positions left - Going to Die")
|
||||||
move = None
|
move = None
|
||||||
|
|
||||||
self.add_to_history({"turn": game_data["turn"], "data": self.calculations})
|
self.add_to_history({"turn": game_data.get_turn(), "data": self.calculations})
|
||||||
return move if move else "up"
|
return move if move else "up"
|
||||||
|
|
||||||
def get_possible_moves(self, snake_head):
|
def get_possible_moves(self, snake_head):
|
||||||
@@ -95,8 +85,8 @@ class TemplateSnake:
|
|||||||
def avoid_walls(self, safe_positions:dict[str, dict], add_to_calculations:bool=False):
|
def avoid_walls(self, safe_positions:dict[str, dict], add_to_calculations:bool=False):
|
||||||
remove = []
|
remove = []
|
||||||
for direction, location in list(safe_positions.items()):
|
for direction, location in list(safe_positions.items()):
|
||||||
x_out_range = (location["x"] < 0 or location["x"] == self.board_width)
|
x_out_range = (location["x"] < 0 or location["x"] == self.game_board.get_width())
|
||||||
y_out_range = (location["y"] < 0 or location["y"] == self.board_height)
|
y_out_range = (location["y"] < 0 or location["y"] == self.game_board.get_height())
|
||||||
if x_out_range or y_out_range:
|
if x_out_range or y_out_range:
|
||||||
remove.append(direction)
|
remove.append(direction)
|
||||||
|
|
||||||
@@ -104,7 +94,7 @@ class TemplateSnake:
|
|||||||
del safe_positions[direction]
|
del safe_positions[direction]
|
||||||
|
|
||||||
if add_to_calculations:
|
if add_to_calculations:
|
||||||
self.add_calculations({"function": "avoid_walls", "board_width": self.board_width, "board_height": self.board_height, "safe_positions": safe_positions})
|
self.add_calculations({"function": "avoid_walls", "board_width": self.game_board.get_width(), "board_height": self.game_board.get_height(), "safe_positions": safe_positions})
|
||||||
|
|
||||||
return safe_positions
|
return safe_positions
|
||||||
|
|
||||||
@@ -160,22 +150,22 @@ class TemplateSnake:
|
|||||||
return safe_positions
|
return safe_positions
|
||||||
|
|
||||||
def find_safe_positions(self, add_to_calculations:bool=False):
|
def find_safe_positions(self, add_to_calculations:bool=False):
|
||||||
safe_positions = self.get_possible_moves(self.my_head)
|
safe_positions = self.get_possible_moves(self.game_board.get_my_snake_head())
|
||||||
if add_to_calculations:
|
if add_to_calculations:
|
||||||
self.add_calculations({"function": "get_possible_moves", "safe_positions": safe_positions})
|
self.add_calculations({"function": "get_possible_moves", "safe_positions": safe_positions})
|
||||||
|
|
||||||
safe_positions = self.avoid_my_body(self.my_body, safe_positions, add_to_calculations)
|
safe_positions = self.avoid_my_body(self.game_board.get_my_snake_body(), safe_positions, add_to_calculations)
|
||||||
safe_positions = self.avoid_walls(safe_positions, add_to_calculations)
|
safe_positions = self.avoid_walls(safe_positions, add_to_calculations)
|
||||||
safe_positions = self.avoid_snakes(self.other_snakes, safe_positions, add_to_calculations)
|
safe_positions = self.avoid_snakes(self.game_board.get_other_snakes(), safe_positions, add_to_calculations)
|
||||||
safe_positions = self.avoid_get_eaten_by_other_snakes(self.other_snakes, safe_positions, add_to_calculations)
|
safe_positions = self.avoid_get_eaten_by_other_snakes(self.game_board.get_other_snakes(), safe_positions, add_to_calculations)
|
||||||
return safe_positions
|
return safe_positions
|
||||||
|
|
||||||
def calculate_new_body_position(self, move:str=None, with_tail:bool=False):
|
def calculate_new_body_position(self, move:str=None, with_tail:bool=False):
|
||||||
if move:
|
if move:
|
||||||
head = self.get_possible_moves(self.my_head)[move]
|
head = self.get_possible_moves(self.game_board.get_my_snake_head())[move]
|
||||||
|
|
||||||
body = [head]
|
body = [head]
|
||||||
body.extend(self.my_body)
|
body.extend(self.game_board.get_my_snake_body())
|
||||||
body.pop()
|
body.pop()
|
||||||
|
|
||||||
if not with_tail:
|
if not with_tail:
|
||||||
|
|||||||
Reference in New Issue
Block a user