add new Snake
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
from snakes.DummSnake import DummSnake
|
from snakes.DummSnake import DummSnake
|
||||||
from snakes.LogicSnake import LogicSnake
|
from snakes.LogicSnake import LogicSnake
|
||||||
from snakes.AStarSnake import AStarSnake
|
from snakes.AStarSnake import AStarSnake
|
||||||
|
from snakes.MasterSnake import MasterSnake
|
||||||
|
|
||||||
SNAKE = AStarSnake()
|
SNAKE = MasterSnake()
|
||||||
|
|||||||
+37
-26
@@ -36,13 +36,15 @@ class MasterSnake(TemplateSnake):
|
|||||||
safe_positions = self.avoid_snake_body(snakes, board_width, board_height)
|
safe_positions = self.avoid_snake_body(snakes, board_width, board_height)
|
||||||
|
|
||||||
# Finde die nächstgelegene Nahrungsquelle, wenn Nahrung vorhanden ist
|
# Finde die nächstgelegene Nahrungsquelle, wenn Nahrung vorhanden ist
|
||||||
path_to_food = self.find_path_to_food(game_data)
|
try:
|
||||||
if path_to_food:
|
path_to_food = self.find_path_to_food(game_data)
|
||||||
# Implementiere Logik, um in Richtung der Nahrungsquelle zu bewegen, falls sicher
|
if path_to_food:
|
||||||
move = self.move_towards_food(my_head, path_to_food[0], safe_positions)
|
# Implementiere Logik, um in Richtung der Nahrungsquelle zu bewegen, falls sicher
|
||||||
print(move)
|
move = self.move_towards_food(my_head, path_to_food[0], safe_positions)
|
||||||
else:
|
else:
|
||||||
# Einfache Logik, um eine Bewegungsrichtung zu wählen, wenn keine Nahrung vorhanden ist
|
# Einfache Logik, um eine Bewegungsrichtung zu wählen, wenn keine Nahrung vorhanden ist
|
||||||
|
move = self.find_direction(my_head, safe_positions)
|
||||||
|
except ValueError:
|
||||||
move = self.find_direction(my_head, safe_positions)
|
move = self.find_direction(my_head, safe_positions)
|
||||||
|
|
||||||
# Überprüfe zukünftige Bewegungen, um Sackgassen zu vermeiden
|
# Überprüfe zukünftige Bewegungen, um Sackgassen zu vermeiden
|
||||||
@@ -51,18 +53,23 @@ class MasterSnake(TemplateSnake):
|
|||||||
return move
|
return move
|
||||||
|
|
||||||
def move_towards_food(self, head, food, safe_positions):
|
def move_towards_food(self, head, food, safe_positions):
|
||||||
# Beispielhafte Logik, um in Richtung der Nahrungsquelle zu bewegen
|
|
||||||
directions = {'up': (0, 1), 'down': (0, -1), 'left': (-1, 0), 'right': (1, 0)}
|
directions = {'up': (0, 1), 'down': (0, -1), 'left': (-1, 0), 'right': (1, 0)}
|
||||||
best_direction = None
|
best_direction = None
|
||||||
min_distance = float('inf')
|
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():
|
for direction, (dx, dy) in directions.items():
|
||||||
next_position = {'x': head['x'] + dx, 'y': head['y'] + dy}
|
next_position = {'x': head['x'] + dx, 'y': head['y'] + dy}
|
||||||
if next_position in safe_positions:
|
if next_position in safe_positions:
|
||||||
distance = abs(food[0] - next_position['x']) + abs(food[1] - next_position['y'])
|
distance = abs(food[0] - next_position['x']) + abs(food[1] - next_position['y'])
|
||||||
if distance < min_distance:
|
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
|
best_direction = direction
|
||||||
min_distance = distance
|
min_distance = distance
|
||||||
return best_direction if best_direction else "up" # Standardbewegung, falls keine sichere Richtung gefunden wird
|
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):
|
def find_path_to_food(self, game_data):
|
||||||
my_head = game_data['you']['head']
|
my_head = game_data['you']['head']
|
||||||
@@ -71,21 +78,25 @@ class MasterSnake(TemplateSnake):
|
|||||||
board_width = game_data['board']['width']
|
board_width = game_data['board']['width']
|
||||||
board_height = game_data['board']['height']
|
board_height = game_data['board']['height']
|
||||||
|
|
||||||
# Wähle die nächste Nahrungsquelle basierend auf der Heuristik
|
# 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']))
|
closest_food = min(food_positions, key=lambda food: abs(food['x'] - my_head['x']) + abs(food['y'] - my_head['y']))
|
||||||
|
|
||||||
# Verwende A* zur Suche nach einem sicheren Pfad
|
# Use A* to search for a safe path
|
||||||
path = self.a_star_search(my_head, closest_food, snakes, board_width, board_height)
|
path = self.a_star_search(my_head, closest_food, obstacles, board_width, board_height)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def a_star_search(self, start, goal, snakes, board_width, board_height):
|
def a_star_search(self, start, goal, obstacles, board_width, board_height):
|
||||||
# Konvertiere Schlangenpositionen in ein Set von Hindernissen
|
# Convert snake positions into a set of obstacles
|
||||||
obstacles = set()
|
# Helper functions
|
||||||
for snake in snakes:
|
|
||||||
for part in snake['body']:
|
|
||||||
obstacles.add((part['x'], part['y']))
|
|
||||||
|
|
||||||
# Hilfsfunktionen
|
|
||||||
def is_position_safe(position):
|
def is_position_safe(position):
|
||||||
x, y = position
|
x, y = position
|
||||||
return 0 <= x < board_width and 0 <= y < board_height and position not in obstacles
|
return 0 <= x < board_width and 0 <= y < board_height and position not in obstacles
|
||||||
@@ -97,11 +108,11 @@ class MasterSnake(TemplateSnake):
|
|||||||
def heuristic(position, goal):
|
def heuristic(position, goal):
|
||||||
return abs(position[0] - goal[0]) + abs(position[1] - goal[1])
|
return abs(position[0] - goal[0]) + abs(position[1] - goal[1])
|
||||||
|
|
||||||
# Initialisiere Start- und Zielpositionen
|
# Initialize start and goal positions
|
||||||
start = (start['x'], start['y'])
|
start = (start['x'], start['y'])
|
||||||
goal = (goal['x'], goal['y'])
|
goal = (goal['x'], goal['y'])
|
||||||
|
|
||||||
# Initialisiere die offene und geschlossene Liste
|
# Initialize the open and closed list
|
||||||
open_set = set([start])
|
open_set = set([start])
|
||||||
came_from = {}
|
came_from = {}
|
||||||
g_score = {start: 0}
|
g_score = {start: 0}
|
||||||
@@ -110,17 +121,17 @@ class MasterSnake(TemplateSnake):
|
|||||||
while open_set:
|
while open_set:
|
||||||
current = min(open_set, key=lambda pos: f_score.get(pos, float('inf')))
|
current = min(open_set, key=lambda pos: f_score.get(pos, float('inf')))
|
||||||
if current == goal:
|
if current == goal:
|
||||||
# Rekonstruiere den Pfad
|
# Reconstruct the path
|
||||||
path = []
|
path = []
|
||||||
while current in came_from:
|
while current in came_from:
|
||||||
path.append(current)
|
path.append(current)
|
||||||
current = came_from[current]
|
current = came_from[current]
|
||||||
path.reverse()
|
path.reverse()
|
||||||
return path # Rückgabe des Pfades als Liste von Tupeln
|
return path # Return the path as a list of tuples
|
||||||
|
|
||||||
open_set.remove(current)
|
open_set.remove(current)
|
||||||
for neighbor in get_neighbors(current):
|
for neighbor in get_neighbors(current):
|
||||||
tentative_g_score = g_score[current] + 1 # Distanz zwischen Nachbarn ist immer 1
|
tentative_g_score = g_score[current] + 1 # Distance between neighbors is always 1
|
||||||
if tentative_g_score < g_score.get(neighbor, float('inf')):
|
if tentative_g_score < g_score.get(neighbor, float('inf')):
|
||||||
came_from[neighbor] = current
|
came_from[neighbor] = current
|
||||||
g_score[neighbor] = tentative_g_score
|
g_score[neighbor] = tentative_g_score
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import unittest
|
||||||
|
from snakes.MasterSnake import MasterSnake
|
||||||
|
|
||||||
|
class TestMasterSnake(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.snake = MasterSnake()
|
||||||
|
self.game_data = {
|
||||||
|
"board": {
|
||||||
|
"height": 11,
|
||||||
|
"width": 11,
|
||||||
|
"snakes": [
|
||||||
|
{
|
||||||
|
"id": "snake-1",
|
||||||
|
"body": [
|
||||||
|
{"x": 0, "y": 0},
|
||||||
|
{"x": 1, "y": 0},
|
||||||
|
{"x": 2, "y": 0}
|
||||||
|
],
|
||||||
|
"head": {"x": 2, "y": 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "snake-2",
|
||||||
|
"body": [
|
||||||
|
{"x": 5, "y": 4},
|
||||||
|
{"x": 5, "y": 3},
|
||||||
|
{"x": 6, "y": 3},
|
||||||
|
{"x": 6, "y": 2}
|
||||||
|
],
|
||||||
|
"head": {"x": 6, "y": 3},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"food": [
|
||||||
|
{
|
||||||
|
"x": 2,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 10,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 5,
|
||||||
|
"y": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"you": {
|
||||||
|
"id": "snake-1",
|
||||||
|
"body": [
|
||||||
|
{"x": 0, "y": 0},
|
||||||
|
{"x": 1, "y": 0},
|
||||||
|
{"x": 2, "y": 0}
|
||||||
|
],
|
||||||
|
"head": {"x": 0, "y": 0},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_avoid_snake_body(self):
|
||||||
|
snakes = self.game_data['board']['snakes']
|
||||||
|
board_width = self.game_data['board']['width']
|
||||||
|
board_height = self.game_data['board']['height']
|
||||||
|
safe_positions = self.snake.avoid_snake_body(snakes, board_width, board_height)
|
||||||
|
self.assertIsInstance(safe_positions, list)
|
||||||
|
self.assertTrue(all(isinstance(pos, dict) for pos in safe_positions))
|
||||||
|
self.assertTrue(all('x' in pos and 'y' in pos for pos in safe_positions))
|
||||||
|
|
||||||
|
def test_find_safe_positions(self):
|
||||||
|
body_positions = {(0, 0), (1, 0), (2, 0), (5, 4), (5, 3), (6, 3), (6, 2)}
|
||||||
|
safe_positions = self.snake.find_safe_positions(body_positions, 11, 11)
|
||||||
|
self.assertNotIn({'x': 0, 'y': 0}, safe_positions)
|
||||||
|
self.assertIn({'x': 10, 'y': 10}, safe_positions)
|
||||||
|
|
||||||
|
def test_choose_move(self):
|
||||||
|
move = self.snake.choose_move(self.game_data)
|
||||||
|
self.assertIn(move, ["up", "down", "left", "right"])
|
||||||
|
|
||||||
|
def test_move_towards_food(self):
|
||||||
|
head = {'x': 0, 'y': 0}
|
||||||
|
food = (5, 5)
|
||||||
|
safe_positions = [{'x': 1, 'y': 0}, {'x': 0, 'y': 1}, {'x': 1, 'y': 1}]
|
||||||
|
direction = self.snake.move_towards_food(head, food, safe_positions)
|
||||||
|
self.assertIn(direction, ["up", "down", "left", "right"])
|
||||||
|
|
||||||
|
def test_find_path_to_food(self):
|
||||||
|
path = self.snake.find_path_to_food(self.game_data)
|
||||||
|
print(path)
|
||||||
|
self.assertIsInstance(path, list)
|
||||||
|
self.assertTrue(all(isinstance(pos, dict) for pos in path))
|
||||||
|
self.assertTrue(all('x' in pos and 'y' in pos for pos in path))
|
||||||
|
|
||||||
|
def test_find_direction(self):
|
||||||
|
head = {'x': 0, 'y': 0}
|
||||||
|
safe_positions = [{'x': 1, 'y': 0}, {'x': 0, 'y': 1}, {'x': 1, 'y': 1}]
|
||||||
|
direction = self.snake.find_direction(head, safe_positions)
|
||||||
|
self.assertIn(direction, ["up", "down", "left", "right"])
|
||||||
|
|
||||||
|
def test_avoid_dead_ends(self):
|
||||||
|
head = {'x': 0, 'y': 0}
|
||||||
|
move = "right"
|
||||||
|
board_width = 11
|
||||||
|
board_height = 11
|
||||||
|
snakes = self.game_data['board']['snakes']
|
||||||
|
safe_positions = [{'x': 1, 'y': 0}, {'x': 0, 'y': 1}, {'x': 1, 'y': 1}]
|
||||||
|
new_move = self.snake.avoid_dead_ends(head, move, safe_positions, board_width, board_height, snakes)
|
||||||
|
self.assertIn(new_move, ["up", "down", "left", "right"])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user