when both posisions are not save keep them in safe posisions - remove other useless MasterSnake

This commit is contained in:
2024-04-17 13:35:42 +02:00
parent 034b0e361a
commit d4b54d48b9
2 changed files with 5 additions and 256 deletions
-256
View File
@@ -1,256 +0,0 @@
from snakes.TemplateSnake import TemplateSnake
class MasterSnake(TemplateSnake):
def __init__(self):
super().__init__()
self.name = "MasterSnake"
self.history_head = []
def avoid_snake_body(self, snakes, board_width, board_height):
# Konvertiere die Körperpositionen der Schlangen in ein Set von Tupeln für schnellen Zugriff
body_positions = set()
for snake in snakes:
for part in snake['body']:
body_positions.add((part['x'], part['y']))
# Implementiere die Logik, um Positionen zu finden, die nicht von Schlangenkörpern belegt sind
safe_positions = self.find_safe_positions(body_positions, board_width, board_height)
return safe_positions
def find_safe_positions(self, body_positions, board_width, board_height):
# Finde sichere Positionen basierend auf den Körperpositionen und der Größe des Spielbretts
safe_positions = []
for x in range(board_width): # Nutze die tatsächliche Breite des Spielbretts
for y in range(board_height): # Nutze die tatsächliche Höhe des Spielbretts
if (x, y) not in body_positions:
safe_positions.append({'x': x, 'y': y})
return safe_positions
def choose_move(self, game_data):
board_width = game_data['board']['width']
board_height = game_data['board']['height']
snakes = game_data['board']['snakes']
my_snake = game_data['you']
my_head = my_snake['head']
# Vermeide Schlangenkörper
safe_positions = self.avoid_snake_body(snakes, board_width, board_height)
# Wähle Nahrung basierend auf verfügbarem Platz
try:
chosen_food = self.choose_food_based_on_space(game_data)
if chosen_food:
path_to_food = self.a_star_search(my_head, chosen_food, self.get_obstacles(game_data), board_width, board_height)
if path_to_food:
# Implementiere Logik, um in Richtung der Nahrungsquelle zu bewegen, falls sicher
move = self.move_towards_food(my_head, path_to_food[0], safe_positions)
self.add_to_history({"my_head": my_head, "path_to_food": path_to_food, "move": move})
else:
# Einfache Logik, um eine Bewegungsrichtung zu wählen, wenn kein Pfad zur Nahrung vorhanden ist
move = self.find_direction(my_head, safe_positions)
self.add_to_history({"my_head": my_head, "move": move})
else:
# Einfache Logik, um eine Bewegungsrichtung zu wählen, wenn keine geeignete Nahrung gefunden wird
move = self.find_direction(my_head, safe_positions)
self.add_to_history({"my_head": my_head, "move": move})
except ValueError:
move = self.find_direction(my_head, safe_positions)
self.add_to_history({"my_head": my_head, "move": move})
# Überprüfe zukünftige Bewegungen, um Sackgassen zu vermeiden
move = self.avoid_dead_ends_and_circles(my_head, move, safe_positions, board_width, board_height, snakes)
self.add_to_history({"my_head": my_head, "move": move})
self.add_to_history_head({"my_head": my_head, "move": move})
return move
def move_towards_food(self, head, food, safe_positions):
directions = {'up': (0, 1), 'down': (0, -1), 'left': (-1, 0), 'right': (1, 0)}
best_direction = None
min_distance = float('inf')
min_distance_to_body = float('inf')
body_positions = set((pos['x'], pos['y']) for pos in safe_positions[:-1]) # Exclude the head from body positions
for direction, (dx, dy) in directions.items():
next_position = {'x': head['x'] + dx, 'y': head['y'] + dy}
if next_position in safe_positions:
distance = abs(food[0] - next_position['x']) + abs(food[1] - next_position['y'])
distance_to_body = sum(abs(part[0] - next_position['x']) + abs(part[1] - next_position['y']) for part in body_positions)
if distance < min_distance or (distance == min_distance and distance_to_body < min_distance_to_body):
best_direction = direction
min_distance = distance
min_distance_to_body = distance_to_body
return best_direction if best_direction else "up" # Default to moving up if no safe direction found
def find_path_to_food(self, game_data):
my_head = game_data['you']['head']
food_positions = game_data['board']['food']
snakes = game_data['board']['snakes']
board_width = game_data['board']['width']
board_height = game_data['board']['height']
# Exclude own snake's body from obstacles
own_snake_body = game_data['you']['body']
obstacles = set((part['x'], part['y']) for part in own_snake_body)
for snake in snakes:
if snake['id'] != game_data['you']['id']:
for part in snake['body']:
obstacles.add((part['x'], part['y']))
# Choose the closest food source based on the heuristic
closest_food = min(food_positions, key=lambda food: abs(food['x'] - my_head['x']) + abs(food['y'] - my_head['y']))
# Use A* to search for a safe path
path = self.a_star_search(my_head, closest_food, obstacles, board_width, board_height)
return path
def choose_food_based_on_space(self, game_data):
my_head = game_data['you']['head']
food_positions = game_data['board']['food']
snakes = game_data['board']['snakes']
board_width = game_data['board']['width']
board_height = game_data['board']['height']
my_length = game_data['you']['length']
# Sortiere die Nahrungsquellen basierend auf ihrer Entfernung
sorted_food = sorted(food_positions, key=lambda food: abs(food['x'] - my_head['x']) + abs(food['y'] - my_head['y']))
for food in sorted_food:
path = self.a_star_search(my_head, food, self.get_obstacles(game_data), board_width, board_height)
if path and self.will_fit_in_space(path, my_length, board_width, board_height):
return food # Diese Nahrung ist erreichbar und es gibt genug Platz
# Wenn keine geeignete Nahrung gefunden wird, gib ein Standard-Nahrungsobjekt zurück oder löse eine Ausnahme aus
if food_positions:
return food_positions[0] # Gib das erste Nahrungsobjekt zurück
else:
raise ValueError("Keine Nahrung gefunden") # Oder löse eine Ausnahme aus
def will_fit_in_space(self, path, snake_length, board_width, board_height):
# Überprüfe, ob die Länge des Pfades größer oder gleich der Länge der Schlange ist
if len(path) >= snake_length:
return True
# Überprüfe, ob es genügend Platz um den Endpunkt des Pfades gibt
end_of_path = path[-1]
space_count = self.count_space_around(end_of_path, board_width, board_height)
return space_count >= snake_length
def count_space_around(self, position, board_width, board_height):
# Zähle die Anzahl der erreichbaren Positionen um einen Punkt herum
x, y = position
count = 0
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if (dx != 0 or dy != 0) and 0 <= x + dx < board_width and 0 <= y + dy < board_height:
count += 1
return count
def get_obstacles(self, game_data):
# Erstelle ein Set von Hindernissen für die A* Suche
obstacles = set()
for snake in game_data['board']['snakes']:
for part in snake['body']:
obstacles.add((part['x'], part['y']))
return obstacles
def a_star_search(self, start, goal, obstacles, board_width, board_height):
# Convert snake positions into a set of obstacles
# Helper functions
def is_position_safe(position):
x, y = position
return 0 <= x < board_width and 0 <= y < board_height and position not in obstacles
def get_neighbors(position):
x, y = position
return [(nx, ny) for nx, ny in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)] if is_position_safe((nx, ny))]
def heuristic(position, goal):
return abs(position[0] - goal[0]) + abs(position[1] - goal[1])
# Initialize start and goal positions
start = (start['x'], start['y'])
goal = (goal['x'], goal['y'])
# Initialize the open and closed list
open_set = set([start])
came_from = {}
g_score = {start: 0}
f_score = {start: heuristic(start, goal)}
while open_set:
current = min(open_set, key=lambda pos: f_score.get(pos, float('inf')))
if current == goal:
# Reconstruct the path
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.reverse()
return path # Return the path as a list of tuples
open_set.remove(current)
for neighbor in get_neighbors(current):
tentative_g_score = g_score[current] + 1 # Distance between neighbors is always 1
if tentative_g_score < g_score.get(neighbor, float('inf')):
came_from[neighbor] = current
g_score[neighbor] = tentative_g_score
f_score[neighbor] = g_score[neighbor] + heuristic(neighbor, goal)
if neighbor not in open_set:
open_set.add(neighbor)
return None # Kein Pfad gefunden
def find_direction(self, head, safe_positions):
# Beispielhafte Logik zur Auswahl einer Bewegungsrichtung
directions = {'up': (0, 1), 'down': (0, -1), 'left': (-1, 0), 'right': (1, 0)}
for direction, (dx, dy) in directions.items():
next_position = {'x': head['x'] + dx, 'y': head['y'] + dy}
if next_position in safe_positions:
return direction
return "up" # Standardbewegung, falls keine sichere Position gefunden wird
def is_in_history(self, future_head):
# Überprüfe, ob die zukünftige Kopfposition in den letzten N Bewegungen vorkommt
return any(future_head == move_data["my_head"] for move_data in self.history_head[-10:])
def avoid_dead_ends_and_circles(self, head, move, safe_positions, board_width, board_height, snakes):
directions = {'up': (0, 1), 'down': (0, -1), 'left': (-1, 0), 'right': (1, 0)}
dx, dy = directions[move]
future_head = {'x': head['x'] + dx, 'y': head['y'] + dy}
if not self.is_future_move_safe(future_head, safe_positions, board_width, board_height, snakes) or self.is_in_history(future_head):
for alternative_move in directions.keys():
dx, dy = directions[alternative_move]
alternative_future_head = {'x': head['x'] + dx, 'y': head['y'] + dy}
if self.is_future_move_safe(alternative_future_head, safe_positions, board_width, board_height, snakes) and not self.is_in_history(alternative_future_head):
return alternative_move
return move
def add_to_history_head(self, move_data):
# Füge die aktuelle Kopfposition zur Historie hinzu und behalte nur die letzten 10 Positionen
self.history_head.append(move_data)
self.history_head = self.history_head[-10:]
def simulate_snake_movement(self, snakes):
future_body_positions = set()
for snake in snakes:
# Beachte, dass dies nur ein Beispiel ist und angepasst werden muss, um deine spezifische Spiellogik zu berücksichtigen
for part in snake['body'][:-1]: # Ignoriere den letzten Teil des Körpers, da er sich bewegt
future_body_positions.add((part['x'], part['y']))
return future_body_positions
def is_future_move_safe(self, future_head, safe_positions, board_width, board_height, snakes):
# Simuliere die Bewegung der Schlange und aktualisiere die Positionen des eigenen Körpers
future_body_positions = self.simulate_snake_movement(snakes)
# Konvertiere safe_positions in ein Set von Tupeln für den Flood Fill Algorithmus
safe_positions_set = set((pos['x'], pos['y']) for pos in safe_positions)
# Entferne die zukünftigen Körperpositionen aus den sicheren Positionen
safe_positions_set = safe_positions_set - future_body_positions
# Füge die zukünftige Kopfposition hinzu, um sie als Startpunkt zu verwenden
safe_positions_set.add((future_head['x'], future_head['y']))
# Berechne die Anzahl der erreichbaren sicheren Positionen von der zukünftigen Kopfposition aus
# Entscheide, ob die Bewegung sicher ist, basierend auf der Anzahl der erreichbaren Positionen
return safe_positions_set # oder wähle einen anderen Schwellenwert
+5
View File
@@ -119,6 +119,7 @@ class TemplateSnake:
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:
@@ -128,12 +129,16 @@ class TemplateSnake:
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):