Implementacja przeszukiwania stanów przez BFS

This commit is contained in:
karolajoj 2024-04-12 18:17:30 +02:00
parent ffa6f97771
commit 75e597b3c6
17 changed files with 196 additions and 31 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,34 +1,62 @@
import pygame
from state_space_search import is_border, is_obstacle
class Agent:
def __init__(self, x, y, image_path, grid_size):
self.x = x
self.y = y
def __init__(self, istate, image_path, grid_size):
self.istate = istate
self.x, self.y, self.direction = istate
self.grid_size = grid_size
self.image = pygame.image.load(image_path)
self.image = pygame.transform.scale(self.image, (grid_size, grid_size))
self.image_original = pygame.image.load(image_path)
self.image_original = pygame.transform.scale(self.image_original, (grid_size, grid_size))
self.image = self.image_original
def draw(self, screen):
# Obróć obrazek zgodnie z kierunkiem
if self.direction == 'E':
self.image = pygame.transform.rotate(self.image_original, -90)
elif self.direction == 'S':
self.image = pygame.transform.rotate(self.image_original, 180)
elif self.direction == 'W':
self.image = pygame.transform.rotate(self.image_original, 90)
else: # direction == 'N'
self.image = self.image_original
screen.blit(self.image, (self.x * self.grid_size, self.y * self.grid_size))
def move(self, dx, dy):
self.x += dx
self.y += dy
def handle_event(self, event, grid_height,grid_width, animals, blocked_fields):
def handle_event(self, event, max_x, max_y, animals, obstacles):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and self.y > 0 and (self.x, self.y-1) not in blocked_fields:
self.move(0, -1)
elif event.key == pygame.K_DOWN and self.y < grid_height - 1 and (self.x, self.y+1) not in blocked_fields:
self.move(0, 1)
elif event.key == pygame.K_LEFT and self.x > 0 and (self.x-1, self.y) not in blocked_fields:
self.move(-1, 0)
elif event.key == pygame.K_RIGHT and self.x < grid_width - 1 and (self.x+1, self.y) not in blocked_fields:
self.move(1, 0)
if event.key == pygame.K_UP:
self.move('Go Forward', max_x, max_y, obstacles)
elif event.key == pygame.K_LEFT:
self.move('Turn Left', max_x, max_y, obstacles)
elif event.key == pygame.K_RIGHT:
self.move('Turn Right', max_x, max_y, obstacles)
for animal in animals:
if self.x == animal.x and self.y == animal.y:
if animal.feed() == 'True':
animal._feed = 0
print(animal.name, "fed with", animal.food)
def move(self, action, max_x, max_y, obstacles):
if action == 'Go Forward':
new_x, new_y = self.x, self.y
if self.direction == 'N':
new_y -= 1
elif self.direction == 'E':
new_x += 1
elif self.direction == 'S':
new_y += 1
elif self.direction == 'W':
new_x -= 1
# Sprawdź, czy nowe położenie mieści się w granicach kraty i nie jest przeszkodą
if is_border(new_x, new_y, max_x, max_y) and not(is_obstacle(new_x, new_y, obstacles)):
self.x, self.y = new_x, new_y
elif action == 'Turn Left':
self.direction = {'N': 'W', 'W': 'S', 'S': 'E', 'E': 'N'}[self.direction]
elif action == 'Turn Right':
self.direction = {'N': 'E', 'E': 'S', 'S': 'W', 'W': 'N'}[self.direction]

View File

@ -1,6 +1,7 @@
import pygame
from abc import ABC, abstractmethod
class Animal:
def __init__(self, x, y,name, image, food_image, food, environment, adult=False,):
self.x = x - 1

BIN
images/agent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 133 KiB

BIN
images/avatar_old.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

92
main.py
View File

