diff --git a/.idea/misc.xml b/.idea/misc.xml index 812ab5a..dfd527a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/.idea/sztuczna.iml b/.idea/sztuczna.iml index d0876a7..c24009a 100644 --- a/.idea/sztuczna.iml +++ b/.idea/sztuczna.iml @@ -1,8 +1,10 @@ - - + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Animals/animal.py b/Animals/animal.py index a4a40bc..d889ba9 100644 --- a/Animals/animal.py +++ b/Animals/animal.py @@ -1,17 +1,31 @@ +import random import pygame from abc import abstractmethod class Animal: - def __init__(self, x, y,name, image, food_image, food, environment, adult=False,): + + def choose_picture(self, name): + ran = random.randint(0, 1) + if ran == 0: + path = f'images/{name}.png' + return path + else: + path = f'images/{name}2.png' + return path + + def __init__(self, x, y,name, image_path, food_image, food, environment, activity, ill=False, adult=False,): self.x = x - 1 self.y = y - 1 self.name = name - self.image = image + self.image_path = image_path + self.image = pygame.image.load(image_path) self.adult = adult self.food = food self.food_image = food_image self._feed = 0 - self.environment = environment #hot/cold/medium + self.environment = environment # hot/cold/medium + self.activity = activity # diurnal/nocturnal + self.ill = ill def draw(self, screen, grid_size): if self.adult: @@ -30,9 +44,9 @@ class Animal: 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): + def draw_food(self, screen, grid_size, x, y,food_image): scale = 0.45 - food_image = pygame.image.load(self.food_image) + food_image = pygame.image.load(food_image) if(self.adult): y = y + 1 @@ -40,9 +54,32 @@ class Animal: 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): - pass + def is_ill(self): + chance = random.randint(1, 100) + if chance >= 90: + return True + else: return False + + def draw_illness(self, screen, grid_size, x, y): + scale = 0.45 + illness_image = pygame.image.load('images/ill.png') + y = y + + if self.adult: + x = x + 1 + y = y + scale = 0.7 + + x_blit = x * grid_size + (grid_size - int(grid_size * scale)) + illness_image = pygame.transform.scale(illness_image, (int(grid_size * scale), int(grid_size * scale))) + screen.blit(illness_image, (x_blit, y * grid_size)) + + def draw_snack(self, screen, grid_size, x, y): + exclamation_image = pygame.image.load(self.food_image) + 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)) + pygame.display.update() + pygame.time.wait(700) @abstractmethod def getting_hungry(self): diff --git a/Animals/animals.py b/Animals/animals.py index b228a52..4823cd9 100644 --- a/Animals/animals.py +++ b/Animals/animals.py @@ -3,6 +3,8 @@ from giraffe import Giraffe from penguin import Penguin from parrot import Parrot from bear import Bear +from owl import Owl +from bat import Bat def create_animals(): giraffe1 = Giraffe(0, 0, adult=True) @@ -26,22 +28,35 @@ def create_animals(): elephant5 = Elephant(0, 0) parrot1 = Parrot(0, 0) parrot2 = Parrot(0, 0) - parrot3 = Parrot(0, 0) - parrot4 = Parrot(0, 0) - parrot5 = Parrot(0, 0) + owl1 = Owl(0, 0) + owl2 = Owl(0, 0) + bat1 = Bat(0, 0) + bat2 = Bat(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] + parrot1, parrot2, owl1, owl2, bat1, bat2] 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 + + hunger_level = Animal.getting_hungry(const) + + if hunger_level >= 9: + food_image = 'images/empty_bowl.png' + elif hunger_level >= 8: + food_image = 'images/almost_empty.png' + elif hunger_level >= 5: + food_image = 'images/half_bowl.png' + else: + food_image = 'images/full_bowl.png' + + Animal.draw_food(const.screen, const.GRID_SIZE, Animal.x, Animal.y, food_image) + + if Animal.ill: + Animal.draw_illness(const.screen, const.GRID_SIZE, Animal.x, Animal.y) \ No newline at end of file diff --git a/Animals/bat.py b/Animals/bat.py new file mode 100644 index 0000000..83dc661 --- /dev/null +++ b/Animals/bat.py @@ -0,0 +1,26 @@ +from animal import Animal +import pygame +from datetime import datetime + +class Bat(Animal): + def __init__(self, x, y, adult=False): + name = 'bat' + image_path = self.choose_picture(name) + environment = "medium" + food_image = 'images/grains.png' + parrot_food = 'grains' + activity = 'nocturnal' + super().__init__(x, y,name, image_path, food_image,parrot_food, environment, adult) + self._starttime = datetime.now() + + def getting_hungry(self, const): + checktime = datetime.now() + delta = checktime - self._starttime + minutes_passed = delta.total_seconds() / (25) + self._starttime = checktime + + if const.IS_NIGHT and self._feed < 10: + self._feed += minutes_passed + self._feed = min(self._feed, 10) + + return self._feed \ No newline at end of file diff --git a/Animals/bear.py b/Animals/bear.py index 3eb5c65..2950042 100644 --- a/Animals/bear.py +++ b/Animals/bear.py @@ -4,27 +4,24 @@ from datetime import datetime class Bear(Animal): def __init__(self, x, y, adult=False): - Bear_image = pygame.image.load('images/bear.png') name = 'bear' + image_path = self.choose_picture(name) environment = "cold" + activity = 'nocturnal' + ill = self.is_ill() bear_food = 'meat' food_image = 'images/meat.png' - super().__init__(x, y,name, Bear_image, food_image,bear_food,environment, adult) + super().__init__(x, y,name, image_path, food_image,bear_food,environment, activity, ill, adult) self._starttime = datetime.now() - - - def feed(self): - self.getting_hungry() - if self._feed < 2: - return 'False' - else: - return 'True' + def getting_hungry(self, const): - - def getting_hungry(self): checktime = datetime.now() delta = checktime - self._starttime - minutes_passed = delta.total_seconds() / 60 - self._feed += minutes_passed - self._starttime = checktime \ No newline at end of file + minutes_passed = delta.total_seconds() / (45) + self._starttime = checktime + + if const.IS_NIGHT and self._feed < 10 and const.season != "winter": + self._feed += minutes_passed + self._feed = min(self._feed, 10) + return self._feed \ No newline at end of file diff --git a/Animals/elephant.py b/Animals/elephant.py index 4e63bfb..701b40d 100644 --- a/Animals/elephant.py +++ b/Animals/elephant.py @@ -2,13 +2,13 @@ from animal import Animal import pygame from datetime import datetime - - class Elephant(Animal): def __init__(self, x, y, adult=False): - Elephant_image = pygame.image.load('images/elephant.png') name = 'elephant' + image_path = self.choose_picture(name) environment = "hot" + activity = 'diurnal' + ill = self.is_ill() if adult: elephant_food = 'leavs' food_image = 'images/leaves.png' @@ -16,22 +16,16 @@ class Elephant(Animal): elephant_food = 'milk' food_image = 'images/milk.png' - super().__init__(x, y,name, Elephant_image, food_image,elephant_food, environment, adult) + super().__init__(x, y,name, image_path, food_image,elephant_food, environment, activity, ill, adult) self._starttime = datetime.now() - - - - def feed(self): - self.getting_hungry() - if self._feed < 0.3: - return 'False' - else: - return 'True' - - - def getting_hungry(self): + + def getting_hungry(self, const): checktime = datetime.now() delta = checktime - self._starttime - minutes_passed = delta.total_seconds() / 60 - self._feed += minutes_passed - self._starttime = checktime \ No newline at end of file + minutes_passed = delta.total_seconds() / (90) + self._starttime = checktime + + if not const.IS_NIGHT and self._feed < 10: + self._feed += minutes_passed + self._feed = min(self._feed, 10) + return self._feed \ No newline at end of file diff --git a/Animals/giraffe.py b/Animals/giraffe.py index f5c191f..93479bb 100644 --- a/Animals/giraffe.py +++ b/Animals/giraffe.py @@ -2,31 +2,25 @@ from animal import Animal import pygame from datetime import datetime - - class Giraffe(Animal): def __init__(self, x, y, adult=False): - Giraffe_image = pygame.image.load('images/giraffe.png') name = 'giraffe' + image_path = self.choose_picture(name) environment = "hot" + activity = 'diurnal' + ill = self.is_ill() food_image = 'images/leaves.png' giraffe_food = 'leaves' - super().__init__(x, y,name, Giraffe_image, food_image,giraffe_food, environment, adult) + super().__init__(x, y, name, image_path, food_image,giraffe_food, environment, activity, ill, adult) self._starttime = datetime.now() - - - def feed(self): - self.getting_hungry() - if self._feed < 0.8: - return 'False' - else: - return 'True' - - - def getting_hungry(self): + def getting_hungry(self, const): checktime = datetime.now() delta = checktime - self._starttime - minutes_passed = delta.total_seconds() / 60 - self._feed += minutes_passed - self._starttime = checktime \ No newline at end of file + minutes_passed = delta.total_seconds() / (60) + self._starttime = checktime + + if not const.IS_NIGHT and self._feed < 10: + self._feed += minutes_passed + self._feed = min(self._feed, 10) + return self._feed \ No newline at end of file diff --git a/Animals/owl.py b/Animals/owl.py new file mode 100644 index 0000000..fb6125f --- /dev/null +++ b/Animals/owl.py @@ -0,0 +1,26 @@ +from animal import Animal +import pygame +from datetime import datetime + +class Owl(Animal): + def __init__(self, x, y, adult=False): + name = 'owl' + image_path = self.choose_picture(name) + environment = "medium" + food_image = 'images/grains.png' + parrot_food = 'grains' + activity = 'nocturnal' + super().__init__(x, y,name, image_path, food_image,parrot_food, environment, adult) + self._starttime = datetime.now() + + def getting_hungry(self, const): + checktime = datetime.now() + delta = checktime - self._starttime + minutes_passed = delta.total_seconds() / (50) + self._starttime = checktime + + if const.IS_NIGHT and self._feed < 10: + self._feed += minutes_passed + self._feed = min(self._feed, 10) + + return self._feed \ No newline at end of file diff --git a/Animals/parrot.py b/Animals/parrot.py index 1873b53..e675e8d 100644 --- a/Animals/parrot.py +++ b/Animals/parrot.py @@ -2,31 +2,25 @@ from animal import Animal import pygame from datetime import datetime - - class Parrot(Animal): def __init__(self, x, y, adult=False): - Parrot_image = pygame.image.load('images/parrot.png') name = 'parrot' + image_path = self.choose_picture(name) environment = "medium" + activity = 'diurnal' + ill = self.is_ill() food_image = 'images/grains.png' parrot_food = 'grains' - super().__init__(x, y,name, Parrot_image, food_image,parrot_food, environment, adult) + super().__init__(x, y, name, image_path, food_image, parrot_food, environment, activity, ill, adult) self._starttime = datetime.now() - - - def feed(self): - self.getting_hungry() - if self._feed < 1.5: - return 'False' - else: - return 'True' - - - def getting_hungry(self): + def getting_hungry(self, const): checktime = datetime.now() delta = checktime - self._starttime - minutes_passed = delta.total_seconds() / 60 - self._feed += minutes_passed - self._starttime = checktime \ No newline at end of file + minutes_passed = delta.total_seconds() / (30) + self._starttime = checktime + + if not const.IS_NIGHT and self._feed < 10: + self._feed += minutes_passed + self._feed = min(self._feed, 10) + return self._feed \ No newline at end of file diff --git a/Animals/penguin.py b/Animals/penguin.py index 830f176..33a885c 100644 --- a/Animals/penguin.py +++ b/Animals/penguin.py @@ -2,31 +2,25 @@ from animal import Animal import pygame from datetime import datetime - - class Penguin(Animal): def __init__(self, x, y, adult=False): - Penguin_image = pygame.image.load('images/penguin.png') name = 'penguin' + image_path = self.choose_picture(name) environment = "cold" + activity = 'diurnal' + ill = self.is_ill() food_image = 'images/fish.png' penguin_food = 'fish' - super().__init__(x, y,name, Penguin_image, food_image,penguin_food,environment, adult) + super().__init__(x, y, name, image_path, food_image, penguin_food, environment, activity, ill, adult) self._starttime = datetime.now() - - - def feed(self): - self.getting_hungry() - if self._feed < 2: - return 'False' - else: - return 'True' - - - def getting_hungry(self): + def getting_hungry(self, const): checktime = datetime.now() delta = checktime - self._starttime - minutes_passed = delta.total_seconds() / 60 - self._feed += minutes_passed - self._starttime = checktime \ No newline at end of file + minutes_passed = delta.total_seconds() / (25) + self._starttime = checktime + + if not const.IS_NIGHT and self._feed < 10: + self._feed += minutes_passed + self._feed = min(self._feed, 10) + return self._feed \ No newline at end of file diff --git a/agent.py b/agent.py index 19734b3..176c697 100644 --- a/agent.py +++ b/agent.py @@ -1,6 +1,23 @@ import pygame +import random +from constants import Constants from state_space_search import is_border, is_obstacle +from night import draw_night +from decision_tree import feed_decision +from constants import Constants +from classification import AnimalClassifier +const = Constants() + +classes = [ + "bat", + "bear", + "elephant", + "giraffe", + "owl", + "parrot", + "penguin" +] class Agent: def __init__(self, istate, image_path, grid_size): self.istate = istate @@ -8,8 +25,10 @@ class Agent: self.grid_size = grid_size self.image= pygame.image.load(image_path) self.image = pygame.transform.scale(self.image, (grid_size, grid_size)) + self._dryfood = 0 + self._wetfood = 0 - def draw(self, screen, grid_size): + def draw(self, const): # Obróć obrazek zgodnie z kierunkiem if self.direction == 'E': self.image= pygame.image.load('images/agent4.png') @@ -19,19 +38,21 @@ class Agent: 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)) + self.image = pygame.transform.scale(self.image, (const.GRID_SIZE, const.GRID_SIZE)) + const.screen.blit(self.image, (self.x * self.grid_size, self.y * self.grid_size)) - def handle_event(self, event, max_x, max_y, animals, obstacles): + if const.IS_NIGHT: draw_night(const) + + def handle_event(self, event, max_x, max_y, animals, obstacles,const): if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: - self.move('Go Forward', max_x, max_y, obstacles, animals) + self.move('Go Forward', max_x, max_y, obstacles, animals,const) elif event.key == pygame.K_LEFT: - self.move('Turn Left', max_x, max_y, obstacles, animals) + self.move('Turn Left', max_x, max_y, obstacles, animals,const) elif event.key == pygame.K_RIGHT: - self.move('Turn Right', max_x, max_y, obstacles, animals) + self.move('Turn Right', max_x, max_y, obstacles, animals,const) - def move(self, action, max_x, max_y, obstacles, animals, goal): + def move(self, action, max_x, max_y, obstacles, animals, goal,const): if action == 'Go Forward': new_x, new_y = self.x, self.y if self.direction == 'N': @@ -54,13 +75,54 @@ class Agent: 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) + feed_animal(self, animals, goal,const) + take_food(self) -def feed_animal(self, animals, goal): +def feed_animal(self, animals, goal,const): goal_x, goal_y = goal + neuron = AnimalClassifier('./model/best_model.pth', classes) if self.x == goal_x and self.y == goal_y: for animal in animals: if animal.x == goal_x and animal.y == goal_y: - if animal.feed() == 'True': - animal._feed = 0 - print(animal.name, "fed with", animal.food) \ No newline at end of file + if (animal.activity == 'nocturnal' and const.IS_NIGHT) or (animal.activity == 'diurnal' and not(const.IS_NIGHT)): + activity_time = True + else: + activity_time = False + guests = random.randint(1, 15) + guess = neuron.classify(animal.image_path) + if guess == animal.name: + print(f"I'm sure this is {guess} and i give it {animal.food} as a snack") + animal.draw_snack(const.screen, const.GRID_SIZE, animal.x, animal.y) + else: + print(f"I was wrong, this is not a {guess} but a {animal.name}") + decision = feed_decision(animal.adult, activity_time, animal.ill, const.season, guests, animal._feed, self._dryfood, self._wetfood) + if decision != [1]: + if decision == [2]: + if animal.getting_hungry(const=Constants()) < self._wetfood : + self._wetfood -= animal._feed + animal._feed = 0 + else: + animal._feed -= self._wetfood + self._wetfood = 0 + print(animal.name, "fed with wet food") + else: + if animal.getting_hungry(const=Constants()) < self._dryfood : + self._dryfood -= animal._feed + animal._feed = 0 + else: + animal._feed -= self._dryfood + self._dryfood = 0 + print(animal.name, "fed with dry food") + print("Current wet food level: ", self._wetfood) + print("Current dry food level: ", self._dryfood) + else: print(animal.name, " not fed") + + +def take_food(self): + house_x = 3 + house_y = 1 + if self.x == house_x and self.y == house_y: + if self._dryfood < 1 or self._wetfood < 1: + self._dryfood = 50 + self._wetfood = 50 + print("Agent took food and current food level is", self._dryfood, self._wetfood) diff --git a/classification.py b/classification.py new file mode 100644 index 0000000..5545b7d --- /dev/null +++ b/classification.py @@ -0,0 +1,47 @@ +import torch +import torchvision.transforms as transforms +import PIL.Image as Image + +class AnimalClassifier: + def __init__(self, model_path, classes, image_size=224, mean=None, std=None): + self.classes = classes + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + self.model = torch.load(model_path, map_location=torch.device('cpu')) + self.model = self.model.to(self.device) + self.model = self.model.eval() + self.image_size = image_size + self.mean = mean if mean is not None else [0.5164, 0.5147, 0.4746] + self.std = std if std is not None else [0.2180, 0.2126, 0.2172] + self.image_transforms = transforms.Compose([ + transforms.Resize((self.image_size, self.image_size)), + transforms.ToTensor(), + transforms.Normalize(torch.Tensor(self.mean), torch.Tensor(self.std)) + ]) + + def classify(self, image_path): + image = Image.open(image_path) + + if image.mode == 'RGBA': + image = image.convert('RGB') + + image = self.image_transforms(image).float() + image = image.unsqueeze(0).to(self.device) + + with torch.no_grad(): + output = self.model(image) + + _, predicted = torch.max(output.data, 1) + + return self.classes[predicted.item()] + +classes = [ + "bat", + "bear", + "elephant", + "giraffe", + "owl", + "parrot", + "penguin" +] + + diff --git a/constants.py b/constants.py index 2796685..e3623c0 100644 --- a/constants.py +++ b/constants.py @@ -1,15 +1,26 @@ +import random import pygame +import time class Constants: def __init__(self): self.BLACK = (0, 0, 0) self.RED = (255, 0, 0) - self.GRID_SIZE = 50 + self.GRID_SIZE = 65 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) + self.IS_NIGHT = False + self.TIME_CHANGE = time.time() + 60 + + self.season = random.choice(["spring", "summer", "autumn", "winter"]) + + self.SIZE = 224 + self.mean = [0.5164, 0.5147, 0.4746] + self.std = [0.2180, 0.2126, 0.2172] + def init_pygame(const): pygame.init() const.screen = pygame.display.set_mode(const.WINDOW_SIZE) \ No newline at end of file diff --git a/dane.csv b/dane.csv new file mode 100644 index 0000000..3125c80 --- /dev/null +++ b/dane.csv @@ -0,0 +1,313 @@ +adult,active_time,ill,season,guests,hunger,wet_food,dry_food,decision +True,True,True,spring,12,4.0462,37.63803,5.60819,2 +True,False,False,spring,9,2.89229,34.37597,27.75948,1 +False,True,True,summer,15,2.4002,45.06447,41.50999,3 +True,False,False,summer,5,0.73248,46.1058,33.44281,1 +True,False,False,summer,12,0.62973,49.99647,41.07699,1 +True,False,False,winter,9,7.0889,46.16796,45.904,2 +False,True,False,summer,2,9.07977,22.08011,20.53507,3 +False,False,True,winter,11,3.5635,14.75823,43.46342,2 +False,False,True,winter,9,8.03113,20.6384,30.81177,2 +True,True,True,summer,0,0.01966,28.27203,3.37575,1 +False,False,False,autumn,12,8.27518,5.91931,1.10505,2 +False,False,True,summer,1,5.058,11.01892,48.04589,3 +False,True,False,winter,9,5.64777,17.19678,12.20864,1 +True,True,True,summer,0,6.86046,19.03315,47.13198,3 +True,False,True,winter,13,0.42516,12.62312,19.15853,1 +True,False,True,summer,14,4.46951,33.59537,47.343,1 +True,True,False,autumn,11,6.49386,0.64398,1.0515,1 +False,False,False,winter,10,1.9354,22.80015,26.01165,1 +True,False,False,summer,7,3.55716,1.91094,41.82462,1 +False,True,True,winter,8,9.01072,15.89341,9.10422,2 +False,True,True,spring,4,4.64513,10.39766,7.57955,2 +True,False,False,autumn,2,4.11019,45.85039,30.34183,1 +True,True,True,spring,8,7.09003,6.92577,24.77301,3 +True,True,False,spring,6,4.12955,47.91516,12.84722,1 +True,True,True,spring,10,2.70845,1.0623,42.6941,3 +True,True,True,spring,15,4.34025,6.89381,3.03923,2 +True,False,False,autumn,5,7.24464,31.34759,6.44719,1 +True,True,True,summer,6,3.8924,18.08964,18.77435,1 +False,False,True,spring,13,4.86962,48.62578,6.05301,2 +False,True,False,spring,11,1.60186,31.34926,14.41007,2 +False,True,False,autumn,2,4.19839,19.58116,28.63919,1 +False,True,True,autumn,6,1.50346,25.88282,24.97486,1 +False,True,False,spring,7,2.67431,17.05587,24.7939,1 +True,True,True,spring,7,1.72828,38.17304,24.3685,1 +False,True,True,summer,12,7.55322,26.52797,42.24754,3 +False,True,False,summer,5,8.74993,30.39317,4.5676,2 +False,True,False,summer,5,7.42862,48.73014,5.94891,2 +True,False,False,spring,4,9.3662,12.90556,41.31266,3 +False,True,False,autumn,8,4.72785,0.1623,19.48377,1 +False,False,False,winter,14,6.49349,29.52121,21.87192,1 +True,False,False,summer,14,1.57899,26.90783,33.03528,1 +False,True,False,summer,3,6.21725,3.60564,23.51978,1 +True,True,True,winter,4,4.18565,25.24209,11.02056,1 +False,False,True,autumn,8,6.5479,39.16107,4.75438,2 +False,False,False,summer,13,2.14609,39.97177,13.98651,1 +True,True,False,winter,9,7.43651,10.09353,15.70939,3 +False,False,True,autumn,5,7.85569,40.47073,49.75818,2 +True,False,True,summer,1,9.03492,23.44692,20.0026,3 +False,True,True,autumn,8,2.36724,42.81768,21.34668,2 +False,False,True,summer,15,6.8222,15.2733,15.14799,3 +True,False,True,summer,4,8.63882,41.36166,7.98981,2 +False,True,False,autumn,12,0.48943,8.67832,40.4952,1 +False,False,False,autumn,3,3.0489,14.81219,8.32707,1 +False,True,True,winter,6,0.41014,49.94757,12.61713,1 +True,False,True,winter,12,5.55017,0.98544,10.25287,1 +True,False,False,summer,11,9.92135,6.80759,48.0665,3 +False,True,True,winter,2,7.14394,11.41862,18.29288,2 +False,True,True,winter,10,1.39924,36.41807,42.95548,2 +False,True,False,summer,1,0.95193,46.53851,25.70391,1 +False,True,False,winter,4,1.44658,6.61497,31.58116,1 +False,True,False,autumn,10,7.9404,26.82316,49.5898,2 +True,False,False,spring,5,5.14951,32.36345,11.32114,1 +True,True,False,summer,5,7.55665,49.12578,29.32983,3 +True,False,True,autumn,3,3.80646,11.86722,35.43034,1 +False,False,False,winter,12,3.65822,0.14026,19.18031,1 +True,False,False,spring,8,8.58384,46.33595,11.52974,2 +True,False,False,summer,3,6.34127,22.66891,19.15813,1 +False,True,False,spring,13,7.86448,8.85557,40.03913,3 +True,True,False,spring,13,8.89316,49.89548,21.04525,2 +True,True,False,autumn,9,0.91339,36.35922,16.09576,1 +False,False,False,summer,3,7.36268,28.50462,29.52973,1 +True,True,True,spring,3,6.1319,37.71758,33.50616,1 +False,True,True,spring,0,0.77228,42.89976,19.19004,1 +True,False,True,autumn,3,7.73055,20.87865,37.18248,1 +False,False,False,summer,1,8.30392,34.47046,8.77926,2 +True,True,False,summer,8,2.96562,17.50839,23.22476,1 +True,True,True,winter,4,2.27279,20.58575,32.17293,1 +True,False,True,spring,7,6.14608,34.46015,17.22245,1 +False,False,True,winter,1,8.32044,12.09058,37.28732,3 +False,True,False,spring,14,9.56618,48.49473,46.37651,2 +True,False,True,spring,10,9.33146,47.99213,35.92519,2 +False,True,False,spring,6,0.47396,37.45415,36.87019,1 +True,False,False,summer,12,7.61463,4.36339,36.07375,3 +True,True,True,autumn,3,6.42039,4.90383,43.29857,3 +False,True,False,winter,13,6.89007,43.09184,3.04284,2 +True,False,True,winter,1,6.56604,19.04681,27.58314,2 +True,False,True,spring,3,1.96784,2.18597,34.02966,1 +False,False,False,spring,0,3.76673,1.64674,34.50649,1 +False,False,True,summer,2,0.05382,10.48896,24.03557,1 +True,False,True,spring,14,5.12387,44.44585,8.35502,3 +True,True,False,autumn,10,4.90335,43.27857,27.22901,1 +True,False,False,winter,11,5.89082,28.91495,15.58095,1 +True,False,True,autumn,3,7.39589,21.53402,44.50694,3 +True,False,True,autumn,3,7.39589,21.53402,0.00000,2 +True,False,False,summer,12,5.68671,49.18777,22.53807,3 +False,False,False,winter,0,0.86765,41.28704,33.77284,1 +False,False,True,summer,10,5.97643,36.23669,48.32615,2 +False,True,True,autumn,7,1.76947,38.34692,13.28679,1 +True,True,True,summer,13,8.63622,16.14861,44.91355,3 +True,False,False,winter,11,8.48481,37.52722,47.76888,2 +True,True,True,summer,12,7.65812,4.16785,34.57922,3 +False,False,True,winter,7,8.44897,42.99815,44.66558,2 +False,False,False,winter,7,0.53067,13.47003,18.45329,1 +False,False,False,winter,14,3.24747,9.51144,6.62824,1 +True,True,False,spring,12,5.19071,47.53107,34.68942,2 +True,False,False,summer,9,6.9442,46.79146,13.92798,2 +True,False,False,autumn,1,3.09242,18.02023,11.03004,1 +True,True,True,spring,3,0.19271,1.00203,1.16671,1 +False,True,True,winter,5,9.00758,37.95091,11.54697,2 +True,False,True,spring,9,6.11904,37.42698,4.82627,2 +False,False,True,autumn,9,6.29507,22.99044,15.46992,2 +False,False,False,winter,13,5.4099,11.75134,6.91861,1 +False,False,False,winter,5,9.92035,21.82547,10.2415,2 +False,True,False,winter,10,6.06913,1.46795,12.76663,1 +True,False,True,spring,5,8.1218,37.03643,32.04156,3 +True,False,False,autumn,11,0.48844,39.36689,0.03464,1 +False,True,True,summer,6,1.72816,26.85829,16.53262,1 +False,False,False,spring,5,6.04025,29.55673,18.85232,2 +False,True,True,winter,2,1.75157,0.6601,49.91163,1 +False,True,True,winter,9,6.75125,15.22221,6.72688,2 +False,True,True,autumn,9,6.72535,24.07403,33.94074,2 +False,False,False,winter,14,0.02843,48.49973,15.81701,1 +False,False,True,autumn,15,1.07944,45.94025,4.05257,1 +False,False,True,winter,12,7.26288,15.82501,22.56163,2 +True,True,True,winter,11,8.50892,23.89966,46.14267,3 +True,False,True,autumn,11,8.10923,24.31448,6.70919,2 +True,True,False,summer,11,4.65313,3.44791,3.96313,3 +True,False,True,summer,2,2.56716,10.85536,49.88738,1 +False,False,True,autumn,4,8.19265,5.43942,48.74041,3 +False,True,False,autumn,5,5.6574,9.75738,25.96888,3 +False,True,False,autumn,5,5.6574,9.75738,0.00000,2 +False,True,False,winter,14,4.87066,33.40134,18.98246,2 +True,True,True,winter,6,8.2623,37.47298,33.76759,2 +True,True,True,spring,10,2.20409,13.6178,5.80078,2 +True,False,True,autumn,7,9.06057,37.8724,23.62209,2 +False,False,True,autumn,3,6.69861,37.07336,16.87187,2 +False,False,True,autumn,3,6.69861,0.00000,16.87187,3 +True,False,True,autumn,13,4.96475,46.87852,3.1412,1 +True,False,True,autumn,9,2.65212,19.06994,37.33364,1 +True,True,False,summer,15,3.47148,35.84529,0.00000,1 +False,True,True,summer,8,1.51025,9.44246,19.05913,1 +False,False,True,autumn,6,6.48485,45.61986,15.91179,2 +False,False,False,spring,2,8.98075,39.32941,42.47669,2 +False,True,True,winter,5,8.37177,12.99299,42.31566,3 +True,True,True,autumn,6,3.38746,48.86975,49.62605,1 +False,True,True,summer,7,7.09358,22.83074,38.5172,2 +False,False,True,spring,9,1.00148,11.16064,0.52706,1 +False,False,True,winter,1,6.08476,37.67744,4.49812,2 +False,True,False,spring,5,4.5182,32.48803,33.44274,1 +True,True,True,summer,8,6.11265,30.32015,46.47287,3 +False,True,True,winter,4,8.50937,22.72015,0.00000,2 +True,False,True,summer,4,7.23924,39.09963,42.82872,3 +False,False,True,summer,5,1.28353,7.18667,38.93923,1 +False,True,False,spring,3,4.50329,22.95269,0.41795,1 +True,True,True,summer,1,0.47824,14.79432,24.64273,1 +False,True,False,spring,10,8.43205,19.1333,20.95803,2 +False,True,False,spring,6,9.94659,18.83814,39.26147,2 +False,True,False,spring,3,3.68802,1.58951,26.4255,1 +False,False,True,autumn,8,4.79336,22.56564,4.95207,2 +False,True,True,spring,10,1.63541,0.00000,31.82704,1 +False,True,False,spring,2,1.2274,47.87731,32.98744,1 +True,True,False,winter,11,7.31457,26.08142,16.5835,2 +False,True,True,summer,2,4.90627,19.73976,49.56272,3 +True,True,False,winter,8,3.02707,35.9547,29.52088,1 +True,True,True,summer,7,5.02577,5.37674,16.61368,3 +False,False,True,spring,8,9.58805,8.12549,0.00000,2 +False,True,True,summer,6,2.08786,37.11126,36.15777,3 +True,True,False,spring,7,8.11839,12.2032,8.26737,2 +True,False,True,summer,7,4.08923,20.77025,11.25944,1 +False,False,True,winter,4,4.85557,0.00000,39.4493,2 +False,False,False,summer,14,9.12718,41.84025,49.51895,2 +True,True,True,summer,15,9.4014,34.10345,26.84361,3 +False,True,False,spring,14,8.61728,28.58017,39.3705,2 +False,True,False,winter,8,7.12808,12.04193,43.86622,2 +True,False,True,winter,1,9.50102,43.46168,28.81571,2 +True,True,False,spring,5,1.35366,6.95688,33.37058,1 +False,False,True,autumn,11,7.61014,11.10761,41.58039,2 +False,True,True,summer,2,6.86814,37.72905,14.64706,3 +True,False,False,winter,1,8.12812,22.55081,9.43532,2 +True,True,True,winter,10,4.18282,27.82423,30.42216,1 +False,False,False,summer,7,2.52646,3.74242,10.61286,1 +False,False,True,spring,13,3.15065,19.01632,34.56097,2 +True,True,False,summer,3,0.18108,46.67684,46.76693,1 +True,True,True,spring,0,1.50217,5.27541,16.18378,1 +False,True,True,summer,5,3.71758,11.15496,12.57224,3 +False,True,False,summer,6,9.92613,8.59078,21.32207,3 +True,False,False,winter,11,0.1261,2.42716,17.23296,1 +True,False,True,summer,14,6.90049,10.76539,3.92394,3 +False,True,True,autumn,15,1.76164,35.60051,2.5168,2 +False,False,True,spring,11,2.39225,36.14198,9.13906,3 +True,True,False,summer,2,4.04026,0.00000,12.47216,1 +True,True,False,spring,13,3.32803,7.59913,1.89442,3 +True,False,True,spring,1,5.15927,44.02139,4.03454,1 +True,True,True,autumn,13,5.52565,7.75133,38.62709,3 +True,True,False,spring,3,8.44216,30.01593,12.45777,3 +False,False,True,summer,13,2.88557,5.18905,5.87065,3 +True,True,True,spring,11,2.45261,7.22671,49.68806,3 +True,True,True,winter,4,8.55814,3.29899,32.82852,2 +False,False,True,summer,4,9.85169,47.62867,17.3155,3 +False,False,True,winter,2,5.30151,26.50068,48.79306,2 +False,False,False,autumn,9,7.59806,0.00000,36.92142,2 +False,True,True,autumn,1,9.28424,17.58014,28.42461,2 +True,False,True,summer,14,7.82306,35.29264,46.36975,3 +False,False,True,winter,2,1.10909,46.37088,40.88245,1 +True,True,False,summer,1,7.71442,43.2301,27.42849,3 +False,True,True,summer,6,1.21255,3.7357,4.31858,1 +True,True,True,winter,8,9.53076,12.54774,17.63524,2 +True,True,True,autumn,3,8.47955,19.04656,3.62988,2 +True,False,True,winter,3,2.58264,28.29242,0.00000,1 +True,False,False,autumn,5,6.83145,0.00000,15.88102,1 +True,False,False,summer,10,3.24742,16.50963,26.24036,1 +False,False,False,summer,8,8.66174,49.55046,33.2433,2 +True,False,True,winter,7,1.40722,4.06585,2.57929,1 +False,True,False,winter,12,4.483,2.42211,20.55941,2 +False,False,True,spring,12,2.98512,30.55243,5.53733,3 +False,False,True,autumn,6,0.84086,33.57311,32.42908,1 +False,True,True,winter,12,1.07916,8.27438,7.9284,1 +False,False,True,spring,12,3.17402,46.59657,14.21739,3 +False,True,True,winter,11,7.09559,14.18261,43.41709,2 +False,False,True,autumn,3,0.53006,21.37664,17.14295,1 +False,False,False,autumn,14,4.67143,4.11788,0.04226,1 +True,False,True,winter,12,3.48493,35.24303,0.00000,1 +True,True,True,spring,9,5.1789,0.97673,8.31413,2 +False,False,False,spring,5,1.50319,28.57762,27.80054,1 +True,True,True,autumn,10,9.23444,43.51842,19.90954,2 +False,False,False,autumn,9,3.84582,40.34953,9.01663,1 +True,True,False,winter,5,3.90587,32.97826,0.67046,1 +True,True,True,autumn,2,9.19994,0.00000,34.36662,3 +False,True,True,summer,6,5.614,29.08038,0.00000,2 +True,True,True,autumn,2,2.15339,6.36751,6.45082,1 +True,False,True,spring,1,9.19416,32.05433,8.27667,2 +True,False,True,autumn,0,8.12282,48.68677,8.38304,2 +False,True,True,spring,12,3.26729,29.61584,1.69993,2 +True,False,True,summer,8,1.99886,31.26437,3.51834,1 +False,False,True,summer,7,7.41314,44.88982,34.46453,2 +True,False,True,summer,0,7.24464,8.85289,34.29828,3 +False,True,False,summer,8,2.38628,21.76861,47.20283,3 +True,True,True,autumn,3,7.12112,12.08359,41.06062,3 +True,False,False,winter,5,6.74504,47.09367,1.97357,2 +False,False,False,summer,8,1.23539,35.47945,7.67276,1 +True,False,False,spring,11,7.91742,34.52557,30.96412,3 +False,True,True,winter,14,5.91181,7.53226,16.37669,3 +False,True,True,spring,13,6.07261,47.43572,15.83885,2 +True,True,True,autumn,2,9.22518,31.25996,28.06488,3 +False,True,True,summer,3,8.47609,0.23934,31.25786,3 +False,True,False,autumn,6,0.97126,13.65648,25.59887,1 +True,False,False,spring,14,9.29029,46.83676,12.58912,2 +False,False,False,winter,14,0.14092,4.6673,20.3859,1 +True,False,True,autumn,2,3.52708,37.61372,32.83573,1 +True,True,True,winter,1,4.37134,43.19138,22.04785,1 +True,False,True,summer,9,1.1614,10.9739,42.3009,1 +False,False,False,winter,9,7.27324,29.74731,47.17759,2 +False,True,True,winter,9,3.17153,35.14715,21.37868,2 +False,True,False,autumn,0,2.37863,20.35733,46.96943,1 +False,False,True,autumn,4,0.70656,8.70201,5.26527,1 +True,True,True,winter,1,8.23562,36.01552,25.03969,2 +True,True,False,winter,3,6.65062,6.75622,24.91086,3 +False,False,False,spring,10,2.30179,19.62758,25.57147,1 +True,True,False,autumn,10,6.60812,6.61336,12.39931,3 +False,False,True,summer,3,8.9948,47.39225,18.11157,2 +True,False,True,autumn,5,6.69302,42.62701,13.01677,2 +False,False,False,spring,14,8.53868,33.42545,2.43572,2 +False,True,True,autumn,10,4.46205,10.37542,39.58137,3 +True,True,False,spring,14,5.34262,15.45545,21.48404,3 +True,False,False,winter,9,7.02885,4.88308,27.56619,3 +False,False,False,autumn,13,3.55279,0.17091,5.43831,1 +True,True,True,autumn,1,9.98637,27.57982,15.82173,2 +False,True,True,summer,9,8.25408,13.10493,27.07596,3 +False,False,False,spring,15,1.9089,33.25115,44.57492,1 +True,False,False,autumn,12,6.65534,38.00972,20.31047,2 +False,True,True,autumn,1,0.01592,6.24929,15.51308,1 +False,True,True,winter,13,1.24017,36.88006,16.50894,1 +False,True,True,winter,13,6.1878,15.18876,9.02381,2 +True,True,True,winter,5,5.45157,13.27868,39.39805,2 +True,False,True,spring,5,2.82881,28.62319,24.03077,1 +False,False,True,spring,2,4.8246,41.45269,48.89539,2 +True,False,False,spring,8,9.3343,39.02018,45.01066,3 +True,True,True,autumn,4,1.8456,2.94366,37.44996,1 +False,True,True,summer,14,0.95333,4.57964,26.37633,1 +False,False,True,autumn,13,9.84087,24.03819,41.72097,2 +True,False,False,autumn,9,3.70617,32.70115,1.69105,1 +True,True,True,spring,12,6.77783,6.67976,20.46179,3 +False,False,True,summer,15,7.15829,31.24546,10.37666,3 +False,True,True,summer,1,2.28393,18.13299,34.38756,3 +True,False,True,autumn,7,3.96302,39.84093,47.0172,1 +True,False,False,summer,1,0.65085,20.20581,14.96995,1 +True,False,False,winter,2,9.24331,26.34543,30.5147,2 +True,False,False,summer,3,2.86309,15.56342,1.04324,1 +True,True,True,autumn,8,5.71809,24.41045,48.78273,2 +True,True,True,autumn,8,5.71809,24.41045,48.78273,2 +True,True,True,winter,8,5.71809,0.99999,48.78273,3 +True,True,True,winter,8,5.71809,1.98675,48.79993,3 +True,True,False,winter,8,7.71809,1.02345,38.78273,3 +True,False,False,summer,1,4.03947,33.84073,6.48891,1 +True,False,False,winter,4,2.46471,24.07929,17.77792,1 +False,False,False,winter,9,3.66415,23.68306,24.43865,1 +True,True,True,autumn,8,5.71809,24.41045,48.78273,2 +False,True,True,spring,3,5.3009,34.83862,6.75862,2 +True,False,True,winter,8,6.23275,8.1183,19.6922,3 +False,True,True,autumn,2,4.21016,11.24334,34.98395,3 +True,True,False,autumn,0,2.79424,13.25106,5.69617,1 +True,True,False,winter,15,2.43843,14.61703,49.57393,2 +True,True,True,summer,8,2.28654,20.9895,5.64007,1 +False,False,False,autumn,1,2.5607,26.85209,47.10784,1 +True,True,True,winter,14,1.56638,18.02703,7.05011,1 +False,False,False,winter,13,3.86632,28.9884,20.1928,1 +True,False,False,summer,13,6.37654,34.3833,34.53892,3 +True,False,False,summer,13,6.37654,34.3833,34.53892,3 +True,False,False,spring,11,8.35634,0.00000,34.53892,3 +True,False,True,summer,13,9.37654,34.3833,0.00000,2 +True,False,False,winter,13,7.77754,34.3833,0.00000,2 +True,True,True,summer,5,8.10422,7.6617,23.41017,3 \ No newline at end of file diff --git a/decision_tree.py b/decision_tree.py new file mode 100644 index 0000000..b42ffea --- /dev/null +++ b/decision_tree.py @@ -0,0 +1,48 @@ +import pandas as pd +from sklearn.tree import DecisionTreeClassifier, plot_tree +from sklearn.model_selection import train_test_split +from sklearn.metrics import accuracy_score +import matplotlib.pyplot as plt +headers = ['adult','active_time','ill','season','guests','hunger','wet_food','dry_food'] +# Wczytanie danych +data = pd.read_csv('dane.csv', header=0) +X = data[headers] +Y = data['decision'] +X = pd.get_dummies(data=X, columns=['season']) +clf = DecisionTreeClassifier(max_depth=6) +X1, X2, Y1, Y2 = train_test_split(X, Y, train_size=0.8) +clf = clf.fit(X1, Y1) +pred = clf.predict(X2) +accuracy = accuracy_score(Y2, pred) +print("Dokładność:", accuracy) + + + +#zapisanie drzewa do pliku +plt.figure(figsize=(50,30)) +plot_tree(clf, filled=True, feature_names=X.columns.tolist(), class_names=['nie karmi', 'karmi mokrą karmą', 'karmi suchą karmą']) +plt.savefig('tree.png') +# dane do decyzji +def feed_decision(adult,active_time,ill,season,guests,hunger,dry_food,wet_food): + + X_new = pd.DataFrame({ + 'adult': [adult], + 'active_time': [active_time], + 'ill': [ill], + 'season': [season], + 'guests':[guests], + 'hunger': [hunger], + 'wet_food': [wet_food], + 'dry_food': [dry_food] +}) + X_new = pd.get_dummies(X_new) + missing_columns = set(X.columns) - set(X_new) + for col in missing_columns: + X_new[col] = False + X_new = X_new.reindex(columns=X.columns, fill_value=0) + print("Atrybuty zwierzęcia:", adult,active_time,ill,season,guests,hunger,wet_food,dry_food) + return (clf.predict(X_new)) + + + + diff --git a/draw.py b/draw.py index f032281..df5df3e 100644 --- a/draw.py +++ b/draw.py @@ -11,4 +11,12 @@ 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 + pygame.draw.rect(const.screen, const.BLACK, rect, 1) + +def draw_house(const): + X = 2 + Y = 0 + image_path = 'images/house.png' + image_surface = pygame.image.load(image_path) # Wczytanie obrazka do obiektu Surface + scaled_image = pygame.transform.scale(image_surface, (const.GRID_SIZE * 2, const.GRID_SIZE * 2)) + const.screen.blit(scaled_image, (X * const.GRID_SIZE, Y * const.GRID_SIZE)) \ No newline at end of file diff --git a/enclosure.py b/enclosure.py index 723e243..da237a8 100644 --- a/enclosure.py +++ b/enclosure.py @@ -1,6 +1,5 @@ import pygame - class Enclosure: def __init__(self, x1, y1, x2, y2, gate1, gate2, type, imageH, imageV, imageGate): self.x1 = x1 - 1 @@ -15,6 +14,7 @@ class Enclosure: self.imageH = imageH self.imageV = imageV self.imageGate = imageGate + self.animals = set() def gatebuild(self, screen, grid_size): self.imageGate = pygame.transform.scale(self.imageGate, (grid_size, grid_size)) @@ -56,10 +56,10 @@ def create_enclosures(): 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 + en2 = Enclosure(4, 13, 28, 16, (12, 13), (20, 13), 'cold', fenceH, fenceV, gate) # Dolna klatka + en3 = Enclosure(19, 5, 31, 11, (23, 5), (25, 11), 'hot', fenceH, fenceV, gate) # Prawa klatka + en4 = Enclosure(11, 5, 16, 11, (12, 5), (16, 8), 'cold', fenceH, fenceV, gate) # Środkowa klatka + en5 = Enclosure(13, 0, 29, 3, (16, 3), (27, 3), 'medium', fenceH, fenceV, gate) # Górna klatka Enclosures = [en1, en2, en3, en4, en5] diff --git a/genetics.py b/genetics.py new file mode 100644 index 0000000..22dea52 --- /dev/null +++ b/genetics.py @@ -0,0 +1,148 @@ +from state_space_search import graphsearch, generate_cost_map +import random + +# Parametry algorytmu genetycznego +POPULATION_SIZE = 700 +MUTATION_RATE = 0.01 +NUM_GENERATIONS = 600 + +# Generowanie początkowej populacji +def generate_individual(animals): + return random.sample(animals, len(animals)) + +def generate_population(animals, size): + return [generate_individual(animals) for _ in range(size)] + +# Obliczanie odległości między zwierzetami +def calculate_distance(animal1, animal2): + x1, y1 = animal1 + x2, y2 = animal2 + return abs(x1 - x2) + abs(y1 - y2) # Odległość Manhattana + +def calculate_total_distance(animals): + total_distance = 0 + for i in range(len(animals) - 1): + total_distance += calculate_distance(animals[i], animals[i+1]) + total_distance += calculate_distance(animals[-1], animals[0]) # Zamknięcie cyklu + return total_distance + +# Selekcja rodziców za pomocą metody ruletki +def select_parents(population, num_parents): + fitness_scores = [1 / calculate_total_distance(individual) for individual in population] + total_fitness = sum(fitness_scores) + selection_probs = [fitness / total_fitness for fitness in fitness_scores] + + parents = random.choices(population, weights=selection_probs, k=num_parents) + return parents + +# Krzyżowanie rodziców (OX,Davis) +def crossover(parent1, parent2): + child1 = [None] * len(parent1) + child2 = [None] * len(parent1) + start_index = random.randint(0, len(parent1) - 1) + end_index = random.randint(start_index, len(parent1) - 1) + child1[start_index:end_index+1] = parent1[start_index:end_index+1] + child2[start_index:end_index+1] = parent2[start_index:end_index+1] + + # Uzupełnienie brakujących zwierząt z drugiego rodzica + for i in range(len(parent1)): + if parent2[i] not in child1: + for j in range(len(parent2)): + if child1[j] is None: + child1[j] = parent2[i] + break + + for i in range(len(parent1)): + if parent1[i] not in child2: + for j in range(len(parent1)): + if child2[j] is None: + child2[j] = parent1[i] + break + + return child1, child2 + +# Mutacja: zamiana dwóch losowych zwierząt z prawdopodobieństwem MUTATION_RATE +def mutate(individual): + if random.random() < MUTATION_RATE: + index1, index2 = random.sample(range(len(individual)), 2) + individual[index1], individual[index2] = individual[index2], individual[index1] + +# Algorytm genetyczny +def genetic_algorithm(animals): + population = generate_population(animals, POPULATION_SIZE) + + for generation in range(NUM_GENERATIONS): + # Selekcja rodziców + parents = select_parents(population, POPULATION_SIZE // 2) + + # Krzyżowanie i tworzenie nowej populacji + next_generation = [] + for i in range(0, len(parents), 2): + parent1 = parents[i] + if i + 1 < len(parents): + parent2 = parents[i + 1] + else: + parent2 = parents[0] + child1, child2 = crossover(parent1, parent2) + next_generation.extend([child1, child2]) + + # Mutacja nowej populacji + for individual in next_generation: + mutate(individual) + + # Zastąpienie starej populacji nową + population = next_generation + + # Znalezienie najlepszego osobnika + best_individual = min(population, key=calculate_total_distance) + + return best_individual + +# def calculate_distance(start, goal, max_x, max_y, obstacles, cost_map): +# istate = (start[0], start[1], 'N') # Zakładamy, że zaczynamy od kierunku północnego +# actions, cost = graphsearch(istate, goal, max_x, max_y, obstacles, cost_map) +# return cost + +# def calculate_total_distance(animals, max_x, max_y, obstacles, cost_map): +# total_distance = 0 +# for i in range(len(animals) - 1): +# total_distance += calculate_distance(animals[i], animals[i+1], max_x, max_y, obstacles, cost_map) +# total_distance += calculate_distance(animals[-1], animals[0], max_x, max_y, obstacles, cost_map) # Zamknięcie cyklu +# return total_distance + +# # Selekcja rodziców za pomocą metody ruletki +# def select_parents(population, num_parents, max_x, max_y, obstacles, cost_map): +# fitness_scores = [1 / calculate_total_distance(individual, max_x, max_y, obstacles, cost_map) for individual in population] +# total_fitness = sum(fitness_scores) +# selection_probs = [fitness / total_fitness for fitness in fitness_scores] + +# parents = random.choices(population, weights=selection_probs, k=num_parents) +# return parents + + +# def genetic_algorithm(animals, max_x, max_y, obstacles, cost_map): +# population = generate_population(animals, POPULATION_SIZE) + +# for generation in range(NUM_GENERATIONS): +# # Selekcja rodziców +# parents = select_parents(population, POPULATION_SIZE // 2, max_x, max_y, obstacles, cost_map) + +# # Krzyżowanie i tworzenie nowej populacji +# next_generation = [] +# for i in range(0, len(parents), 2): +# parent1 = parents[i] +# parent2 = parents[i + 1] +# child1, child2 = crossover(parent1, parent2) +# next_generation.extend([child1, child2]) + +# # Mutacja nowej populacji +# for individual in next_generation: +# mutate(individual) + +# # Zastąpienie starej populacji nową +# population = next_generation + +# # Znalezienie najlepszego osobnika +# best_individual = min(population, key=lambda individual: calculate_total_distance(individual, max_x, max_y, obstacles, cost_map)) + +# return best_individual \ No newline at end of file diff --git a/images/almost_empty.png b/images/almost_empty.png new file mode 100644 index 0000000..f6b404d Binary files /dev/null and b/images/almost_empty.png differ diff --git a/images/bat.png b/images/bat.png new file mode 100644 index 0000000..2dd676a Binary files /dev/null and b/images/bat.png differ diff --git a/images/bat2.png b/images/bat2.png new file mode 100644 index 0000000..3a6d087 Binary files /dev/null and b/images/bat2.png differ diff --git a/images/bear2.png b/images/bear2.png new file mode 100644 index 0000000..75d8b71 Binary files /dev/null and b/images/bear2.png differ diff --git a/images/elephant.png b/images/elephant.png index 86c15e1..6a9125c 100644 Binary files a/images/elephant.png and b/images/elephant.png differ diff --git a/images/elephant2.png b/images/elephant2.png new file mode 100644 index 0000000..532d6b6 Binary files /dev/null and b/images/elephant2.png differ diff --git a/images/empty_bowl.png b/images/empty_bowl.png new file mode 100644 index 0000000..975e256 Binary files /dev/null and b/images/empty_bowl.png differ diff --git a/images/full_bowl.png b/images/full_bowl.png new file mode 100644 index 0000000..9f45a3b Binary files /dev/null and b/images/full_bowl.png differ diff --git a/images/giraffe.png b/images/giraffe.png index 8247a89..cbfe5a2 100644 Binary files a/images/giraffe.png and b/images/giraffe.png differ diff --git a/images/giraffe2.png b/images/giraffe2.png new file mode 100644 index 0000000..c1b0b63 Binary files /dev/null and b/images/giraffe2.png differ diff --git a/images/half_bowl.png b/images/half_bowl.png new file mode 100644 index 0000000..992ebab Binary files /dev/null and b/images/half_bowl.png differ diff --git a/images/house.png b/images/house.png new file mode 100644 index 0000000..9195278 Binary files /dev/null and b/images/house.png differ diff --git a/images/ill.png b/images/ill.png new file mode 100644 index 0000000..fb97cbd Binary files /dev/null and b/images/ill.png differ diff --git a/images/owl.png b/images/owl.png new file mode 100644 index 0000000..039dbd0 Binary files /dev/null and b/images/owl.png differ diff --git a/images/owl2.png b/images/owl2.png new file mode 100644 index 0000000..5a836c1 Binary files /dev/null and b/images/owl2.png differ diff --git a/images/parrot2.png b/images/parrot2.png new file mode 100644 index 0000000..99bc134 Binary files /dev/null and b/images/parrot2.png differ diff --git a/images/penguin2.png b/images/penguin2.png new file mode 100644 index 0000000..d0eea2d Binary files /dev/null and b/images/penguin2.png differ diff --git a/images/tłojesień.jpg b/images/tłojesień.jpg new file mode 100644 index 0000000..c9215a5 Binary files /dev/null and b/images/tłojesień.jpg differ diff --git a/images/tłowiosna.jpg b/images/tłowiosna.jpg new file mode 100644 index 0000000..7e17fa2 Binary files /dev/null and b/images/tłowiosna.jpg differ diff --git a/images/tłozima.jpg b/images/tłozima.jpg new file mode 100644 index 0000000..8c49b50 Binary files /dev/null and b/images/tłozima.jpg differ diff --git a/main.py b/main.py index 8246fde..738317f 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ import random import pygame import sys -import sys + sys.path.append('./Animals') from animals import create_animals, draw_Animals from agent import Agent @@ -10,7 +10,10 @@ 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 +from draw import draw_goal, draw_grid, draw_house +from season import draw_background +from night import change_time +from genetics import genetic_algorithm const = Constants() init_pygame(const) @@ -75,42 +78,81 @@ def main(): actions = [] clock = pygame.time.Clock() spawned = False + route = False + + # # Lista zawierająca klatki do odwiedzenia + # enclosures_to_visit = Enclosures.copy() + # current_enclosure_index = -1 # Indeks bieżącej klatki + # actions_to_compare_list = [] # Lista zawierająca ścieżki do porównania + # goals_to_compare_list = list() # Lista zawierająca cele do porównania while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() - agent.handle_event(event, const.GRID_WIDTH, const.GRID_HEIGHT, Animals, obstacles) + agent.handle_event(event, const.GRID_WIDTH, const.GRID_HEIGHT, Animals, obstacles,const) - const.screen.blit(const.background_image, (0, 0)) - draw_grid(const) + change_time(const) + draw_background(const) draw_enclosures(Enclosures, const) draw_gates(Enclosures, const) - + draw_house(const) + 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 + # animal._feed = 0 + animal._feed = random.randint(0, 10) spawned = True + + if not route: + animals = [(animal.x, animal.y) for animal in Animals] + best_route = genetic_algorithm(animals) + route = True draw_Animals(Animals, const) draw_Terrain_Obstacles(Terrain_Obstacles, const) - agent.draw(const.screen, const.GRID_SIZE) + agent.draw(const) pygame.display.flip() clock.tick(10) if actions: action = actions.pop(0) - agent.move(action, const.GRID_WIDTH, const.GRID_HEIGHT, obstacles, Animals, goal) + agent.move(action, const.GRID_WIDTH, const.GRID_HEIGHT, obstacles, Animals, goal,const) 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 agent._dryfood > 1 and agent._wetfood > 1 : + # if not goals_to_compare_list: + # current_enclosure_index = (current_enclosure_index + 1) % len(enclosures_to_visit) + # current_enclosure = enclosures_to_visit[current_enclosure_index] + + # for animal in current_enclosure.animals: + # goal = (animal.x, animal.y) + # goals_to_compare_list.append(goal) + + # actions_to_compare = graphsearch(agent.istate, goal, const.GRID_WIDTH, const.GRID_HEIGHT, obstacles, cost_map) + # actions_to_compare_list.append((actions_to_compare, goal)) + + # chosen_path_and_goal = min(actions_to_compare_list, key=lambda x: len(x[0])) + # goal = chosen_path_and_goal[1] + # draw_goal(const, goal) + + # # Usuń wybrany element z listy + # actions_to_compare_list.remove(chosen_path_and_goal) + # goals_to_compare_list.remove(goal) + goal = best_route.pop(0) + best_route.append(goal) + draw_goal(const, goal) + + actions, cost = graphsearch(agent.istate, goal, const.GRID_WIDTH, const.GRID_HEIGHT, obstacles, cost_map) + + else: + goal = (3,1) + draw_goal(const, goal) + actions, cost = graphsearch(agent.istate, goal, const.GRID_WIDTH, const.GRID_HEIGHT, obstacles, cost_map) if __name__ == "__main__": main() \ No newline at end of file diff --git a/model/best_model.pth b/model/best_model.pth new file mode 100644 index 0000000..c308654 Binary files /dev/null and b/model/best_model.pth differ diff --git a/model/data/train/bat/0CUH9CM2IF4Z.jpg b/model/data/train/bat/0CUH9CM2IF4Z.jpg new file mode 100644 index 0000000..966ac67 Binary files /dev/null and b/model/data/train/bat/0CUH9CM2IF4Z.jpg differ diff --git a/model/data/train/bear/0BVFXHLSFYEM.jpg b/model/data/train/bear/0BVFXHLSFYEM.jpg new file mode 100644 index 0000000..dc3d9be Binary files /dev/null and b/model/data/train/bear/0BVFXHLSFYEM.jpg differ diff --git a/model/data/train/elephant/Elephant_0.jpg b/model/data/train/elephant/Elephant_0.jpg new file mode 100644 index 0000000..cc40bd2 Binary files /dev/null and b/model/data/train/elephant/Elephant_0.jpg differ diff --git a/model/data/train/giraffe/Giraffe_0.jpg b/model/data/train/giraffe/Giraffe_0.jpg new file mode 100644 index 0000000..c2a0024 Binary files /dev/null and b/model/data/train/giraffe/Giraffe_0.jpg differ diff --git a/model/data/train/owl/0AL42OEB782C.jpg b/model/data/train/owl/0AL42OEB782C.jpg new file mode 100644 index 0000000..42b4a28 Binary files /dev/null and b/model/data/train/owl/0AL42OEB782C.jpg differ diff --git a/model/data/train/parrot/Parrot_Download_train_0.jpg b/model/data/train/parrot/Parrot_Download_train_0.jpg new file mode 100644 index 0000000..7f0dd8d Binary files /dev/null and b/model/data/train/parrot/Parrot_Download_train_0.jpg differ diff --git a/model/data/train/penguin/Penguin_Download_1_train_0.jpg b/model/data/train/penguin/Penguin_Download_1_train_0.jpg new file mode 100644 index 0000000..857e00d Binary files /dev/null and b/model/data/train/penguin/Penguin_Download_1_train_0.jpg differ diff --git a/model/data/val/bat/0BN7W0OQC1M1.jpg b/model/data/val/bat/0BN7W0OQC1M1.jpg new file mode 100644 index 0000000..7b3c883 Binary files /dev/null and b/model/data/val/bat/0BN7W0OQC1M1.jpg differ diff --git a/model/data/val/bear/0I31CLWNAVJV.jpg b/model/data/val/bear/0I31CLWNAVJV.jpg new file mode 100644 index 0000000..a1fb299 Binary files /dev/null and b/model/data/val/bear/0I31CLWNAVJV.jpg differ diff --git a/model/data/val/elephant/Elephant_10.jpg b/model/data/val/elephant/Elephant_10.jpg new file mode 100644 index 0000000..b02232b Binary files /dev/null and b/model/data/val/elephant/Elephant_10.jpg differ diff --git a/model/data/val/giraffe/Giraffe_2.jpg b/model/data/val/giraffe/Giraffe_2.jpg new file mode 100644 index 0000000..0a05324 Binary files /dev/null and b/model/data/val/giraffe/Giraffe_2.jpg differ diff --git a/model/data/val/owl/0AD8FZAIF9BZ.jpg b/model/data/val/owl/0AD8FZAIF9BZ.jpg new file mode 100644 index 0000000..4b10f95 Binary files /dev/null and b/model/data/val/owl/0AD8FZAIF9BZ.jpg differ diff --git a/model/data/val/parrot/Parrot_Download_train_9.jpg b/model/data/val/parrot/Parrot_Download_train_9.jpg new file mode 100644 index 0000000..42fdbb3 Binary files /dev/null and b/model/data/val/parrot/Parrot_Download_train_9.jpg differ diff --git a/model/data/val/penguin/Penguin_Download_1_train_4.jpg b/model/data/val/penguin/Penguin_Download_1_train_4.jpg new file mode 100644 index 0000000..2001ddd Binary files /dev/null and b/model/data/val/penguin/Penguin_Download_1_train_4.jpg differ diff --git a/model/model.py b/model/model.py new file mode 100644 index 0000000..b36904a --- /dev/null +++ b/model/model.py @@ -0,0 +1,129 @@ +import torch +import torch.nn as nn +import torch.optim as optim +import torchvision.datasets +from torchvision import datasets, transforms, models +from torch.utils.data import DataLoader + + +def set_device(): + if torch.cuda.is_available(): + device = 'cuda' + else: + device = 'cpu' + return torch.device(device) + + +train_dataset_path = './data/train' +test_dataset_path = './data/val' +number_of_classes = 7 + +SIZE = 224 +mean = [0.5164, 0.5147, 0.4746] +std = [0.2180, 0.2126, 0.2172] + +train_transforms = transforms.Compose([ + transforms.Resize((SIZE, SIZE)), + transforms.RandomHorizontalFlip(), + transforms.RandomRotation(10), + transforms.ToTensor(), + transforms.Normalize(torch.Tensor(mean), torch.Tensor(std)) +]) + +test_transforms = transforms.Compose([ + transforms.Resize((SIZE, SIZE)), + transforms.ToTensor(), + transforms.Normalize(torch.Tensor(mean), torch.Tensor(std)) +]) + +train_dataset = torchvision.datasets.ImageFolder(root=train_dataset_path, transform=train_transforms) +test_dataset = torchvision.datasets.ImageFolder(root=test_dataset_path, transform=test_transforms) + +train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True) +test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False) + +resnet18_model = models.resnet18(weights=None) +num_ftrs = resnet18_model.fc.in_features +resnet18_model.fc = nn.Linear(num_ftrs, number_of_classes) +device = set_device() +resnet18_model = resnet18_model.to(device) +loss_fn = nn.CrossEntropyLoss() + +optimizer = optim.SGD(resnet18_model.parameters(), lr=0.001, momentum=0.9, weight_decay=0.003) + + +def save_checkpoint(model, epoch, optimizer, best_acc): + state = { + 'epoch': epoch + 1, + 'model': model.state_dict(), + 'best accuracy': best_acc, + 'optimizer': optimizer.state_dict() + } + torch.save(state, 'model_best_checkpoint.pth.tar') +def train_nn(model, train_loader, test_loader, criterion, optimizer, n_epochs): + device = set_device() + best_acc = 0 + + for epoch in range(n_epochs): + print("Epoch number %d " % (epoch + 1)) + model.train() + running_loss = 0.0 + running_correct = 0.0 + total = 0 + + for data in train_loader: + images, labels = data + images = images.to(device) + labels = labels.to(device) + total += labels.size(0) + + optimizer.zero_grad() + outputs = model(images) + _, predicted = torch.max(outputs.data, 1) + loss = criterion(outputs, labels) + loss.backward() + optimizer.step() + + running_loss += loss.item() + running_correct += (labels == predicted).sum().item() + + epoch_loss = running_loss/len(train_loader) + epoch_acc = 100 * running_correct / total + print(f"Training dataset. Got {running_correct} out of {total} images correctly ({epoch_acc}). Epoch loss: {epoch_loss}") + + test_data_acc = evaluate_model_on_test_set(model, test_loader) + + if test_data_acc > best_acc: + best_acc = test_data_acc + save_checkpoint(model, epoch, optimizer, best_acc) + + print("Finished") + return model +def evaluate_model_on_test_set(model, test_loader): + model.eval() + predicted_correctly_on_epoch = 0 + total = 0 + device = set_device() + + with torch.no_grad(): + for data in test_loader: + images, labels = data + images = images.to(device) + labels = labels.to(device) + total += labels.size(0) + + outputs = model(images) + _, predicted = torch.max(outputs.data, 1) + + predicted_correctly_on_epoch += (predicted == labels).sum().item() + + epoch_acc = 100 * predicted_correctly_on_epoch / total + print(f"Testing dataset. Got {predicted_correctly_on_epoch} out of {total} images correctly ({epoch_acc})") + return epoch_acc + + +train_nn(resnet18_model, train_loader, test_loader, loss_fn, optimizer, n_epochs=30) + +checkpoint = torch.load('model_best_checkpoint.pth.tar') +resnet18_model.load_state_dict(checkpoint['model']) +torch.save(resnet18_model, 'best_model.pth') \ No newline at end of file diff --git a/model/model_best_checkpoint.pth.tar b/model/model_best_checkpoint.pth.tar new file mode 100644 index 0000000..e00de45 Binary files /dev/null and b/model/model_best_checkpoint.pth.tar differ diff --git a/night.py b/night.py new file mode 100644 index 0000000..cc831fd --- /dev/null +++ b/night.py @@ -0,0 +1,19 @@ +import time +import pygame + +DAY_LENGTH = 90 # Długość dnia w sekundach + +def draw_night(const): + overlay = pygame.Surface(const.WINDOW_SIZE) + overlay.fill((0, 0, 0)) + overlay.set_alpha(128) # Ustawienie przezroczystości (0 - całkowicie przeźroczyste, 255 - nieprzeźroczyste) + const.screen.blit(overlay, (0, 0)) + +def change_time(const): + current_time = time.time() + + # Sprawdzamy, czy nadszedł czas zmiany pory dnia + if current_time >= const.TIME_CHANGE: + # Zmieniamy porę dnia + const.IS_NIGHT = not const.IS_NIGHT # Jeśli było dzień, teraz będzie noc, i odwrotnie + const.TIME_CHANGE = current_time + DAY_LENGTH \ No newline at end of file diff --git a/season.py b/season.py new file mode 100644 index 0000000..4268ef7 --- /dev/null +++ b/season.py @@ -0,0 +1,11 @@ +import pygame + +def draw_background(const): + season_images = { + "spring": "images/tłowiosna.jpg", + "summer": "images/tło.jpg", + "autumn": "images/tłojesień.jpg", + "winter": "images/tłozima.jpg" + } + background_image = pygame.transform.scale(pygame.image.load(season_images[const.season]), const.WINDOW_SIZE) + const.screen.blit(background_image, (0, 0)) \ No newline at end of file diff --git a/spawner.py b/spawner.py index 29f89eb..04b0849 100644 --- a/spawner.py +++ b/spawner.py @@ -9,6 +9,8 @@ class Spawner: # Wyrażenie listowe filtrujące tylko te wybiegi, które pasują do środowiska zwierzęcia enclosure = random.choice(self.enclosures) + enclosure.animals.add(self.entity) # Przydzielenie zwierzęcia do wybiegu + while True: if self.entity.adult: self.entity.x = random.randint(enclosure.x1+1, enclosure.x2-2) @@ -21,7 +23,7 @@ class Spawner: 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)} + blocked1 = blocked1 | {(2,0),(3,0),(2,1),(3,1),(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) diff --git a/state_space_search.py b/state_space_search.py index 7aae41e..0f1ea91 100644 --- a/state_space_search.py +++ b/state_space_search.py @@ -40,7 +40,7 @@ def graphsearch(istate, goal, max_x, max_y, obstacles, cost_map): state, _, _ = node if goaltest(state, goal): - return build_action_sequence(node) + return build_action_sequence(node), current_cost(node, cost_map) explored.add(state) @@ -61,7 +61,7 @@ def graphsearch(istate, goal, max_x, max_y, obstacles, cost_map): else: break - return False + return False, float('inf') def is_state_in_queue(state, queue): for _, (s, _, _) in queue.queue: @@ -111,9 +111,9 @@ def generate_cost_map(Animals, Terrain_Obstacles, cost_map={}): 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 + 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 @@ -124,4 +124,5 @@ def generate_cost_map(Animals, Terrain_Obstacles, cost_map={}): else: cost_map[(terrain_obstacle.x , terrain_obstacle.y )] = bush_cost - return cost_map \ No newline at end of file + return cost_map + diff --git a/tree.png b/tree.png new file mode 100644 index 0000000..e87cc57 Binary files /dev/null and b/tree.png differ