diff --git a/snakes/MasterSnake.py b/snakes/MasterSnake.py index 7be2d6a..b359b85 100644 --- a/snakes/MasterSnake.py +++ b/snakes/MasterSnake.py @@ -4,6 +4,13 @@ class MasterSnake(TemplateSnake): def __init__(self): super().__init__() self.name = "MasterSnake" + self.disabled_find_near_by_food = True + + def is_food_nearby(self, head, food_positions): + for food in food_positions: + if abs(head['x'] - food['x']) <= 1 and abs(head['y'] - food['y']) <= 1: + return True + return False 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 @@ -37,26 +44,38 @@ class MasterSnake(TemplateSnake): # Finde die nächstgelegene Nahrungsquelle, wenn Nahrung vorhanden ist try: - path_to_food = self.find_path_to_food(game_data) - 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}) + if self.is_food_nearby(my_head, game_data['board']['food']) or self.disabled_find_near_by_food: + path_to_food = self.find_path_to_food(game_data) + if path_to_food: + # Implementiere Logik, um in Richtung der Nahrungsquelle zu bewegen, falls sicher + move = self.move_towards(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 keine 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 Nahrung vorhanden ist + # Wenn keine Nahrung in der Nähe ist, bewege dich in eine Richtung, die dich nahe an deinem eigenen Körper hält 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}) + # Finde den größten sicheren Bereich + max_area_start, max_area = self.flood_fill(my_head, safe_positions) + # Wenn der Schwanz der Schlange im größten sicheren Bereich liegt, bewege dich in Richtung des Schwanzes + my_tail = (my_snake['body'][-1]['x'], my_snake['body'][-1]['y']) # Convert to tuple + if my_tail in max_area: + move = self.move_towards(my_head, my_tail, safe_positions) + # Überprüfe zukünftige Bewegungen, um Sackgassen zu vermeiden - move = self.avoid_dead_ends(my_head, move, safe_positions, board_width, board_height, snakes) + move = self.avoid_dead_ends(my_head, move, safe_positions, snakes) self.add_to_history({"my_head": my_head, "move": move}) return move - def move_towards_food(self, head, food, safe_positions): + def move_towards(self, head, target, safe_positions): directions = {'up': (0, 1), 'down': (0, -1), 'left': (-1, 0), 'right': (1, 0)} best_direction = None min_distance = float('inf') @@ -66,7 +85,7 @@ class MasterSnake(TemplateSnake): 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 = abs(target[0] - next_position['x']) + abs(target[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 @@ -154,16 +173,21 @@ class MasterSnake(TemplateSnake): return direction return "up" # Standardbewegung, falls keine sichere Position gefunden wird - def avoid_dead_ends(self, head, move, safe_positions, board_width, board_height, snakes): + def avoid_self_collision(self, future_head, body_positions): + # Überprüft, ob die zukünftige Kopfposition im Körper der Schlange liegt + return (future_head['x'], future_head['y']) not in body_positions + + def avoid_dead_ends(self, head, move, safe_positions, 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} + body_positions = set((part['x'], part['y']) for part in snakes[0]['body']) - if not self.is_future_move_safe(future_head, safe_positions, board_width, board_height, snakes): + if not self.is_future_move_safe(future_head, safe_positions, snakes) or not self.avoid_self_collision(future_head, body_positions): 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): + if self.is_future_move_safe(alternative_future_head, safe_positions, snakes) and self.avoid_self_collision(alternative_future_head, body_positions): return alternative_move return move @@ -175,7 +199,7 @@ class MasterSnake(TemplateSnake): 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): + def is_future_move_safe(self, future_head, safe_positions, 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 @@ -185,5 +209,38 @@ class MasterSnake(TemplateSnake): # 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 + reachable_positions = self.flood_fill((future_head['x'], future_head['y']), safe_positions_set) # Entscheide, ob die Bewegung sicher ist, basierend auf der Anzahl der erreichbaren Positionen - return safe_positions_set # oder wähle einen anderen Schwellenwert + + fill_bool = len(reachable_positions) > len(safe_positions_set) * 0.25 + if fill_bool: + return fill_bool + + return len(safe_positions_set) >= len(snakes[0]['body']) + + def flood_fill(self, start, safe_positions): + stack = [start] + visited = set() + max_area = 0 + max_area_start = None + + while stack: + position = stack.pop() + if isinstance(position, dict): + position = tuple(position.values()) + else: + position = tuple(position) + + if position not in visited: + visited.add(position) + for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: # links, rechts, oben, unten + next_position = tuple([position[0] + dx, position[1] + dy]) + if next_position in safe_positions: + stack.append(next_position) + + # Überprüfe, ob der aktuelle Bereich größer ist als der bisher größte Bereich + if len(visited) > max_area: + max_area = len(visited) + max_area_start = position + + return max_area_start, visited