diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e99e36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..72f2b55 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.analysis.extraPaths": [ + "./Animals" + ] +} \ No newline at end of file diff --git a/animal.py b/Animals/animal.py similarity index 58% rename from animal.py rename to Animals/animal.py index 2059ffe..a4a40bc 100644 --- a/animal.py +++ b/Animals/animal.py @@ -1,5 +1,5 @@ import pygame -from abc import ABC, abstractmethod +from abc import abstractmethod class Animal: def __init__(self, x, y,name, image, food_image, food, environment, adult=False,): @@ -14,29 +14,31 @@ class Animal: self.environment = environment #hot/cold/medium def draw(self, screen, grid_size): - self.image = pygame.transform.scale(self.image, (grid_size, grid_size)) if self.adult: - # If adult, draw like AdultAnimal + # Jeśli zwierzę jest dorosłe, skaluj obrazek na większy rozmiar new_width = grid_size * 2 new_height = grid_size * 2 scaled_image = pygame.transform.scale(self.image, (new_width, new_height)) screen.blit(scaled_image, (self.x * grid_size, self.y * grid_size)) else: - # If not adult, draw like normal Animal - screen.blit(self.image, (self.x * grid_size, self.y * grid_size)) + # Jeśli zwierzę nie jest dorosłe, skaluj obrazek na rozmiar jednej kratki + scaled_image = pygame.transform.scale(self.image, (grid_size, grid_size)) + screen.blit(scaled_image, (self.x * grid_size, self.y * grid_size)) def draw_exclamation(self, screen, grid_size, x, y): exclamation_image = pygame.image.load('images/exclamation.png') - exclamation_image = pygame.transform.scale(exclamation_image, (grid_size,grid_size)) - screen.blit(exclamation_image, (x*grid_size, y*grid_size - grid_size)) + exclamation_image = pygame.transform.scale(exclamation_image, (int(grid_size * 0.45), int(grid_size * 0.45))) + screen.blit(exclamation_image, (x * grid_size, y * grid_size)) def draw_food(self, screen, grid_size, x, y): + scale = 0.45 food_image = pygame.image.load(self.food_image) - food_image = pygame.transform.scale(food_image, (grid_size,grid_size)) - screen.blit(food_image, (x*grid_size, y*grid_size + grid_size)) - - + if(self.adult): + y = y + 1 + scale = 0.7 + food_image = pygame.transform.scale(food_image, (int(grid_size * scale), int(grid_size * scale))) + screen.blit(food_image, (x * grid_size, (y + 1) * grid_size - int(grid_size * scale))) @abstractmethod def feed(self): @@ -44,4 +46,4 @@ class Animal: @abstractmethod def getting_hungry(self): - pass + pass \ No newline at end of file diff --git a/Animals/animals.py b/Animals/animals.py new file mode 100644 index 0000000..b228a52 --- /dev/null +++ b/Animals/animals.py @@ -0,0 +1,47 @@ +from elephant import Elephant +from giraffe import Giraffe +from penguin import Penguin +from parrot import Parrot +from bear import Bear + +def create_animals(): + giraffe1 = Giraffe(0, 0, adult=True) + giraffe2 = Giraffe(0, 0, adult=True) + giraffe3 = Giraffe(0, 0, adult=True) + giraffe4 = Giraffe(0, 0) + giraffe5 = Giraffe(0, 0) + bear1 = Bear(0, 0, adult=True) + bear2 = Bear(0, 0, adult=True) + bear3 = Bear(0, 0) + bear4 = Bear(0, 0) + bear5 = Bear(0, 0) + penguin1 = Penguin(0, 0) + penguin2 = Penguin(0, 0) + penguin3 = Penguin(0, 0) + penguin4 = Penguin(0, 0) + elephant1 = Elephant(0, 0, adult=True) + elephant2 = Elephant(0, 0, adult=True) + elephant3 = Elephant(0, 0) + elephant4 = Elephant(0, 0) + elephant5 = Elephant(0, 0) + parrot1 = Parrot(0, 0) + parrot2 = Parrot(0, 0) + parrot3 = Parrot(0, 0) + parrot4 = Parrot(0, 0) + parrot5 = Parrot(0, 0) + + Animals = [giraffe1, giraffe2, giraffe3, giraffe4, giraffe5, + bear1, bear2, bear3, bear4, bear5, + elephant1, elephant2, elephant3, elephant4, elephant5, + penguin1, penguin2, penguin3, penguin4, + parrot1, parrot2, parrot3, parrot4, parrot5] + + return Animals + +def draw_Animals(Animals, const): + for Animal in Animals: + Animal.draw(const.screen, const.GRID_SIZE) + if Animal.feed() == 'True': + Animal.draw_exclamation(const.screen, const.GRID_SIZE, Animal.x, Animal.y) + else: + Animal.draw_food(const.screen,const.GRID_SIZE,Animal.x,Animal.y) \ No newline at end of file diff --git a/bear.py b/Animals/bear.py similarity index 95% rename from bear.py rename to Animals/bear.py index e0aafe3..3eb5c65 100644 --- a/bear.py +++ b/Animals/bear.py @@ -2,8 +2,6 @@ from animal import Animal import pygame from datetime import datetime - - class Bear(Animal): def __init__(self, x, y, adult=False): Bear_image = pygame.image.load('images/bear.png') diff --git a/elephant.py b/Animals/elephant.py similarity index 100% rename from elephant.py rename to Animals/elephant.py diff --git a/giraffe.py b/Animals/giraffe.py similarity index 100% rename from giraffe.py rename to Animals/giraffe.py diff --git a/parrot.py b/Animals/parrot.py similarity index 100% rename from parrot.py rename to Animals/parrot.py diff --git a/penguin.py b/Animals/penguin.py similarity index 100% rename from penguin.py rename to Animals/penguin.py diff --git a/__pycache__/adult_animal.cpython-311.pyc b/__pycache__/adult_animal.cpython-311.pyc deleted file mode 100644 index aa04f9e..0000000 Binary files a/__pycache__/adult_animal.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/agent.cpython-311.pyc b/__pycache__/agent.cpython-311.pyc deleted file mode 100644 index 4bfbab3..0000000 Binary files a/__pycache__/agent.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/animal.cpython-311.pyc b/__pycache__/animal.cpython-311.pyc deleted file mode 100644 index 48fc46f..0000000 Binary files a/__pycache__/animal.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/bear.cpython-311.pyc b/__pycache__/bear.cpython-311.pyc deleted file mode 100644 index 7967955..0000000 Binary files a/__pycache__/bear.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/combined_animal.cpython-311.pyc b/__pycache__/combined_animal.cpython-311.pyc deleted file mode 100644 index fd6781a..0000000 Binary files a/__pycache__/combined_animal.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/elephant.cpython-311.pyc b/__pycache__/elephant.cpython-311.pyc deleted file mode 100644 index 92cd0a1..0000000 Binary files a/__pycache__/elephant.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/giraffe.cpython-311.pyc b/__pycache__/giraffe.cpython-311.pyc deleted file mode 100644 index 4f975bc..0000000 Binary files a/__pycache__/giraffe.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/parrot.cpython-311.pyc b/__pycache__/parrot.cpython-311.pyc deleted file mode 100644 index 2142ed6..0000000 Binary files a/__pycache__/parrot.cpython-311.pyc and /dev/null differ diff --git a/__pycache__/penguin.cpython-311.pyc b/__pycache__/penguin.cpython-311.pyc deleted file mode 100644 index 4a2a7bb..0000000 Binary files a/__pycache__/penguin.cpython-311.pyc and /dev/null differ diff --git a/agent.py b/agent.py index bb463e2..19734b3 100644 --- a/agent.py +++ b/agent.py @@ -1,34 +1,66 @@ 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.image.load(image_path) self.image = pygame.transform.scale(self.image, (grid_size, grid_size)) - - def draw(self, screen): + def draw(self, screen, grid_size): + # Obróć obrazek zgodnie z kierunkiem + if self.direction == 'E': + self.image= pygame.image.load('images/agent4.png') + elif self.direction == 'S': + self.image= pygame.image.load('images/agent1.png') + elif self.direction == 'W': + self.image= pygame.image.load('images/agent3.png') + else: # direction == 'N' + self.image= pygame.image.load('images/agent2.png') + self.image = pygame.transform.scale(self.image, (grid_size, grid_size)) 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, animals) + elif event.key == pygame.K_LEFT: + self.move('Turn Left', max_x, max_y, obstacles, animals) + elif event.key == pygame.K_RIGHT: + self.move('Turn Right', max_x, max_y, obstacles, animals) + def move(self, action, max_x, max_y, obstacles, animals, goal): + 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] + + self.istate = (self.x, self.y, self.direction) + feed_animal(self, animals, goal) + +def feed_animal(self, animals, goal): + goal_x, goal_y = goal + if self.x == goal_x and self.y == goal_y: for animal in animals: - if self.x == animal.x and self.y == animal.y: - if animal.feed()== 'True': + if animal.x == goal_x and animal.y == goal_y: + if animal.feed() == 'True': animal._feed = 0 - print(animal.name,"fed with",animal.food) + print(animal.name, "fed with", animal.food) \ No newline at end of file diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..2796685 --- /dev/null +++ b/constants.py @@ -0,0 +1,15 @@ +import pygame + +class Constants: + def __init__(self): + self.BLACK = (0, 0, 0) + self.RED = (255, 0, 0) + self.GRID_SIZE = 50 + self.GRID_WIDTH = 30 + self.GRID_HEIGHT = 15 + self.WINDOW_SIZE = (self.GRID_WIDTH * self.GRID_SIZE, self.GRID_HEIGHT * self.GRID_SIZE) + self.background_image = pygame.transform.scale(pygame.image.load('images/tło.jpg'), self.WINDOW_SIZE) + +def init_pygame(const): + pygame.init() + const.screen = pygame.display.set_mode(const.WINDOW_SIZE) \ No newline at end of file diff --git a/draw.py b/draw.py new file mode 100644 index 0000000..f032281 --- /dev/null +++ b/draw.py @@ -0,0 +1,14 @@ +import pygame + +def draw_goal(const, goal): + x, y = goal + rect = (x * const.GRID_SIZE, y * const.GRID_SIZE, const.GRID_SIZE, const.GRID_SIZE) + pygame.draw.rect(const.screen, const.RED, rect) + pygame.display.flip() + pygame.time.delay(2000) + +def draw_grid(const): + for y in range(0, const.GRID_HEIGHT * const.GRID_SIZE, const.GRID_SIZE): + for x in range(0, const.GRID_WIDTH * const.GRID_SIZE, const.GRID_SIZE): + rect = pygame.Rect(x, y, const.GRID_SIZE, const.GRID_SIZE) + pygame.draw.rect(const.screen, const.BLACK, rect, 1) \ No newline at end of file diff --git a/enclosure.py b/enclosure.py index 2a79c52..723e243 100644 --- a/enclosure.py +++ b/enclosure.py @@ -1,14 +1,16 @@ import pygame + class Enclosure: - def __init__(self, x1, y1, x2, y2, gate, type, imageH, imageV, imageGate): + def __init__(self, x1, y1, x2, y2, gate1, gate2, type, imageH, imageV, imageGate): self.x1 = x1 - 1 self.y1 = y1 - 1 - #(x1,y1) - wierzchołek przekątnej + # (x1,y1) - wierzchołek przekątnej self.x2 = x2 - 1 self.y2 = y2 - 1 - #(x2,y2) - 2 wierzchołek przekątnej - self.gate = gate + # (x2,y2) - 2 wierzchołek przekątnej + self.gate1 = gate1 + self.gate2 = gate2 self.type = type self.imageH = imageH self.imageV = imageV @@ -16,64 +18,57 @@ class Enclosure: def gatebuild(self, screen, grid_size): self.imageGate = pygame.transform.scale(self.imageGate, (grid_size, grid_size)) - gate_x, gate_y = self.gate - gate_x-=1 - gate_y-=1 - rect = pygame.Rect(gate_x * grid_size, gate_y * grid_size, grid_size, grid_size) - pygame.draw.rect(screen, (0, 0, 0), rect) # Fill the area with - screen.blit(self.imageGate, (gate_x * grid_size, gate_y * grid_size)) + gate_x1, gate_y1 = self.gate1 + gate_x2, gate_y2 = self.gate2 + gate_x1 -= 1 + gate_y1 -= 1 + gate_x2 -= 1 + gate_y2 -= 1 + rect1 = pygame.Rect(gate_x1 * grid_size, gate_y1 * grid_size, grid_size, grid_size) + rect2 = pygame.Rect(gate_x2 * grid_size, gate_y2 * grid_size, grid_size, grid_size) + screen.blit(self.imageGate, (gate_x1 * grid_size, gate_y1 * grid_size)) + screen.blit(self.imageGate, (gate_x2 * grid_size, gate_y2 * grid_size)) - def gateopen(self, blocked): - gate_x, gate_y = self.gate - gate_x -= 1 - gate_y -= 1 - if (gate_x, gate_y) in blocked: - blocked.remove((gate_x, gate_y)) - - - - def draw(self,screen, grid_size , blocked_fields): + def draw(self, screen, grid_size): self.imageH = pygame.transform.scale(self.imageH, (grid_size, grid_size)) self.imageV = pygame.transform.scale(self.imageV, (grid_size, grid_size)) + gate_x1, gate_y1 = self.gate1 + gate_x2, gate_y2 = self.gate2 + gate_x1 -= 1 + gate_y1 -= 1 + gate_x2 -= 1 + gate_y2 -= 1 if self.x1 < self.x2: - for i in range(self.x1, self.x2+1): - screen.blit(self.imageH, (i * grid_size, self.y1 * grid_size)) - blocked_fields.add((i, self.y1)) - screen.blit(self.imageH, (i * grid_size, self.y2 * grid_size)) - blocked_fields.add((i, self.y2)) - if self.y1 < self.y2: - for j in range(self.y1, self.y2+1): - screen.blit(self.imageH, (self.x1 * grid_size, j * grid_size)) - blocked_fields.add((self.x1, j)) - screen.blit(self.imageH, (self.x2 * grid_size, j * grid_size)) - blocked_fields.add((self.x2, j)) - if self.y1 > self.y2: - for j in range(self.y2, self.y1+1): - screen.blit(self.imageH, (self.x1 * grid_size, j * grid_size)) - blocked_fields.add((self.x1, j)) - screen.blit(self.imageH, (self.x2 * grid_size, j * grid_size)) - blocked_fields.add((self.x2, j)) - if self.x1 > self.x2: - for i in range(self.x2, self.x1+1): - screen.blit(self.imageH, (i * grid_size, self.y1 * grid_size)) - blocked_fields.add((i, self.y1)) - screen.blit(self.imageH, (i * grid_size, self.y2 * grid_size)) - blocked_fields.add((i, self.y2)) - if self.y1 < self.y2: - for j in range(self.y1, self.y2+1): - screen.blit(self.imageH, (self.x1 * grid_size, j * grid_size)) - blocked_fields.add((self.x1, j)) - screen.blit(self.imageH, (self.x2 * grid_size, j * grid_size)) - blocked_fields.add((self.x2, j)) - if self.y1 > self.y2: - for j in range(self.y2, self.y1+1): - screen.blit(self.imageH, (self.x1 * grid_size, j * grid_size)) - blocked_fields.add((self.x1, j)) - screen.blit(self.imageH, (self.x2 * grid_size, j * grid_size)) - blocked_fields.add((self.x2, j)) + for i in range(self.x1, self.x2 + 1): + if (i, self.y1) != (gate_x1, gate_y1) and (i, self.y1) != (gate_x2, gate_y2): + screen.blit(self.imageH, (i * grid_size, self.y1 * grid_size)) + if (i, self.y2) != (gate_x1, gate_y1) and (i, self.y2) != (gate_x2, gate_y2): + screen.blit(self.imageH, (i * grid_size, self.y2 * grid_size)) + for j in range(self.y1, self.y2 + 1): + if (self.x1, j) != (gate_x1, gate_y1) and (self.x1, j) != (gate_x2, gate_y2): + screen.blit(self.imageV, (self.x1 * grid_size, j * grid_size)) + if (self.x2, j) != (gate_x1, gate_y1) and (self.x2, j) != (gate_x2, gate_y2): + screen.blit(self.imageV, (self.x2 * grid_size, j * grid_size)) +def create_enclosures(): + fenceH = pygame.image.load('images/fenceHor.png') + fenceV = pygame.image.load('images/fenceVer.png') + gate = pygame.image.load('images/gate.png') + en1 = Enclosure(0, 5, 9, 11, (9, 6), (4, 11), "hot", fenceH, fenceV, gate) # Lewa klatka + en2 = Enclosure(13, 0, 29, 3, (16, 3), (27, 3), 'medium', fenceH, fenceV, gate) # Górna klatka + en3 = Enclosure(11, 5, 16, 11, (12, 5), (16, 8), 'cold', fenceH, fenceV, gate) # Środkowa klatka + en4 = Enclosure(19, 5, 31, 11, (23, 5), (25, 11), 'hot', fenceH, fenceV, gate) # Prawa klatka + en5 = Enclosure(4, 13, 28, 16, (12, 13), (20, 13), 'cold', fenceH, fenceV, gate) # Dolna klatka + Enclosures = [en1, en2, en3, en4, en5] + return Enclosures +def draw_enclosures(Enclosures, const): + for enclosure in Enclosures: + enclosure.draw(const.screen, const.GRID_SIZE) +def draw_gates(Enclosures, const): + for enclosure in Enclosures: + enclosure.gatebuild(const.screen, const.GRID_SIZE) \ No newline at end of file diff --git a/images/agent1.png b/images/agent1.png new file mode 100644 index 0000000..6370d60 Binary files /dev/null and b/images/agent1.png differ diff --git a/images/agent2.png b/images/agent2.png new file mode 100644 index 0000000..4405e80 Binary files /dev/null and b/images/agent2.png differ diff --git a/images/agent3.png b/images/agent3.png new file mode 100644 index 0000000..3b850ad Binary files /dev/null and b/images/agent3.png differ diff --git a/images/agent4.png b/images/agent4.png new file mode 100644 index 0000000..a6feab8 Binary files /dev/null and b/images/agent4.png differ diff --git a/images/avatar.png b/images/avatar.png deleted file mode 100644 index 4d290c1..0000000 Binary files a/images/avatar.png and /dev/null differ diff --git a/images/bear.png b/images/bear.png index e02a84f..3c5267b 100644 Binary files a/images/bear.png and b/images/bear.png differ diff --git a/images/bush.png b/images/bush.png new file mode 100644 index 0000000..7a3276d Binary files /dev/null and b/images/bush.png differ diff --git a/images/exclamation.png b/images/exclamation.png index 4e7d6c7..2dd1b27 100644 Binary files a/images/exclamation.png and b/images/exclamation.png differ diff --git a/images/fenceVer.png b/images/fenceVer.png index 2699618..b86e9b6 100644 Binary files a/images/fenceVer.png and b/images/fenceVer.png differ diff --git a/images/fish.png b/images/fish.png index 8a5f710..e396358 100644 Binary files a/images/fish.png and b/images/fish.png differ diff --git a/images/giraffe.png b/images/giraffe.png index 8035ad6..8247a89 100644 Binary files a/images/giraffe.png and b/images/giraffe.png differ diff --git a/images/meat.png b/images/meat.png index 34a3d23..fe2b9c6 100644 Binary files a/images/meat.png and b/images/meat.png differ diff --git a/images/milk.png b/images/milk.png index b51a627..326de64 100644 Binary files a/images/milk.png and b/images/milk.png differ diff --git a/images/parrot.png b/images/parrot.png index b38bf98..df1a787 100644 Binary files a/images/parrot.png and b/images/parrot.png differ diff --git a/images/penguin.png b/images/penguin.png index 6e80909..f82c874 100644 Binary files a/images/penguin.png and b/images/penguin.png differ diff --git a/images/puddle.png b/images/puddle.png new file mode 100644 index 0000000..049fb40 Binary files /dev/null and b/images/puddle.png differ diff --git a/main.py b/main.py index 18de593..8246fde 100644 --- a/main.py +++ b/main.py @@ -1,117 +1,116 @@ +import random import pygame import sys -from elephant import Elephant -from giraffe import Giraffe -from penguin import Penguin -from parrot import Parrot -from bear import Bear +import sys +sys.path.append('./Animals') +from animals import create_animals, draw_Animals from agent import Agent -from enclosure import Enclosure +from enclosure import create_enclosures, draw_enclosures, draw_gates from spawner import Spawner +from state_space_search import graphsearch, generate_cost_map +from terrain_obstacle import create_obstacles, draw_Terrain_Obstacles +from constants import Constants, init_pygame +from draw import draw_goal, draw_grid -BLACK = (0, 0, 0) - -GRID_SIZE = 50 -GRID_WIDTH = 30 -GRID_HEIGHT = 15 - -pygame.init() - -WINDOW_SIZE = (GRID_WIDTH * GRID_SIZE, GRID_HEIGHT * GRID_SIZE) -screen = pygame.display.set_mode(WINDOW_SIZE) +const = Constants() +init_pygame(const) pygame.display.set_caption("Mini Zoo") - - -background_image = pygame.image.load('images/tło.jpg') -background_image = pygame.transform.scale(background_image, WINDOW_SIZE) -fenceH = pygame.image.load('images/fenceHor.png') -fenceV = pygame.image.load('images/fenceVer.png') -gate = pygame.image.load('images/gate.png') - - -fences = set() +obstacles = set() animals_position = set() +terrain_obstacles_position = set() - - -an1 = Parrot(16, 2) -an2 = Penguin(8, 6) -an3 = Bear(14, 9) -old_an2 = Giraffe(18,4, adult=True) -old_an1 = Elephant(4, 7, adult=True) -an4 = Elephant(4,3) - -Animals = [an1, an2, an3, an4, old_an1, old_an2] - -en1 = Enclosure(1,5,9,11,(9,6),"medium", fenceH, fenceV, gate) -en2 = Enclosure(29,3, 13,1,(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) -en5 = Enclosure(4,13, 28,15, (16,13),'cold', fenceH, fenceV, gate) - - -Enclosures = [en1, en2, en3, en4, en5] - - -def draw_grid(): - for y in range(0, GRID_HEIGHT * GRID_SIZE, GRID_SIZE): - for x in range(0, GRID_WIDTH * GRID_SIZE, GRID_SIZE): - rect = pygame.Rect(x, y, GRID_SIZE, GRID_SIZE) - pygame.draw.rect(screen, BLACK, rect, 1) - -def draw_enclosures(): - for enclosure in Enclosures: - enclosure.draw(screen, GRID_SIZE, fences) - -def draw_gates(): - for enclosure in Enclosures: - enclosure.gatebuild(screen, GRID_SIZE) - -def opengates(): - for enclosure in Enclosures: - enclosure.gateopen(fences) - -def draw_Animals(): - for Animal in Animals: - Animal.draw(screen, GRID_SIZE) - if Animal.feed() == 'True': - Animal.draw_exclamation(screen, GRID_SIZE, Animal.x, Animal.y) - else: - Animal.draw_food(screen,GRID_SIZE,Animal.x,Animal.y) +Animals = create_animals() +Enclosures = create_enclosures() +Terrain_Obstacles = create_obstacles() def spawn_all_animals(): for Animal in Animals: - spawner1 = Spawner(Animal, Enclosures) - spawner1.spawn_animal(fences, animals_position) + spawner1 = Spawner(Animal) + spawner1.spawn_animal(obstacles, animals_position, Enclosures) +def spawn_obstacles(): + for terrain_obstacle in Terrain_Obstacles: + spawner2 = Spawner(terrain_obstacle) + spawner2.spawn_terrain_obstacles(obstacles, animals_position, terrain_obstacles_position, const.GRID_WIDTH, const.GRID_HEIGHT) +def generate_obstacles(): + for en in Enclosures: + # Pobierz współrzędne bramy + gate_x, gate_y = en.gate1 + gate_x -= 1 + gate_y -= 1 + + gate_x2, gate_y2 = en.gate2 + gate_x2 -= 1 + gate_y2 -= 1 + + # Dodaj lewy brzeg prostokąta + for y in range(en.y1, en.y2 + 1): + if (en.x1, y) != (gate_x, gate_y) and (en.x1, y) != (gate_x2, gate_y2): + obstacles.add((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) and (en.x2, y) != (gate_x2, gate_y2): + obstacles.add((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) and (x, en.y1) != (gate_x2, gate_y2): + obstacles.add((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) and (x, en.y2) != (gate_x2, gate_y2): + obstacles.add((x, en.y2)) + + return obstacles def main(): - agent = Agent(0, 0, 'images/avatar.png', GRID_SIZE) + initial_state = (0, 0, 'S') + agent = Agent(initial_state, 'images/agent1.png', const.GRID_SIZE) + + obstacles = generate_obstacles() + actions = [] 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, const.GRID_WIDTH, const.GRID_HEIGHT, Animals, obstacles) - + const.screen.blit(const.background_image, (0, 0)) + draw_grid(const) + draw_enclosures(Enclosures, const) + draw_gates(Enclosures, const) - screen.blit(background_image,(0,0)) - draw_grid() - draw_enclosures() - draw_gates() if not spawned: spawn_all_animals() + spawn_obstacles() + cost_map = generate_cost_map(Animals, Terrain_Obstacles) + for animal in Animals: + animal._feed = 2 # Ustawienie, aby zwierzę było głodne spawned = True - draw_Animals() - opengates() - agent.draw(screen) + + draw_Animals(Animals, const) + draw_Terrain_Obstacles(Terrain_Obstacles, const) + agent.draw(const.screen, const.GRID_SIZE) pygame.display.flip() clock.tick(10) + if actions: + action = actions.pop(0) + agent.move(action, const.GRID_WIDTH, const.GRID_HEIGHT, obstacles, Animals, goal) + pygame.time.wait(200) + else: + animal = random.choice(Animals) + goal = (animal.x, animal.y) + draw_goal(const, goal) + actions = graphsearch(agent.istate, goal, const.GRID_WIDTH, const.GRID_HEIGHT, obstacles, cost_map) + if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/spawner.py b/spawner.py index 181ea06..29f89eb 100644 --- a/spawner.py +++ b/spawner.py @@ -1,44 +1,53 @@ import random - class Spawner: - def __init__(self, animal, enclosures): - self.animal = animal - self.enclosures = enclosures + def __init__(self, entity): + self.entity = entity + + def spawn_animal(self, blocked, taken, enclosures): + self.enclosures = [enclosure for enclosure in enclosures if enclosure.type == self.entity.environment] + # Wyrażenie listowe filtrujące tylko te wybiegi, które pasują do środowiska zwierzęcia + enclosure = random.choice(self.enclosures) - def spawn_animal(self, blocked, taken): - possibilities = self.enclosures - fitting = [] - for option in possibilities: - if option.type == self.animal.environment: - fitting.append(option) - enclosure = random.choice(fitting) while True: - if enclosure.x1 < enclosure.x2: - self.animal.x = random.randint(enclosure.x1, enclosure.x2) - if enclosure.y1 < enclosure.y2: - self.animal.y = random.randint(enclosure.y1, enclosure.y2) - if enclosure.y1 > enclosure.y2: - self.animal.y = random.randint(enclosure.y2, enclosure.y1) - if enclosure.x1 > enclosure.x2: - self.animal.x = random.randint(enclosure.x2, enclosure.x1) - if enclosure.y1 < enclosure.y2: - self.animal.y = random.randint(enclosure.y1, enclosure.y2) - if enclosure.y1 > enclosure.y2: - self.animal.y = random.randint(enclosure.y2, enclosure.y1) - if self.check(blocked, taken): + if self.entity.adult: + self.entity.x = random.randint(enclosure.x1+1, enclosure.x2-2) + self.entity.y = random.randint(enclosure.y1+1, enclosure.y2-2) + else: + self.entity.x = random.randint(enclosure.x1+1, enclosure.x2) + self.entity.y = random.randint(enclosure.y1+1, enclosure.y2) + + if self.check(blocked | {(8,5),(3,10),(15,2),(26,2),(11,4),(15,7),(22,4),(24,10),(11,12),(19,12)}, taken): + break + + def spawn_terrain_obstacles(self, blocked1, blocked2, taken, grid_width, grid_height): + blocked1 = blocked1 | {(8,5),(3,10),(15,2),(26,2),(11,4),(15,7),(22,4),(24,10),(11,12),(19,12)} + while True: + self.entity.x = random.randint(0, grid_width - 1) + self.entity.y = random.randint(0, grid_height - 1) + y = self.entity.y + x = self.entity.x + if (x, y) not in blocked1 and (x, y) not in blocked2 and (x, y) not in taken: + taken.add((self.entity.x, self.entity.y)) break def check(self, blocked, taken): - x = self.animal.x - y = self.animal.y + x = self.entity.x + y = self.entity.y + if (x,y) in blocked or (x,y) in taken: return False - taken.add((x,y)) - return True - - - + if self.entity.adult: + + adult_fields = [(x, y), (x+1,y), (x,y+1), (x+1,y+1)] # Duże zwierze zajmuje 4 pola + if any(field in taken for field in adult_fields): # Jeśli stawiane zwierze jest dorosłe i jakiekolwiek pole jest zajęte, to nie można postawić zwierzęcia + return False + + for field in adult_fields: # Dodaj wszystkie pola zajęte przez duże zwierzę + taken.add(field) + else: + taken.add((x,y)) + return True \ No newline at end of file diff --git a/state_space_search.py b/state_space_search.py new file mode 100644 index 0000000..7aae41e --- /dev/null +++ b/state_space_search.py @@ -0,0 +1,127 @@ +from queue import PriorityQueue + +DEFAULT_COST_VALUE = 1 + +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, cost_map): + fringe = PriorityQueue() + explored = set() + + fringe.put((0, (istate, None , None))) + + while not fringe.empty(): + _, node = fringe.get() + state, _, _ = node + + if goaltest(state, goal): + return build_action_sequence(node) + + explored.add(state) + + successors = succ(state, max_x, max_y, obstacles) + + for new_state, action in successors: + new_node = (new_state, node, action) + + p_new_state = current_cost(node, cost_map) + heuristic(state, goal) + + if not is_state_in_queue(new_state, fringe) and new_state not in explored: + fringe.put((p_new_state, new_node)) + + elif is_state_in_queue(new_state, fringe): + for i, (p_existing_state, (existing_state, _, _)) in enumerate(fringe.queue): + if existing_state == new_state and p_existing_state > p_new_state: + fringe.queue[i] = (p_new_state, new_node) + else: + break + + return False + +def is_state_in_queue(state, queue): + for _, (s, _, _) in queue.queue: + if s == state: + return True + return False + +def build_action_sequence(node): + actions = [] + while node[1] is not None: # Dopóki nie dojdziemy do korzenia + _, parent, action = node + actions.append(action) + 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) + +def current_cost(node, cost_map): + cost = 0 + while node[1] is not None: # Dopóki nie dojdziemy do korzenia + _, parent, action = node + # Dodaj koszt pola z mapy kosztów tylko jeśli akcja to "Forward" + if action == 'Go Forward': + state, _, _ = node + cost += cost_map.get(state[:2], DEFAULT_COST_VALUE) # Pobiera koszt przejścia przez dane pole, a jeśli koszt nie jest zdefiniowany to bierze wartość domyślną + + if action == 'Turn Right' or action == 'Turn Left': + cost += DEFAULT_COST_VALUE + + node = parent # Przejdź do rodzica + return cost + +def heuristic(state, goal): + x, y, _ = state + goal_x, goal_y = goal + return abs(x - goal_x) + abs(y - goal_y) # Odległość Manhattana do celu + +def generate_cost_map(Animals, Terrain_Obstacles, cost_map={}): + adult_animal_cost = 15 # Default : 15 + baby_animal_cost = 10 # Default : 10 + puddle_cost = 50 # Default : 50 + bush_cost = 20 # Default : 20 + + for animal in Animals: + if animal.adult: + cost_map[(animal.x + 1, animal.y + 1)] = adult_animal_cost + cost_map[(animal.x + 1, animal.y)] = adult_animal_cost + cost_map[(animal.x, animal.y + 1)] = adult_animal_cost + cost_map[(animal.x, animal.y)] = adult_animal_cost + else: + cost_map[(animal.x, animal.y)] = baby_animal_cost + + for terrain_obstacle in Terrain_Obstacles: + if terrain_obstacle.type == 'puddle': + cost_map[(terrain_obstacle.x , terrain_obstacle.y )] = puddle_cost + else: + cost_map[(terrain_obstacle.x , terrain_obstacle.y )] = bush_cost + + return cost_map \ No newline at end of file diff --git a/terrain_obstacle.py b/terrain_obstacle.py new file mode 100644 index 0000000..9e00d61 --- /dev/null +++ b/terrain_obstacle.py @@ -0,0 +1,37 @@ +import pygame + +class Terrain_Obstacle: + def __init__(self, x, y, type , image): + self.x = x - 1 + self.y = y - 1 + self.type = type + self.image = image + + def draw(self, screen, grid_size): + scaled_image = pygame.transform.scale(self.image, (grid_size, grid_size)) + screen.blit(scaled_image, (self.x * grid_size, self.y * grid_size)) + +def create_obstacles(): + puddle_image = pygame.image.load('images/puddle.png') + bush_image = pygame.image.load('images/bush.png') + + puddle1 = Terrain_Obstacle(0,0,'puddle', puddle_image) + puddle2 = Terrain_Obstacle(0,0,'puddle', puddle_image) + puddle3 = Terrain_Obstacle(0,0,'puddle', puddle_image) + puddle4 = Terrain_Obstacle(0,0,'puddle', puddle_image) + puddle5 = Terrain_Obstacle(0,0,'puddle', puddle_image) + puddle6 = Terrain_Obstacle(0,0,'puddle', puddle_image) + puddle7 = Terrain_Obstacle(0,0,'puddle', puddle_image) + bush1 = Terrain_Obstacle(0,0,'bush', bush_image) + bush2 = Terrain_Obstacle(0,0,'bush', bush_image) + bush3 = Terrain_Obstacle(0,0,'bush', bush_image) + bush4 = Terrain_Obstacle(0,0,'bush', bush_image) + bush5 = Terrain_Obstacle(0,0,'bush', bush_image) + + Terrain_Obstacles = [puddle1, puddle2, puddle3, puddle4, puddle5, puddle6, puddle7, bush1, bush2, bush3, bush4, bush5] + + return Terrain_Obstacles + +def draw_Terrain_Obstacles(Terrain_Obstacles, const): + for terrain_obstacle in Terrain_Obstacles: + terrain_obstacle.draw(const.screen, const.GRID_SIZE) \ No newline at end of file