@ -8,6 +8,8 @@ from bear import Bear
from agent import Agent
from enclosure import Enclosure
from spawner import Spawner
from state_space_search import succ
from state_space_search import graphsearch
BLACK = (0, 0, 0)
@ -44,10 +46,11 @@ an4 = Elephant(4,3)
Animals = [an1, an2, an3, an4, old_an1, old_an2]
# Enclosure (lewy_górny_x, lewy_górny_y, prawy_dolny_x, prawy_dolny_y, brama, klimat, fenceH, fenceV, gate_obrazek)
en1 = Enclosure(1,5, 9,11, (9,6),"medium", fenceH, fenceV, gate)
en2 = Enclosure(29,3, 13,1,(16,3), 'medium', fenceH, fenceV, gate)
en2 = Enclosure(13,1, 29,3, (16,3), 'medium', fenceH, fenceV, gate)
en3 = Enclosure(11,5, 16,11, (12,5),'cold', fenceH, fenceV, gate)
en4 = Enclosure(19,11, 30,5, (25,5),'hot', fenceH, fenceV, gate)
en4 = Enclosure(19,5, 30,11, (25,5),'hot', fenceH, fenceV, gate)
en5 = Enclosure(4,13, 28,15, (16,13),'cold', fenceH, fenceV, gate)
@ -85,18 +88,89 @@ def spawn_all_animals():
spawner1 = Spawner(Animal, Enclosures)
spawner1.spawn_animal(fences, animals_position)
def generate_obstacles():
obstacles = []
for en in Enclosures:
# Pobierz współrzędne bramy
gate_x, gate_y = en.gate
gate_x -= 1
gate_y -= 1
# Dodaj lewy brzeg prostokąta
for y in range(en.y1, en.y2 + 1):
if (en.x1, y) != (gate_x, gate_y):
obstacles.append((en.x1, y))
# Dodaj prawy brzeg prostokąta
for y in range(en.y1, en.y2 + 1):
if (en.x2, y) != (gate_x, gate_y):
obstacles.append((en.x2, y))
# Dodaj górny brzeg prostokąta
for x in range(en.x1+1, en.x2):
if (x, en.y1) != (gate_x, gate_y):
obstacles.append((x, en.y1))
# Dodaj dolny brzeg prostokąta
for x in range(en.x1+1, en.x2):
if (x, en.y2) != (gate_x, gate_y):
obstacles.append((x, en.y2))
return obstacles
# region Obstacles Tests
# WHITE = (255,255,255)
# TRANSPARENT_BLACK = (0, 0, 0, 128) # Półprzezroczysty czarny
# def draw_obstacles(obstacles):
# for obstacle in obstacles:
# x, y = obstacle
# pygame.draw.rect(screen, TRANSPARENT_BLACK, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
# def main():
# obstacles = generate_obstacles() # Załóżmy, że masz funkcję generate_obstacles, która generuje listę przeszkód
# # Pętla główna
# running = True
# while running:
# # Obsługa zdarzeń
# for event in pygame.event.get():
# if event.type == pygame.QUIT:
# running = False
# # Czyszczenie ekranu
# screen.fill(WHITE)
# # Rysowanie przeszkód
# draw_obstacles(obstacles)
# # Odświeżenie ekranu
# pygame.display.flip()
# # Wyjście z Pygame
# pygame.quit()
# endregion
def main():
agent = Agent(0, 0, 'images/avatar.png', GRID_SIZE)
initial_state = (1,1,'W')
agent = Agent(initial_state, 'images/agent.png', GRID_SIZE)
obstacles = generate_obstacles()
actions = []
spawn_all_animals()
actions = graphsearch(agent.istate, (an1.x, an1.y), GRID_WIDTH, GRID_HEIGHT, obstacles)
# actions = graphsearch(agent.istate, (25,1), GRID_WIDTH, GRID_HEIGHT, obstacles)
clock = pygame.time.Clock()
spawned = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
agent.handle_event(event, GRID_HEIGHT, GRID_WIDTH, Animals, fences)
agent.handle_event(event, GRID_WIDTH, GRID_HEIGHT, Animals, obstacles)
@ -104,14 +178,16 @@ def main():
draw_grid()
draw_enclosures()
draw_gates()
if not spawned:
spawn_all_animals()
spawned = True
draw_Animals()
opengates()
agent.draw(screen)
pygame.display.flip()
clock.tick(10)
if actions:
action = actions.pop(0)
agent.move(action, GRID_WIDTH, GRID_HEIGHT, obstacles)
pygame.time.wait(200)
if __name__ == "__main__":
main()

60
state_space_search.py Normal file
View File

@ -0,0 +1,60 @@
def is_border(x, y, max_x, max_y):
return 0 <= x < max_x and 0 <= y < max_y
def is_obstacle(x, y, obstacles):
return (x, y) in obstacles
def succ(current_state, max_x, max_y, obstacles):
successors = []
x, y, direction = current_state
# Akcja: Do przodu
direction_x, direction_y = {'N': (0, -1), 'E': (1, 0), 'S': (0, 1), 'W': (-1, 0)}[direction] # Słownik przesunięć w zależności od kierunku
new_x, new_y = x + direction_x, y + direction_y
if is_border(new_x, new_y, max_x, max_y) and not(is_obstacle(new_x, new_y, obstacles)):
successors.append(((new_x, new_y, direction), 'Go Forward'))
# Akcja: Obrót w lewo
left_turns = {'N': 'W', 'W': 'S', 'S': 'E', 'E': 'N'} # Słownik kierunków po obrocie w lewo
successors.append(((x, y, left_turns[direction]), 'Turn Left'))
# Akcja: Obrót w prawo
right_turns = {'N': 'E', 'E': 'S', 'S': 'W', 'W': 'N'} # Słownik kierunków po obrocie w prawo
successors.append(((x, y, right_turns[direction]), 'Turn Right'))
return successors
def graphsearch(istate, goal, max_x, max_y, obstacles):
fringe = [{"state": istate, "parent": None, "action": None}]
explored = set()
while fringe:
elem = fringe.pop(0)
state = elem["state"]
if goaltest(state, goal):
return build_action_sequence(elem)
explored.add(state)
successors = succ(state, max_x, max_y, obstacles)
for new_state, action in successors:
if new_state not in fringe and new_state not in explored:
fringe.append({"state": new_state, "parent": elem, "action": action})
return False
def build_action_sequence(node):
actions = []
while node["parent"]:
actions.append(node["action"])
node = node["parent"]
actions.reverse()
return actions
def goaltest(state, goal):
x, y, _ = state
goal_x, goal_y = goal
return (x,y) == (goal_x, goal_y)