From ef7aa77470677bc1462f62f0019a8b54cba9d77b Mon Sep 17 00:00:00 2001 From: Polevara Veronika Date: Thu, 18 May 2023 23:18:07 +0200 Subject: [PATCH] changes --- .gitignore | 12 +- .idea/.gitignore | 6 +- .idea/Machine_learning_2023.iml | 26 +- .../inspectionProfiles/profiles_settings.xml | 10 +- .idea/misc.xml | 6 +- .idea/modules.xml | 14 +- .idea/vcs.xml | 10 +- .vs/ProjectSettings.json | 3 + .vs/slnx.sqlite | Bin 0 -> 90112 bytes AI_brain/go_any_direction.py | 160 +++---- AI_brain/rotate_and_go_astar.py | 224 +++++----- AI_brain/rotate_and_go_bfs.py | 166 ++++---- Project discription.txt | 120 +++--- README.md | 116 ++--- config.ini | 6 +- decisionTree/data.csv | 220 +++++++++- decisionTree/decision_tree_model.pkl | Bin 1833 -> 2249 bytes decisionTree/evaluate.py | 16 +- decisionTree/prepare.py | 40 +- domain/commands/command.py | 6 +- domain/commands/random_cat_move_command.py | 140 +++---- domain/commands/vacuum_move_command.py | 66 +-- domain/entities/cat.py | 34 +- domain/entities/docking_station.py | 18 +- domain/entities/earring.py | 16 +- domain/entities/entity.py | 10 +- domain/entities/garbage.py | 22 +- domain/entities/plant.py | 20 +- domain/entities/vacuum.py | 44 +- domain/world.py | 114 ++--- main.py | 338 +++++++-------- requirements.txt | 10 +- view/renderer.py | 396 +++++++++--------- 33 files changed, 1285 insertions(+), 1104 deletions(-) create mode 100644 .vs/ProjectSettings.json create mode 100644 .vs/slnx.sqlite diff --git a/.gitignore b/.gitignore index 7efaafe..4932e41 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -/venv -.DS_Store -/.vscode -__pycache__ - -#PyCharm +/venv +.DS_Store +/.vscode +__pycache__ + +#PyCharm .idea/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore index 26d3352..eaf91e2 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -1,3 +1,3 @@ -# Default ignored files -/shelf/ -/workspace.xml +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Machine_learning_2023.iml b/.idea/Machine_learning_2023.iml index f6175b4..128a20f 100644 --- a/.idea/Machine_learning_2023.iml +++ b/.idea/Machine_learning_2023.iml @@ -1,14 +1,14 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml index 105ce2d..20fc29e 100644 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -1,6 +1,6 @@ - - - + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index c69c90c..f7eed7c 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 5e0b360..ab04967 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..9661ac7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..866f1e1 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..a4e6d3ff0dd092740afc6c0852446628feefb9bd GIT binary patch literal 90112 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 bool: - return ( - state.x == self.goal_state.x +import heapq +from domain.world import World + + +class State: + def __init__(self, x, y, direction=(1, 0), entity=None): + self.x = x + self.y = y + self.direction = direction + + + def __hash__(self): + return hash((self.x, self.y)) + + def __eq__(self, other): + return ( + self.x == other.x + and self.y == other.y + and self.direction == other.direction + ) + + def heuristic(self, goal_state): + return abs(self.x - goal_state.x) + abs(self.y - goal_state.y) + + +class Node: + def __init__(self, state: State, g_score: int, goal_state: State): + self.state = state + self.g_score = g_score + self.f_score = g_score + state.heuristic(goal_state) + self.parent = None + self.action = None + + def __lt__(self, other): + return self.f_score < other.f_score + + +def action_sequence(node: Node): + actions = [] + while node.parent: + actions.append(node.action) + node = node.parent + actions.reverse() + return actions + + +class RotateAndGoAStar: + def __init__(self, world: World, start_state: State, goal_state: State): + self.world = world + self.start_state = start_state + self.goal_state = goal_state + self.fringe = [] + self.enqueued_states = set() + self.explored = set() + self.actions = [] + + def get_g_score(self, state): + return self.world.get_cost(state.x, state.y) + + def search(self): + heapq.heappush( + self.fringe, Node(self.start_state, 0, self.goal_state) + ) + + while self.fringe: + elem = heapq.heappop(self.fringe) + if self.is_goal(elem.state): + self.actions = action_sequence(elem) + return True + self.explored.add(elem.state) + + for action, state in self.successors(elem.state): + if state in self.explored: + continue + + new_g_score = new_g_score = elem.g_score + self.world.get_cost(state.x, state.y) + if state not in self.enqueued_states: + next_node = Node(state, new_g_score, self.goal_state) + next_node.action = action + next_node.parent = elem + heapq.heappush(self.fringe, next_node) + self.enqueued_states.add(state) + elif new_g_score < self.get_g_score(state): + for node in self.fringe: + if node.state == state: + node.g_score = new_g_score + node.f_score = ( + new_g_score + node.state.heuristic(self.goal_state) + ) + node.parent = elem + node.action = action + heapq.heapify(self.fringe) + break + + return False + + def successors(self, state: State): + new_successors = [ + ("RR", State(state.x, state.y, (-state.direction[1], state.direction[0]))), + ("RL", State(state.x, state.y, (state.direction[1], -state.direction[0]))), + ] + next_x = state.x + state.direction[0] + next_y = state.y + state.direction[1] + if self.world.accepted_move(next_x, next_y): + new_successors.append( + ("GO", State(next_x, next_y, state.direction)) + ) + return new_successors + + def is_goal(self, state: State) -> bool: + return ( + state.x == self.goal_state.x and state.y == self.goal_state.y ) \ No newline at end of file diff --git a/AI_brain/rotate_and_go_bfs.py b/AI_brain/rotate_and_go_bfs.py index 966650d..fecc976 100644 --- a/AI_brain/rotate_and_go_bfs.py +++ b/AI_brain/rotate_and_go_bfs.py @@ -1,83 +1,83 @@ -import queue - -from domain.world import World - - -class State: - def __init__(self, x, y, direction=(1, 0)): - self.x = x - self.y = y - self.direction = direction - - def __hash__(self): - return hash((self.x, self.y)) - - def __eq__(self, other): - return (self.x == other.x and self.y == other.y - and self.direction == other.direction) - - -class Node: - def __init__(self, state: State): - self.state = state - self.parent = None - self.action = None - - -def action_sequence(node: Node): - actions = [] - while node.parent: - actions.append(node.action) - node = node.parent - actions.reverse() - return actions - - -class RotateAndGoBFS: - def __init__(self, world: World, start_state: State, goal_state: State): - self.world = world - self.start_state = start_state - self.goal_state = goal_state - self.fringe = queue.Queue() - self.enqueued_states = set() - self.explored = set() - self.actions = [] - - def search(self): - self.fringe.put(Node(self.start_state)) - - while self.fringe: - elem = self.fringe.get() - if self.is_goal(elem.state): - self.actions = action_sequence(elem) - return True - self.explored.add(elem.state) - - for (action, state) in self.successors(elem.state): - if state in self.explored or state in self.enqueued_states: - continue - next_node = Node(state) - next_node.action = action - next_node.parent = elem - self.fringe.put(next_node) - self.enqueued_states.add(state) - - return False - - def successors(self, state: State): - new_successors = [ - # rotate right - ("RR", State(state.x, state.y, (-state.direction[1], state.direction[0]))), - # rotate left - ("RL", State(state.x, state.y, (state.direction[1], -state.direction[0]))), - ] - if self.world.accepted_move(state.x + state.direction[0], state.y + state.direction[1]): - new_successors.append( - ("GO", State(state.x + state.direction[0], state.y + state.direction[1], state.direction))) - return new_successors - - def is_goal(self, state: State) -> bool: - return ( - state.x == self.goal_state.x - and state.y == self.goal_state.y - ) +import queue + +from domain.world import World + + +class State: + def __init__(self, x, y, direction=(1, 0)): + self.x = x + self.y = y + self.direction = direction + + def __hash__(self): + return hash((self.x, self.y)) + + def __eq__(self, other): + return (self.x == other.x and self.y == other.y + and self.direction == other.direction) + + +class Node: + def __init__(self, state: State): + self.state = state + self.parent = None + self.action = None + + +def action_sequence(node: Node): + actions = [] + while node.parent: + actions.append(node.action) + node = node.parent + actions.reverse() + return actions + + +class RotateAndGoBFS: + def __init__(self, world: World, start_state: State, goal_state: State): + self.world = world + self.start_state = start_state + self.goal_state = goal_state + self.fringe = queue.Queue() + self.enqueued_states = set() + self.explored = set() + self.actions = [] + + def search(self): + self.fringe.put(Node(self.start_state)) + + while self.fringe: + elem = self.fringe.get() + if self.is_goal(elem.state): + self.actions = action_sequence(elem) + return True + self.explored.add(elem.state) + + for (action, state) in self.successors(elem.state): + if state in self.explored or state in self.enqueued_states: + continue + next_node = Node(state) + next_node.action = action + next_node.parent = elem + self.fringe.put(next_node) + self.enqueued_states.add(state) + + return False + + def successors(self, state: State): + new_successors = [ + # rotate right + ("RR", State(state.x, state.y, (-state.direction[1], state.direction[0]))), + # rotate left + ("RL", State(state.x, state.y, (state.direction[1], -state.direction[0]))), + ] + if self.world.accepted_move(state.x + state.direction[0], state.y + state.direction[1]): + new_successors.append( + ("GO", State(state.x + state.direction[0], state.y + state.direction[1], state.direction))) + return new_successors + + def is_goal(self, state: State) -> bool: + return ( + state.x == self.goal_state.x + and state.y == self.goal_state.y + ) diff --git a/Project discription.txt b/Project discription.txt index 80f22b8..1dfb036 100644 --- a/Project discription.txt +++ b/Project discription.txt @@ -1,60 +1,60 @@ -****** - -Dokumentacja projektu "Automatyczny robot sprzątający" - -Wprowadzenie: -Projekt "Automatyczny robot sprzątający" jest projektem bazującym się na symulacji pracy robota sprzątającego w pomieszczeniu za pomocą sztucznej inteligencji. Robot ma za zadanie wyznaczać miejsca do sprzątania oraz uniknąć przeszkód oraz reagować na zdarzenia losowe. Projekt jest napisany w języku Python. - -Instrukcja obsługi: - - Uruchomienie projektu: - Aby uruchomić projekt należy uruchomić plik "main.py" za pomocą interpretera Python. Projektu wyświetli się w konsoli.Po uruchomieniu projektu na ekranie wyświetli się plansza o wymiarach NxN (default: 10x10). Robot "Cleaner" (oznaczony jako "R" na planszy) startuje z pozycji (0,0). użytkownik ma za zadanie wprowadzić pozycje do sprzątania, które są oznaczone na planszy jako litery "D". Możliwe pozycje to liczby od 0 do N-1. - - Użytkownik wprowadza pozycje za pomocą terminala. Wprowadzenie koordynat odbywa się w następujący sposób: - Najpierw wprowadzamy numer wiersza, a następnie numer kolumny, oddzielając je spacją. - Przykładowo, jeśli chcemy wskazać pozycję (4,5) wpisujemy: "4 5". - Po wskazaniu pozycji do sprzątania, użytkownik musi uniknąć przeszkód, które są oznaczone na planszy jako znak "X". Robot nie może przejść przez przeszkody. Jeśli użytkownik wskazuje pozycję przeszkody, projektu zwróci błąd i będzie wymagała podania nowych współrzędnych. - - Przebieg projektu: - Robot, zgodnie z zbudowaną mapą, musi obliczyć najkrótszą ścieżkę do sprzątania wszystkich pozycji oraz uniknąć przeszkód. Podczas sprzątania mogą wystąpić przypadkowe zdarzenia, na które robot będzie reagował. W tym celu, z pomocą sieci neuronowych, robot analizuje zdjęcie zdarzenia, aby wybrać najlepsze rozwiązania. - - Zakończenie projektu: - Program kończy swoje działanie w momencie, gdy robot posprząta wszystkie przez użytkownika wybrane pola do sprzątania. Na zakończenie programu zostanie wyświetlona liczba wykonanych ruchów przez robota oraz podjęte decyzje w przypadku zaistnienia zdarzeń. - -Możliwe modyfikacje: - Projekt zostanie napisany z myślą o możliwości łatwej modyfikacji. Można zmienić wymiary planszy, dodać lub usunąć przeszkody oraz ilość przypadkowych zdarzeń i pozycji do sprzątania. Wszystkie te zmiany można wprowadzić w pliku "config.py". - -Podsumowanie: - Projekt "Automatyczny robot sprzątający" to prosty, ale edukacyjny projekt programistyczny. Użytkownik ma za zadanie wskazanie pozycji, które robot powinien posprzątać, a także koordynat przeszkody. Natomiast zadaniem robota, który został zbudowany przy użyciu sztucznej inteligencji, jest unikanie przeszkód, podejmowanie decyzji w przypadku wystąpienia przypadkowych zdarzeń oraz sprzątanie wyznaczonych punktów. Projekt został napisany w języku Python z wykorzystaniem sztucznej inteligencji. Analiza zdjęć jest oparta na sieciach neuronowych. - -****** - -Documentation of the "Automatic Cleaning Robot" project - -Introduction: - The "Automatic Cleaning Robot" project is based on simulating the work of a cleaning robot in a room using artificial intelligence. The robot is tasked with determining the areas to be cleaned, avoiding obstacles, and reacting to random events. The project is written in Python. - -User Guide: - Starting the project: - To start the project, you need to run the "main.py" file using a Python interpreter. The project will be displayed on the console. Once the project is launched, a 10x10 board will be displayed on the screen. The "Cleaner" robot (marked as "R" on the board) starts from the position (0,0). The user needs to enter the positions to be cleaned, which are marked as the letter "D" on the board. The possible positions are numbers from 0 to 9. - - The user enters the positions through the terminal. The entry of coordinates is done as follows: - First, we enter the row number, and then the column number, separating them with a space. - For example, if we want to indicate the position (4,5), we enter "4 5". - After indicating the positions to be cleaned, the user must avoid obstacles, which are marked on the board as the "X" symbol. The robot cannot pass through obstacles. If the user points to an obstacle position, the project will return an error and require new coordinates. - - Project process: - Based on the built map, the robot must calculate the shortest path to clean all positions and avoid obstacles. Random events may occur during cleaning, to which the robot will react. To do this, with the help of neural networks, the robot analyzes the image of the event to choose the best solutions. - - Project conclusion: - The program is ending when the robot cleans all the fields selected by the user. At the end of the program, the number of robot moves performed and the decisions made in case of events will be displayed. - -Possible modifications: - The "Automatic cleaning robot" project has been designed with the possibility of easy modifications in mind. Users can change the dimensions of the board, add or remove obstacles, and adjust the number of random events and cleaning positions. All these changes can be made in the "config.py" file. - -Summary: - The "Automatic cleaning robot" project is a simple yet educational programming project. Users are tasked with specifying the positions that the robot should clean, as well as the coordinates of obstacles. The robot, built using artificial intelligence, is responsible for avoiding obstacles, making decisions in case of random events, and cleaning the designated points. The project was written in Python with the use of artificial intelligence. The analysis of images is based on neural networks. - -****** -****** - +****** + +Dokumentacja projektu "Automatyczny robot sprzątający" + +Wprowadzenie: +Projekt "Automatyczny robot sprzątający" jest projektem bazującym się na symulacji pracy robota sprzątającego w pomieszczeniu za pomocą sztucznej inteligencji. Robot ma za zadanie wyznaczać miejsca do sprzątania oraz uniknąć przeszkód oraz reagować na zdarzenia losowe. Projekt jest napisany w języku Python. + +Instrukcja obsługi: + + Uruchomienie projektu: + Aby uruchomić projekt należy uruchomić plik "main.py" za pomocą interpretera Python. Projektu wyświetli się w konsoli.Po uruchomieniu projektu na ekranie wyświetli się plansza o wymiarach NxN (default: 10x10). Robot "Cleaner" (oznaczony jako "R" na planszy) startuje z pozycji (0,0). użytkownik ma za zadanie wprowadzić pozycje do sprzątania, które są oznaczone na planszy jako litery "D". Możliwe pozycje to liczby od 0 do N-1. + + Użytkownik wprowadza pozycje za pomocą terminala. Wprowadzenie koordynat odbywa się w następujący sposób: + Najpierw wprowadzamy numer wiersza, a następnie numer kolumny, oddzielając je spacją. + Przykładowo, jeśli chcemy wskazać pozycję (4,5) wpisujemy: "4 5". + Po wskazaniu pozycji do sprzątania, użytkownik musi uniknąć przeszkód, które są oznaczone na planszy jako znak "X". Robot nie może przejść przez przeszkody. Jeśli użytkownik wskazuje pozycję przeszkody, projektu zwróci błąd i będzie wymagała podania nowych współrzędnych. + + Przebieg projektu: + Robot, zgodnie z zbudowaną mapą, musi obliczyć najkrótszą ścieżkę do sprzątania wszystkich pozycji oraz uniknąć przeszkód. Podczas sprzątania mogą wystąpić przypadkowe zdarzenia, na które robot będzie reagował. W tym celu, z pomocą sieci neuronowych, robot analizuje zdjęcie zdarzenia, aby wybrać najlepsze rozwiązania. + + Zakończenie projektu: + Program kończy swoje działanie w momencie, gdy robot posprząta wszystkie przez użytkownika wybrane pola do sprzątania. Na zakończenie programu zostanie wyświetlona liczba wykonanych ruchów przez robota oraz podjęte decyzje w przypadku zaistnienia zdarzeń. + +Możliwe modyfikacje: + Projekt zostanie napisany z myślą o możliwości łatwej modyfikacji. Można zmienić wymiary planszy, dodać lub usunąć przeszkody oraz ilość przypadkowych zdarzeń i pozycji do sprzątania. Wszystkie te zmiany można wprowadzić w pliku "config.py". + +Podsumowanie: + Projekt "Automatyczny robot sprzątający" to prosty, ale edukacyjny projekt programistyczny. Użytkownik ma za zadanie wskazanie pozycji, które robot powinien posprzątać, a także koordynat przeszkody. Natomiast zadaniem robota, który został zbudowany przy użyciu sztucznej inteligencji, jest unikanie przeszkód, podejmowanie decyzji w przypadku wystąpienia przypadkowych zdarzeń oraz sprzątanie wyznaczonych punktów. Projekt został napisany w języku Python z wykorzystaniem sztucznej inteligencji. Analiza zdjęć jest oparta na sieciach neuronowych. + +****** + +Documentation of the "Automatic Cleaning Robot" project + +Introduction: + The "Automatic Cleaning Robot" project is based on simulating the work of a cleaning robot in a room using artificial intelligence. The robot is tasked with determining the areas to be cleaned, avoiding obstacles, and reacting to random events. The project is written in Python. + +User Guide: + Starting the project: + To start the project, you need to run the "main.py" file using a Python interpreter. The project will be displayed on the console. Once the project is launched, a 10x10 board will be displayed on the screen. The "Cleaner" robot (marked as "R" on the board) starts from the position (0,0). The user needs to enter the positions to be cleaned, which are marked as the letter "D" on the board. The possible positions are numbers from 0 to 9. + + The user enters the positions through the terminal. The entry of coordinates is done as follows: + First, we enter the row number, and then the column number, separating them with a space. + For example, if we want to indicate the position (4,5), we enter "4 5". + After indicating the positions to be cleaned, the user must avoid obstacles, which are marked on the board as the "X" symbol. The robot cannot pass through obstacles. If the user points to an obstacle position, the project will return an error and require new coordinates. + + Project process: + Based on the built map, the robot must calculate the shortest path to clean all positions and avoid obstacles. Random events may occur during cleaning, to which the robot will react. To do this, with the help of neural networks, the robot analyzes the image of the event to choose the best solutions. + + Project conclusion: + The program is ending when the robot cleans all the fields selected by the user. At the end of the program, the number of robot moves performed and the decisions made in case of events will be displayed. + +Possible modifications: + The "Automatic cleaning robot" project has been designed with the possibility of easy modifications in mind. Users can change the dimensions of the board, add or remove obstacles, and adjust the number of random events and cleaning positions. All these changes can be made in the "config.py" file. + +Summary: + The "Automatic cleaning robot" project is a simple yet educational programming project. Users are tasked with specifying the positions that the robot should clean, as well as the coordinates of obstacles. The robot, built using artificial intelligence, is responsible for avoiding obstacles, making decisions in case of random events, and cleaning the designated points. The project was written in Python with the use of artificial intelligence. The analysis of images is based on neural networks. + +****** +****** + diff --git a/README.md b/README.md index e86e82d..29d0404 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,58 @@ -****** - -Dokumentacja projektu "Automatyczny robot sprzątający" - -Wprowadzenie: -Projekt "Automatyczny robot sprzątający" jest projektem bazującym się na symulacji pracy robota sprzątającego w pomieszczeniu za pomocą sztucznej intelegencji. Robot ma za zadanie wyznaczać miejsca do sprzątania oraz uniknąć przeszkód oraz reagować na zdarzenia randomowe. Projekt jest napisany w języku Python. - -Instrukcja obsługi: - - Uruchomienie projektu: - Aby uruchomić projekt należy uruchomić plik "main.py" za pomocą interpretera Python. Projektu wyświetli się w konsoli.Po uruchomieniu projektu na ekranie wyświetli się plansza o wymiarach 10x10. Robot "Cleaner" (oznaczony jako "R" na planszy) startuje z pozycji (0,0). użytkownik ma za zadanie wprowadzić pozycje do sprzątania, które są oznaczone na planszy jako litery "D". Możliwe pozycje to liczby od 0 do 9. - - Użytkownik wprowadza pozycje za pomocą terminala. Wprowadzenie koordynat odbywa się w następujący sposób: - Najpierw wprowadzamy numer wiersza, a następnie numer kolumny, oddzielając je spacją. - Przykładowo, jeśli chcemy wskazać pozycję (4,5) wpisujemy: "4 5". - Po wskazaniu pozycji do sprzątania, użytkownik musi uniknąć przeszkód, które są oznaczone na planszy jako znak "X". Robot nie może przejść przez przeszkody. Jeśli użytkownik wskazuje pozycję przeszkody, projektu zwróci błąd i będzie wymagała podania nowych koordynatów. - - Przebieg projektu: - Robot, zgodnie z zbudowaną mapą, musi obliczyć najkrótszą ścieżkę do sprzątania wszystkich pozycji oraz uniknąć przeszkód. Podczas sprzątania mogą wystąpić przypadkowe zdarzenia, na które robot będzie reagował. W tym celu, z pomocą sieci neuronowych, robot analizuje zdjęcie zdarzenia, aby wybrać najlepsze rozwiązania. - - Zakończenie projektu: - Program kończy swoje działanie w momencie, gdy robot posprząta wszystkie przez użytkownika wybrane pola do sprzątania. Na zakończenie programu zostanie wyświetlona liczba wykonanych ruchów przez robota oraz podjęte decyzje w przypadku zaistnienia zdarzeń. - -Możliwe modyfikacje: - Projekt zostanie napisany z myślą o możliwości łatwej modyfikacji. Można zmienić wymiary planszy, dodać lub usunąć przeszkody oraz ilość przypadkowych zdarzeń i pozycji do sprzątania. Wszystkie te zmiany można wprowadzić w pliku "config.py". - -Podsumowanie: - Projekt "Automatyczny robot sprzątający" to prosty, ale edukacyjny projekt programistyczny. Użytkownik ma za zadanie wskazanie pozycji, które robot powinien posprzątać, a także koordynat przeszkody. Natomiast zadaniem robota, który został zbudowany przy użyciu sztucznej inteligencji, jest unikanie przeszkód, podejmowanie decyzji w przypadku wystąpienia przypadkowych zdarzeń oraz sprzątanie wyznaczonych punktów. Projekt został napisany w języku Python z wykorzystaniem sztucznej inteligencji.Analiza zdięć jest oparta na sieciach neuronowych. - -****** - -Documentation of the "Automatic Cleaning Robot" project - -Introduction: - The "Automatic Cleaning Robot" project is based on simulating the work of a cleaning robot in a room using artificial intelligence. The robot is tasked with determining the areas to be cleaned, avoiding obstacles, and reacting to random events. The project is written in Python. - -User Guide: - Starting the project: - To start the project, you need to run the "main.py" file using a Python interpreter. The project will be displayed on the console. Once the project is launched, a 10x10 board will be displayed on the screen. The "Cleaner" robot (marked as "R" on the board) starts from the position (0,0). The user needs to enter the positions to be cleaned, which are marked as the letter "D" on the board. The possible positions are numbers from 0 to 9. - - The user enters the positions through the terminal. The entry of coordinates is done as follows: - First, we enter the row number, and then the column number, separating them with a space. - For example, if we want to indicate the position (4,5), we enter "4 5". - After indicating the positions to be cleaned, the user must avoid obstacles, which are marked on the board as the "X" symbol. The robot cannot pass through obstacles. If the user points to an obstacle position, the project will return an error and require new coordinates. - - Project process: - Based on the built map, the robot must calculate the shortest path to clean all positions and avoid obstacles. Random events may occur during cleaning, to which the robot will react. To do this, with the help of neural networks, the robot analyzes the image of the event to choose the best solutions. - - Project conclusion: - The program is ending when the robot cleans all the fields selected by the user. At the end of the program, the number of robot moves performed and the decisions made in case of events will be displayed. - -Possible modifications: - The "Automatic cleaning robot" project has been designed with the possibility of easy modifications in mind. Users can change the dimensions of the board, add or remove obstacles, and adjust the number of random events and cleaning positions. All these changes can be made in the "config.py" file. - -Summary: - The "Automatic cleaning robot" project is a simple yet educational programming project. Users are tasked with specifying the positions that the robot should clean, as well as the coordinates of obstacles. The robot, built using artificial intelligence, is responsible for avoiding obstacles, making decisions in case of random events, and cleaning the designated points. The project was written in Python with the use of artificial intelligence. The analysis of images is based on neural networks. - -****** +****** + +Dokumentacja projektu "Automatyczny robot sprzątający" + +Wprowadzenie: +Projekt "Automatyczny robot sprzątający" jest projektem bazującym się na symulacji pracy robota sprzątającego w pomieszczeniu za pomocą sztucznej intelegencji. Robot ma za zadanie wyznaczać miejsca do sprzątania oraz uniknąć przeszkód oraz reagować na zdarzenia randomowe. Projekt jest napisany w języku Python. + +Instrukcja obsługi: + + Uruchomienie projektu: + Aby uruchomić projekt należy uruchomić plik "main.py" za pomocą interpretera Python. Projektu wyświetli się w konsoli.Po uruchomieniu projektu na ekranie wyświetli się plansza o wymiarach 10x10. Robot "Cleaner" (oznaczony jako "R" na planszy) startuje z pozycji (0,0). użytkownik ma za zadanie wprowadzić pozycje do sprzątania, które są oznaczone na planszy jako litery "D". Możliwe pozycje to liczby od 0 do 9. + + Użytkownik wprowadza pozycje za pomocą terminala. Wprowadzenie koordynat odbywa się w następujący sposób: + Najpierw wprowadzamy numer wiersza, a następnie numer kolumny, oddzielając je spacją. + Przykładowo, jeśli chcemy wskazać pozycję (4,5) wpisujemy: "4 5". + Po wskazaniu pozycji do sprzątania, użytkownik musi uniknąć przeszkód, które są oznaczone na planszy jako znak "X". Robot nie może przejść przez przeszkody. Jeśli użytkownik wskazuje pozycję przeszkody, projektu zwróci błąd i będzie wymagała podania nowych koordynatów. + + Przebieg projektu: + Robot, zgodnie z zbudowaną mapą, musi obliczyć najkrótszą ścieżkę do sprzątania wszystkich pozycji oraz uniknąć przeszkód. Podczas sprzątania mogą wystąpić przypadkowe zdarzenia, na które robot będzie reagował. W tym celu, z pomocą sieci neuronowych, robot analizuje zdjęcie zdarzenia, aby wybrać najlepsze rozwiązania. + + Zakończenie projektu: + Program kończy swoje działanie w momencie, gdy robot posprząta wszystkie przez użytkownika wybrane pola do sprzątania. Na zakończenie programu zostanie wyświetlona liczba wykonanych ruchów przez robota oraz podjęte decyzje w przypadku zaistnienia zdarzeń. + +Możliwe modyfikacje: + Projekt zostanie napisany z myślą o możliwości łatwej modyfikacji. Można zmienić wymiary planszy, dodać lub usunąć przeszkody oraz ilość przypadkowych zdarzeń i pozycji do sprzątania. Wszystkie te zmiany można wprowadzić w pliku "config.py". + +Podsumowanie: + Projekt "Automatyczny robot sprzątający" to prosty, ale edukacyjny projekt programistyczny. Użytkownik ma za zadanie wskazanie pozycji, które robot powinien posprzątać, a także koordynat przeszkody. Natomiast zadaniem robota, który został zbudowany przy użyciu sztucznej inteligencji, jest unikanie przeszkód, podejmowanie decyzji w przypadku wystąpienia przypadkowych zdarzeń oraz sprzątanie wyznaczonych punktów. Projekt został napisany w języku Python z wykorzystaniem sztucznej inteligencji.Analiza zdięć jest oparta na sieciach neuronowych. + +****** + +Documentation of the "Automatic Cleaning Robot" project + +Introduction: + The "Automatic Cleaning Robot" project is based on simulating the work of a cleaning robot in a room using artificial intelligence. The robot is tasked with determining the areas to be cleaned, avoiding obstacles, and reacting to random events. The project is written in Python. + +User Guide: + Starting the project: + To start the project, you need to run the "main.py" file using a Python interpreter. The project will be displayed on the console. Once the project is launched, a 10x10 board will be displayed on the screen. The "Cleaner" robot (marked as "R" on the board) starts from the position (0,0). The user needs to enter the positions to be cleaned, which are marked as the letter "D" on the board. The possible positions are numbers from 0 to 9. + + The user enters the positions through the terminal. The entry of coordinates is done as follows: + First, we enter the row number, and then the column number, separating them with a space. + For example, if we want to indicate the position (4,5), we enter "4 5". + After indicating the positions to be cleaned, the user must avoid obstacles, which are marked on the board as the "X" symbol. The robot cannot pass through obstacles. If the user points to an obstacle position, the project will return an error and require new coordinates. + + Project process: + Based on the built map, the robot must calculate the shortest path to clean all positions and avoid obstacles. Random events may occur during cleaning, to which the robot will react. To do this, with the help of neural networks, the robot analyzes the image of the event to choose the best solutions. + + Project conclusion: + The program is ending when the robot cleans all the fields selected by the user. At the end of the program, the number of robot moves performed and the decisions made in case of events will be displayed. + +Possible modifications: + The "Automatic cleaning robot" project has been designed with the possibility of easy modifications in mind. Users can change the dimensions of the board, add or remove obstacles, and adjust the number of random events and cleaning positions. All these changes can be made in the "config.py" file. + +Summary: + The "Automatic cleaning robot" project is a simple yet educational programming project. Users are tasked with specifying the positions that the robot should clean, as well as the coordinates of obstacles. The robot, built using artificial intelligence, is responsible for avoiding obstacles, making decisions in case of random events, and cleaning the designated points. The project was written in Python with the use of artificial intelligence. The analysis of images is based on neural networks. + +****** diff --git a/config.ini b/config.ini index 1b451b6..87d6bac 100644 --- a/config.ini +++ b/config.ini @@ -1,4 +1,4 @@ -[APP] -cat = False -movement = robot +[APP] +cat = False +movement = robot #accept: human, robot \ No newline at end of file diff --git a/decisionTree/data.csv b/decisionTree/data.csv index 0563613..2a19a56 100644 --- a/decisionTree/data.csv +++ b/decisionTree/data.csv @@ -1,22 +1,200 @@ 1-2-3-4-5;1-green 2-yellow 3-orange 4-black 5-while 6-blue;in dB 0-100;0-24;0/1;in cm;in C;0/1 -Size;Color;Sound;Time;Smell;Height;Temperature;ToRemove -1;2;0;16;1;10;25;1 -2;1;0;12;0;50;24;0 -2;3;30;13;1;38;38;0 -1;4;0;7;1;5;27;1 -1;2;0;16;1;10;25;1 -2;1;0;12;0;50;24;0 -2;3;30;13;1;38;38;0 -1;4;0;7;1;5;27;1 -1;2;0;16;1;10;25;1 -2;1;0;12;0;50;24;0 -2;3;30;13;1;38;38;0 -1;4;0;7;1;5;27;1 -1;2;0;16;1;10;25;1 -2;1;0;12;0;50;24;0 -2;3;30;13;1;38;38;0 -1;4;0;7;1;5;27;1 -1;2;0;16;1;10;25;1 -2;1;0;12;0;50;24;0 -2;3;30;13;1;38;38;0 -1;4;0;7;1;5;27;1 \ No newline at end of file +Size;Color;Sound;Sharp;Smell;Length;Temperature;Weight;ToRemove; +1;1;0;0;0;2;22;0;1; +1;2;0;0;0;2;22;0;1; +1;3;0;0;0;2;22;0;1; +1;4;0;0;0;2;22;0;1; +1;5;0;0;0;2;22;0;1; +1;6;0;0;0;2;22;0;1; +1;7;0;0;0;2;22;0;1; +1;8;0;0;0;2;22;0;1; +1;9;0;0;0;2;22;0;1; +1;2;0;0;1;3;25;0;1; +1;2;0;0;1;4;25;0;1; +1;2;0;0;1;5;25;0;1; +2;2;0;0;1;3;25;0;1; +2;2;0;0;1;4;25;0;1; +2;2;0;0;1;5;25;0;1; +2;2;0;0;1;6;25;0;1; +3;2;0;0;1;3;25;0;1; +1;7;0;0;1;3;25;2;1; +1;6;0;0;1;4;25;2;1; +1;6;0;0;1;5;25;2;1; +1;6;0;0;1;2;25;2;1; +2;6;0;0;1;2;25;3;1; +2;6;0;0;1;3;25;3;1; +2;6;0;0;1;4;25;3;1; +2;6;0;0;1;5;25;3;1; +3;6;0;0;1;2;25;4;1; +2;1;0;0;0;20;24;1;0; +2;2;0;0;0;20;24;1;0; +2;3;0;0;0;20;24;1;0; +2;4;0;0;0;20;24;1;0; +2;5;0;0;0;20;24;1;0; +2;6;0;0;0;20;24;1;0; +2;7;0;0;0;20;24;1;0; +2;8;0;0;0;20;24;1;0; +2;9;0;0;0;20;24;1;0; +1;1;0;1;0;1;20;0;0; +1;2;0;1;0;1;20;0;0; +1;3;0;1;0;1;20;0;0; +1;4;0;1;0;1;20;0;0; +1;5;0;1;0;1;20;0;0; +1;6;0;1;0;1;20;0;0; +1;7;0;1;0;1;20;0;0; +1;8;0;1;0;1;20;0;0; +2;4;0;0;0;14;22;1;0; +1;2;0;0;1;6;24;1;1; +2;2;0;0;1;6;24;1;1; +1;2;0;0;1;5;24;1;1; +3;1;4;0;0;18;24;2;0; +3;2;4;0;0;18;24;2;0; +3;3;4;0;0;18;24;2;0; +3;4;4;0;0;18;24;2;0; +3;5;4;0;0;18;24;2;0; +3;6;4;0;0;18;24;2;0; +3;7;4;0;0;18;24;2;0; +3;8;4;0;0;18;24;2;0; +3;9;4;0;0;18;24;2;0; +4;3;20;0;1;32;37;5;0; +4;4;20;0;1;32;37;5;0; +4;5;20;0;1;32;37;5;0; +4;6;20;0;1;32;37;5;0; +5;3;25;0;1;40;37;6;0; +5;4;25;0;1;40;37;6;0; +5;5;25;0;1;40;37;6;0; +5;6;25;0;1;40;37;6;0; +1;5;0;0;0;20;22;2;0; +1;5;0;0;0;30;22;2;0; +1;5;0;0;0;40;22;2;0; +1;5;0;0;0;50;22;2;0; +1;4;0;0;0;20;22;2;0; +1;4;0;0;0;30;22;2;0; +1;4;0;0;0;40;22;2;0; +1;4;0;0;0;50;22;2;0; +2;5;0;0;0;20;22;2;0; +2;5;0;0;0;30;22;2;0; +2;5;0;0;0;40;22;2;0; +2;4;0;0;0;20;22;2;0; +2;4;0;0;0;30;22;2;0; +2;4;0;0;0;40;22;2;0; +1;5;0;0;1;2;24;0;1; +1;3;0;0;0;13;23;0;1; +1;4;0;0;0;13;23;0;1; +1;5;0;0;0;13;23;0;1; +1;6;0;0;0;13;23;0;1; +1;3;0;0;0;14;23;0;1; +1;4;0;0;0;14;23;0;1; +1;5;0;0;0;14;23;0;1; +1;6;0;0;0;14;23;0;1; +1;3;0;0;0;15;23;0;1; +1;4;0;0;0;15;23;0;1; +1;5;0;0;0;15;23;0;1; +1;6;0;0;0;15;23;0;1; +1;1;0;1;0;3;22;1;1; +1;2;0;1;0;3;22;1;1; +1;3;0;1;0;3;22;1;1; +1;4;0;1;0;3;22;1;1; +1;5;0;1;0;3;22;1;1; +1;6;0;1;0;3;22;1;1; +1;7;0;1;0;3;22;1;1; +1;8;0;1;0;3;22;1;1; +1;9;0;1;0;3;22;1;1; +2;1;0;1;0;7;22;1;0; +2;2;0;1;0;7;22;1;0; +2;3;0;1;0;7;22;1;0; +2;4;0;1;0;7;22;1;0; +2;5;0;1;0;7;22;1;0; +2;6;0;1;0;7;22;1;0; +2;7;0;1;0;7;22;1;0; +2;8;0;1;0;7;22;1;0; +2;9;0;1;0;7;22;1;0; +3;3;10;0;1;24;36;3;0; +3;4;10;0;1;24;36;3;0; +3;5;10;0;1;24;36;3;0; +3;6;10;0;1;24;36;3;0; +1;1;0;0;0;2;20;1;0; +1;2;0;0;0;2;20;1;0; +1;3;0;0;0;2;20;1;0; +1;4;0;0;0;2;20;1;0; +1;5;0;0;0;2;20;1;0; +1;6;0;0;0;2;20;1;0; +1;7;0;0;0;2;20;1;0; +1;8;0;0;0;2;20;1;0; +1;9;0;0;0;2;20;1;0; +2;1;0;0;1;2;24;0;1; +2;2;0;0;1;2;24;0;1; +2;3;0;0;1;2;24;0;1; +2;7;0;0;1;2;24;0;1; +2;8;0;0;1;2;24;0;1; +2;9;0;0;1;2;24;0;1; +1;5;0;0;0;2;22;0;1; +1;5;0;0;0;3;22;0;1; +1;5;0;0;0;4;22;0;1; +1;6;0;0;0;2;22;0;1; +1;6;0;0;0;3;22;0;1; +1;6;0;0;0;4;22;0;1; +2;5;0;0;0;2;22;0;1; +2;5;0;0;0;3;22;0;1; +2;5;0;0;0;4;22;0;1; +2;6;0;0;0;2;22;0;1; +2;6;0;0;0;3;22;0;1; +2;6;0;0;0;4;22;0;1; +2;1;0;0;0;2;20;0;0; +2;2;0;0;0;2;20;0;0; +2;3;0;0;0;2;20;0;0; +2;4;0;0;0;2;20;0;0; +2;5;0;0;0;2;20;0;0; +2;6;0;0;0;2;20;0;0; +2;7;0;0;0;2;20;0;0; +2;8;0;0;0;2;20;0;0; +2;9;0;0;0;2;20;0;0; +2;1;0;0;1;3;22;0;1; +2;2;0;0;1;3;22;0;1; +2;3;0;0;1;3;22;0;1; +2;4;0;0;1;3;22;0;1; +2;5;0;0;1;3;22;0;1; +2;6;0;0;1;3;22;0;1; +2;7;0;0;1;3;22;0;1; +2;8;0;0;1;3;22;0;1; +2;9;0;0;1;3;22;0;1; +3;1;0;0;0;16;23;3;0; +3;2;0;0;0;16;23;3;0; +3;3;0;0;0;16;23;3;0; +3;4;0;0;0;16;23;3;0; +3;5;0;0;0;16;23;3;0; +3;6;0;0;0;16;23;3;0; +3;7;0;0;0;16;23;3;0; +3;8;0;0;0;16;23;3;0; +3;9;0;0;0;16;23;3;0; +1;5;0;0;0;2;23;0;1; +1;5;0;0;0;3;23;0;1; +1;5;0;0;0;4;23;0;1; +1;5;0;0;0;5;23;0;1; +1;5;0;0;0;6;23;0;1; +2;5;0;0;0;3;23;0;1; +2;5;0;0;0;4;23;0;1; +2;5;0;0;0;5;23;0;1; +2;5;0;0;0;6;23;0;1; +2;5;0;0;0;2;23;0;1; +2;5;0;0;1;4;26;1;1; +3;5;0;0;1;4;26;2;1; +1;7;0;1;0;1;22;0;1; +1;7;0;1;0;1;22;0;1; +4;1;0;0;1;30;21;4;0; +4;1;0;0;1;25;21;4;0; +1;6;0;0;1;1;22;0;1; +1;6;0;0;1;1;22;1;1; +4;3;30;0;1;50;36;4;0; +5;3;30;0;1;50;36;4;0; +1;1;0;0;0;9;22;0;0; +1;8;0;0;0;9;22;0;0; +3;1;0;0;0;25;22;2;0; +3;2;0;0;0;25;22;2;0; +3;3;0;0;0;25;22;2;0; +3;4;0;0;0;25;22;2;0; +3;5;0;0;0;25;22;2;0; +3;6;0;0;0;25;22;2;0; +3;7;0;0;0;25;22;2;0; +3;8;0;0;0;25;22;2;0; +3;9;0;0;0;25;22;2;0; \ No newline at end of file diff --git a/decisionTree/decision_tree_model.pkl b/decisionTree/decision_tree_model.pkl index 58f7d191c36195fcb7ea97128729c5391634db68..20bfa43d45f0d5a7063ccf3eb0062beee452ce67 100644 GIT binary patch delta 744 zcmZ3O{txtk-_QB0yHN-B{e=dzcjC8iZ|!vwJhR{oRg2T^avVxGqg>~2*@z< z<^a-x8Ag*^SPk=Hy%m7G5TK|AkPgj=^)_gmQtEBt&FC#qG9@WPqa#DpTc9+FcKn)h6Y~;2ule{tDx~AvIr6)&&&XH O+jllyR>LW!NqPVz365j{ delta 387 zcmX>pxRP(fYDPx($!i#&0?A2CS>Y@U3=AQexv7Ps5v)LFaBgZ&PN7%?8<6dhnwg$a zQYaq54N{YuTaa3mSW;S)S}2iPQYe|EH?;&P4gx)VdGTqfV7cP>%)Iz1-t3bTnG+eg zCm&@l1KMN5q7EceSWH!X7$G{m8QZ4>O{txtk-_QB*u#~VpOPA%oL`z(GR2#D@?I8k zM&`*^S$bHMdYCdN*Rm?`Gqg>~2*`-?<^a-x8BvpqSPe}Qy%m7G5TK|AkPgjA^fqXl zQtEBt&FC#qG9@WPqa#DpTc9+F>HmMItqe?)8`(r9EgY`3ANzG7;=Vl}#5GV-XR`MI1K+~Dpr)0=yC}b#RBu@UpE~~^K;Q-O20Ht9j!1xlA Or*r7C8ciup(gOhB-C?o- diff --git a/decisionTree/evaluate.py b/decisionTree/evaluate.py index 5c27f94..ffcca85 100644 --- a/decisionTree/evaluate.py +++ b/decisionTree/evaluate.py @@ -1,9 +1,9 @@ -import joblib - -def evaluate(data): - # Load the model - clf = joblib.load('decisionTree/decision_tree_model.pkl') - - # Make a prediction - prediction = clf.predict(data) +import joblib + +def evaluate(data): + # Load the model + clf = joblib.load('decisionTree/decision_tree_model.pkl') + + # Make a prediction + prediction = clf.predict(data) return prediction \ No newline at end of file diff --git a/decisionTree/prepare.py b/decisionTree/prepare.py index 93968c9..a750c28 100644 --- a/decisionTree/prepare.py +++ b/decisionTree/prepare.py @@ -1,21 +1,21 @@ -import pandas as pd -from sklearn.tree import DecisionTreeClassifier -from sklearn.model_selection import train_test_split -from sklearn import metrics -import joblib - -pima = pd.read_csv("data.csv", header=1, delimiter=';') - -feature_cols = ['Size', 'Color', 'Sound', 'Time','Smell', 'Height','Temperature'] -X = pima[feature_cols] -y = pima.ToRemove - -X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) -clf = DecisionTreeClassifier() -clf = clf.fit(X_train,y_train) - -joblib.dump(clf, 'decision_tree_model.pkl') - -y_pred = clf.predict(X_test) - +import pandas as pd +from sklearn.tree import DecisionTreeClassifier +from sklearn.model_selection import train_test_split +from sklearn import metrics +import joblib + +pima = pd.read_csv("data.csv", header=1, delimiter=';') + +feature_cols = ['Size', 'Color', 'Sound', 'Sharp','Smell', 'Length','Temperature', 'Weight'] +X = pima[feature_cols] +y = pima.ToRemove + +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) +clf = DecisionTreeClassifier() +clf = clf.fit(X_train,y_train) + +joblib.dump(clf, 'decision_tree_model.pkl') + +y_pred = clf.predict(X_test) + print("Accuracy:",metrics.accuracy_score(y_test, y_pred)) \ No newline at end of file diff --git a/domain/commands/command.py b/domain/commands/command.py index 377a0f3..50c9034 100644 --- a/domain/commands/command.py +++ b/domain/commands/command.py @@ -1,3 +1,3 @@ -class Command: - def run(self): - raise NotImplementedError() +class Command: + def run(self): + raise NotImplementedError() diff --git a/domain/commands/random_cat_move_command.py b/domain/commands/random_cat_move_command.py index 3dbe005..475d35f 100644 --- a/domain/commands/random_cat_move_command.py +++ b/domain/commands/random_cat_move_command.py @@ -1,70 +1,70 @@ -from random import randint -from typing import Tuple - -import pygame - -from domain.commands.command import Command -from domain.entities.cat import Cat -from domain.world import World - - -class RandomCatMoveCommand(Command): - def __init__(self, world: World, cat: Cat) -> None: - super().__init__() - self.world = world - self.cat = cat - - def run(self): - move_vector = (0, 0) - now = pygame.time.get_ticks() - # region cat random movement - cat = self.world.cat - if now - cat.last_tick >= cat.cooldown: - if not cat.busy: - while True: - cat.direction = randint(0, 3) - if not ( - (cat.direction == 0 and cat.y == 0) - or (cat.direction == 1 and cat.x == self.world.width - 1) - or (cat.direction == 2 and cat.y == self.world.height - 1) - or (cat.direction == 3 and cat.x == 0) - ): - break - - if cat.direction == 0: # up - if cat.busy: - move_vector = (0, -1) - cat.busy = not cat.busy - if cat.direction == 1: # right - if cat.busy: - move_vector = (1, 0) - cat.busy = not cat.busy - if cat.direction == 2: # down - if cat.busy: - move_vector = (0, 1) - cat.busy = not cat.busy - if cat.direction == 3: # left - if cat.busy: - move_vector = (-1, 0) - cat.busy = not cat.busy - cat.last_tick = pygame.time.get_ticks() - - if move_vector == (0, 0): - return - - end_x = cat.x + move_vector[0] - end_y = cat.y + move_vector[1] - - if ( - end_x > self.world.width - 1 - or end_y > self.world.height - 1 - or end_x < 0 - or end_y < 0 - ): - return - - self.world.obstacles[cat.x][cat.y].remove(cat) - cat.x = end_x - cat.y = end_y - self.world.obstacles[end_x][end_y].append(cat) - # endregion cat random movement +from random import randint +from typing import Tuple + +import pygame + +from domain.commands.command import Command +from domain.entities.cat import Cat +from domain.world import World + + +class RandomCatMoveCommand(Command): + def __init__(self, world: World, cat: Cat) -> None: + super().__init__() + self.world = world + self.cat = cat + + def run(self): + move_vector = (0, 0) + now = pygame.time.get_ticks() + # region cat random movement + cat = self.world.cat + if now - cat.last_tick >= cat.cooldown: + if not cat.busy: + while True: + cat.direction = randint(0, 3) + if not ( + (cat.direction == 0 and cat.y == 0) + or (cat.direction == 1 and cat.x == self.world.width - 1) + or (cat.direction == 2 and cat.y == self.world.height - 1) + or (cat.direction == 3 and cat.x == 0) + ): + break + + if cat.direction == 0: # up + if cat.busy: + move_vector = (0, -1) + cat.busy = not cat.busy + if cat.direction == 1: # right + if cat.busy: + move_vector = (1, 0) + cat.busy = not cat.busy + if cat.direction == 2: # down + if cat.busy: + move_vector = (0, 1) + cat.busy = not cat.busy + if cat.direction == 3: # left + if cat.busy: + move_vector = (-1, 0) + cat.busy = not cat.busy + cat.last_tick = pygame.time.get_ticks() + + if move_vector == (0, 0): + return + + end_x = cat.x + move_vector[0] + end_y = cat.y + move_vector[1] + + if ( + end_x > self.world.width - 1 + or end_y > self.world.height - 1 + or end_x < 0 + or end_y < 0 + ): + return + + self.world.obstacles[cat.x][cat.y].remove(cat) + cat.x = end_x + cat.y = end_y + self.world.obstacles[end_x][end_y].append(cat) + # endregion cat random movement diff --git a/domain/commands/vacuum_move_command.py b/domain/commands/vacuum_move_command.py index 4707ca1..a10632b 100644 --- a/domain/commands/vacuum_move_command.py +++ b/domain/commands/vacuum_move_command.py @@ -1,33 +1,33 @@ -from typing import Tuple - -from domain.commands.command import Command -from domain.entities.vacuum import Vacuum -from domain.world import World - - -class VacuumMoveCommand(Command): - def __init__( - self, world: World, vacuum: Vacuum, move_vector: Tuple[int, int] - ) -> None: - super().__init__() - self.world = world - self.vacuum = vacuum - self.dx = move_vector[0] - self.dy = move_vector[1] - - def run(self): - end_x = self.vacuum.x + self.dx - end_y = self.vacuum.y + self.dy - if not self.world.accepted_move(end_x, end_y): - return - - if self.world.is_garbage_at(end_x, end_y): - if self.vacuum.get_container_filling() < 100: - self.vacuum.increase_container_filling() - self.world.dust[end_x][end_y].pop() - - if self.world.is_docking_station_at(end_x, end_y): - self.vacuum.dump_trash() - - self.vacuum.x = end_x - self.vacuum.y = end_y +from typing import Tuple + +from domain.commands.command import Command +from domain.entities.vacuum import Vacuum +from domain.world import World + + +class VacuumMoveCommand(Command): + def __init__( + self, world: World, vacuum: Vacuum, move_vector: Tuple[int, int] + ) -> None: + super().__init__() + self.world = world + self.vacuum = vacuum + self.dx = move_vector[0] + self.dy = move_vector[1] + + def run(self): + end_x = self.vacuum.x + self.dx + end_y = self.vacuum.y + self.dy + if not self.world.accepted_move(end_x, end_y): + return + + if self.world.is_garbage_at(end_x, end_y): + if self.vacuum.get_container_filling() < 100: + self.vacuum.increase_container_filling() + self.world.dust[end_x][end_y].pop() + + if self.world.is_docking_station_at(end_x, end_y): + self.vacuum.dump_trash() + + self.vacuum.x = end_x + self.vacuum.y = end_y diff --git a/domain/entities/cat.py b/domain/entities/cat.py index 14e44b3..fb7901a 100644 --- a/domain/entities/cat.py +++ b/domain/entities/cat.py @@ -1,17 +1,17 @@ -import pygame - -from domain.entities.entity import Entity -from domain.world import World - - -class Cat(Entity): - def __init__(self, x: int, y: int): - super().__init__(x, y, "CAT") - self.last_tick = pygame.time.get_ticks() - self.cooldown = 1000 - self.velocity = 1 - self.busy = False - self.sleeping = False - self.direction = 0 - - self.props = [1,2,0,16,1,10,25] \ No newline at end of file +import pygame + +from domain.entities.entity import Entity +from domain.world import World + + +class Cat(Entity): + def __init__(self, x: int, y: int): + super().__init__(x, y, "CAT") + self.last_tick = pygame.time.get_ticks() + self.cooldown = 1000 + self.velocity = 1 + self.busy = False + self.sleeping = False + self.direction = 0 + + self.props = [4,2,20,0,1,32,37,5] \ No newline at end of file diff --git a/domain/entities/docking_station.py b/domain/entities/docking_station.py index 34262a7..dbd704a 100644 --- a/domain/entities/docking_station.py +++ b/domain/entities/docking_station.py @@ -1,10 +1,10 @@ -from domain.entities.entity import Entity -from domain.world import World - - -class Doc_Station(Entity): - def __init__(self, x: int, y: int): - super().__init__(x, y, "DOC_STATION") - self.power = True - +from domain.entities.entity import Entity +from domain.world import World + + +class Doc_Station(Entity): + def __init__(self, x: int, y: int): + super().__init__(x, y, "DOC_STATION") + self.power = True + # TODO Docing Station: add more properties \ No newline at end of file diff --git a/domain/entities/earring.py b/domain/entities/earring.py index f9498ec..03256c0 100644 --- a/domain/entities/earring.py +++ b/domain/entities/earring.py @@ -1,8 +1,8 @@ -from domain.entities.entity import Entity -from domain.world import World - - -class Earring(Entity): - def __init__(self, x: int, y: int): - super().__init__(x, y, "EARRING") - self.props = [2,1,0,12,0,50,24] \ No newline at end of file +from domain.entities.entity import Entity +from domain.world import World + + +class Earring(Entity): + def __init__(self, x: int, y: int): + super().__init__(x, y, "EARRING") + self.props = [1,9,0,1,0,1,20,0] \ No newline at end of file diff --git a/domain/entities/entity.py b/domain/entities/entity.py index 54f0223..9218f40 100644 --- a/domain/entities/entity.py +++ b/domain/entities/entity.py @@ -1,5 +1,5 @@ -class Entity: - def __init__(self, x: int, y: int, type: str): - self.x = x - self.y = y - self.type = type +class Entity: + def __init__(self, x: int, y: int, type: str): + self.x = x + self.y = y + self.type = type diff --git a/domain/entities/garbage.py b/domain/entities/garbage.py index cda5b91..2273cc7 100644 --- a/domain/entities/garbage.py +++ b/domain/entities/garbage.py @@ -1,11 +1,11 @@ -from domain.entities.entity import Entity - - -class Garbage(Entity): - def __init__(self, x: int, y: int): - super().__init__(x, y, "PEEL") - self.wet = False - self.size = 0 - self.props = [1,2,0,16,1,10,25] - - # TODO GARBAGE: add more properties +from domain.entities.entity import Entity + + +class Garbage(Entity): + def __init__(self, x: int, y: int): + super().__init__(x, y, "PEEL") + self.wet = False + self.size = 0 + self.props = [2,2,0,0,1,5,24,1] + + # TODO GARBAGE: add more properties diff --git a/domain/entities/plant.py b/domain/entities/plant.py index 3d17fb2..be24e95 100644 --- a/domain/entities/plant.py +++ b/domain/entities/plant.py @@ -1,10 +1,10 @@ -from domain.entities.entity import Entity -from domain.world import World - - -class Plant(Entity): - def __init__(self, x: int, y: int): - super().__init__(x, y, "PLANT") - self.watered = 100 - - # TODO PLANT: add more properties to +from domain.entities.entity import Entity +from domain.world import World + + +class Plant(Entity): + def __init__(self, x: int, y: int): + super().__init__(x, y, "PLANT") + self.watered = 100 + + # TODO PLANT: add more properties to diff --git a/domain/entities/vacuum.py b/domain/entities/vacuum.py index 54b86e0..8e01c4d 100644 --- a/domain/entities/vacuum.py +++ b/domain/entities/vacuum.py @@ -1,22 +1,22 @@ -from domain.entities.entity import Entity -from domain.world import World - - -class Vacuum(Entity): - def __init__(self, x: int, y: int): - super().__init__(x, y, "VACUUM") - self.direction = (1, 0) - self.battery = 100 - self.cleaning_detergent = 100 - self.container_filling = 0 - - def increase_container_filling(self) -> None: - self.container_filling += 25 - - def dump_trash(self) -> None: - self.container_filling = 0 - - def get_container_filling(self): - return self.container_filling - - # TODO VACUUM: add more properties +from domain.entities.entity import Entity +from domain.world import World + + +class Vacuum(Entity): + def __init__(self, x: int, y: int): + super().__init__(x, y, "VACUUM") + self.direction = (1, 0) + self.battery = 100 + self.cleaning_detergent = 100 + self.container_filling = 0 + + def increase_container_filling(self) -> None: + self.container_filling += 25 + + def dump_trash(self) -> None: + self.container_filling = 0 + + def get_container_filling(self): + return self.container_filling + + # TODO VACUUM: add more properties diff --git a/domain/world.py b/domain/world.py index f31d84e..b46eb44 100644 --- a/domain/world.py +++ b/domain/world.py @@ -1,58 +1,58 @@ -from decisionTree.evaluate import evaluate -from domain.entities.entity import Entity - - -class World: - def __init__(self, width: int, height: int) -> object: - self.costs = [[1000 for j in range(height)] for i in range(width)] - self.width = width - self.height = height - self.dust = [[[] for j in range(height)] for i in range(width)] - self.obstacles = [[[] for j in range(height)] for i in range(width)] - - self.vacuum = None - self.cat = None - self.doc_station = None - - def add_entity(self, entity: Entity): - if entity.type == "PEEL": - self.dust[entity.x][entity.y].append(entity) - elif entity.type == "EARRING": - self.dust[entity.x][entity.y].append(entity) - elif entity.type == "VACUUM": - self.vacuum = entity - elif entity.type == "DOC_STATION": - self.doc_station = entity - elif entity.type == "CAT": - self.cat = entity - self.obstacles[entity.x][entity.y].append(entity) - else: - self.obstacles[entity.x][entity.y].append(entity) - - def is_obstacle_at(self, x: int, y: int) -> bool: - return bool(self.obstacles[x][y]) - - def is_garbage_at(self, x: int, y: int) -> bool: - if len(self.dust[x][y]) == 0: - return False - tmp = evaluate([self.dust[x][y][0].props]) - return bool(tmp[0]) - - def is_docking_station_at(self, x: int, y: int) -> bool: - return bool(self.doc_station.x == x and self.doc_station.y == y) - - def accepted_move(self, checking_x, checking_y): - if ( - checking_x > self.width - 1 - or checking_y > self.height - 1 - or checking_x < 0 - or checking_y < 0 - ): - return False - - if self.is_obstacle_at(checking_x, checking_y): - return False - - return True - def get_cost(self, x, y): +from decisionTree.evaluate import evaluate +from domain.entities.entity import Entity + + +class World: + def __init__(self, width: int, height: int) -> object: + self.costs = [[1000 for j in range(height)] for i in range(width)] + self.width = width + self.height = height + self.dust = [[[] for j in range(height)] for i in range(width)] + self.obstacles = [[[] for j in range(height)] for i in range(width)] + + self.vacuum = None + self.cat = None + self.doc_station = None + + def add_entity(self, entity: Entity): + if entity.type == "PEEL": + self.dust[entity.x][entity.y].append(entity) + elif entity.type == "EARRING": + self.dust[entity.x][entity.y].append(entity) + elif entity.type == "VACUUM": + self.vacuum = entity + elif entity.type == "DOC_STATION": + self.doc_station = entity + elif entity.type == "CAT": + self.cat = entity + self.obstacles[entity.x][entity.y].append(entity) + else: + self.obstacles[entity.x][entity.y].append(entity) + + def is_obstacle_at(self, x: int, y: int) -> bool: + return bool(self.obstacles[x][y]) + + def is_garbage_at(self, x: int, y: int) -> bool: + if len(self.dust[x][y]) == 0: + return False + tmp = evaluate([self.dust[x][y][0].props]) + return bool(tmp[0]) + + def is_docking_station_at(self, x: int, y: int) -> bool: + return bool(self.doc_station.x == x and self.doc_station.y == y) + + def accepted_move(self, checking_x, checking_y): + if ( + checking_x > self.width - 1 + or checking_y > self.height - 1 + or checking_x < 0 + or checking_y < 0 + ): + return False + + if self.is_obstacle_at(checking_x, checking_y): + return False + + return True + def get_cost(self, x, y): return self.costs[x][y] \ No newline at end of file diff --git a/main.py b/main.py index e4688d2..80fbe71 100644 --- a/main.py +++ b/main.py @@ -1,169 +1,169 @@ -from random import randint - -import pygame -import configparser - -from domain.commands.random_cat_move_command import RandomCatMoveCommand -from domain.commands.vacuum_move_command import VacuumMoveCommand -from domain.entities.cat import Cat -from domain.entities.entity import Entity -from domain.entities.vacuum import Vacuum -from domain.entities.garbage import Garbage -from domain.entities.earring import Earring -from domain.entities.docking_station import Doc_Station -from domain.world import World -from view.renderer import Renderer -# from AI_brain.movement import GoAnyDirectionBFS, State -# from AI_brain.rotate_and_go_bfs import RotateAndGoBFS, State -from AI_brain.rotate_and_go_astar import RotateAndGoAStar, State - - -config = configparser.ConfigParser() -config.read("config.ini") - - -class Main: - def __init__(self): - tiles_x = 10 - tiles_y = 10 - - self.renderer = Renderer(800, 800, tiles_x, tiles_y) - - self.world = generate_world(tiles_x, tiles_y) - - self.commands = [] - - self.clock = pygame.time.Clock() - self.running = True - self.fps = 60 - - def run(self): - while self.running: - self.process_input() - self.update() - self.renderer.render(self.world) - self.clock.tick(self.fps) - - pygame.quit() - - def run_robot(self): - self.renderer.render(self.world) - - start_state = State(self.world.vacuum.x, self.world.vacuum.y) - end_state = State(self.world.doc_station.x, self.world.doc_station.y) - - # path_searcher = GoAnyDirectionBFS(self.world, start_state, end_state) - # path_searcher = RotateAndGoBFS(self.world, start_state, end_state) - path_searcher = RotateAndGoAStar(self.world, start_state, end_state) - if not path_searcher.search(): - print("No solution") - exit(0) - - path_searcher.actions.reverse() - while self.running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - self.running = False - - if len(path_searcher.actions) > 0: - action_direction = path_searcher.actions.pop() - # self.handle_action1(action_direction) - self.handle_action2(action_direction) - - self.update() - self.renderer.render(self.world) - self.clock.tick(5) - - pygame.quit() - - def handle_action1(self, action): - if action == "UP": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (0, -1)) - ) - elif action == "DOWN": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (0, 1)) - ) - elif action == "LEFT": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (-1, 0)) - ) - elif action == "RIGHT": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (1, 0)) - ) - - def handle_action2(self, action): - if action == "GO": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, self.world.vacuum.direction) - ) - elif action == "RR": - self.world.vacuum.direction = (-self.world.vacuum.direction[1], self.world.vacuum.direction[0]) - elif action == "RL": - self.world.vacuum.direction = (self.world.vacuum.direction[1], -self.world.vacuum.direction[0]) - - def process_input(self): - for event in pygame.event.get(): - if event.type == pygame.QUIT: - self.running = False - if event.type == pygame.KEYDOWN: - if event.key == pygame.K_LEFT: - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (-1, 0)) - ) - if event.key == pygame.K_RIGHT: - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (1, 0)) - ) - if event.key == pygame.K_UP: - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (0, -1)) - ) - if event.key == pygame.K_DOWN: - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (0, 1)) - ) - - def update(self): - if config.getboolean("APP", "cat"): - self.commands.append(RandomCatMoveCommand(self.world, self.world.cat)) - for command in self.commands: - command.run() - self.commands.clear() - - -def generate_world(tiles_x: int, tiles_y: int) -> World: - world = World(tiles_x, tiles_y) - for _ in range(35): - temp_x = randint(0, tiles_x - 1) - temp_y = randint(0, tiles_y - 1) - world.add_entity(Garbage(temp_x, temp_y)) - world.vacuum = Vacuum(1, 1) - world.doc_station = Doc_Station(9, 8) - if config.getboolean("APP", "cat"): - world.cat = Cat(7, 8) - world.add_entity(world.cat) - world.add_entity(Entity(2, 8, "PLANT1")) - world.add_entity(Entity(4, 1, "PLANT1")) - world.add_entity(Entity(3, 4, "PLANT2")) - world.add_entity(Entity(8, 8, "PLANT2")) - world.add_entity(Entity(9, 3, "PLANT3")) - world.add_entity(Earring(5, 5)) - - - for x in range(world.width): - for y in range(world.height): - if world.is_garbage_at(x, y): - world.costs[x][y] = 1 - else: - world.costs[x][y] = 10 - return world - -if __name__ == "__main__": - app = Main() - if config["APP"]["movement"] == "human": - app.run() - elif config["APP"]["movement"] == "robot": - app.run_robot() +from random import randint + +import pygame +import configparser + +from domain.commands.random_cat_move_command import RandomCatMoveCommand +from domain.commands.vacuum_move_command import VacuumMoveCommand +from domain.entities.cat import Cat +from domain.entities.entity import Entity +from domain.entities.vacuum import Vacuum +from domain.entities.garbage import Garbage +from domain.entities.earring import Earring +from domain.entities.docking_station import Doc_Station +from domain.world import World +from view.renderer import Renderer +# from AI_brain.movement import GoAnyDirectionBFS, State +# from AI_brain.rotate_and_go_bfs import RotateAndGoBFS, State +from AI_brain.rotate_and_go_astar import RotateAndGoAStar, State + + +config = configparser.ConfigParser() +config.read("config.ini") + + +class Main: + def __init__(self): + tiles_x = 10 + tiles_y = 10 + + self.renderer = Renderer(800, 800, tiles_x, tiles_y) + + self.world = generate_world(tiles_x, tiles_y) + + self.commands = [] + + self.clock = pygame.time.Clock() + self.running = True + self.fps = 60 + + def run(self): + while self.running: + self.process_input() + self.update() + self.renderer.render(self.world) + self.clock.tick(self.fps) + + pygame.quit() + + def run_robot(self): + self.renderer.render(self.world) + + start_state = State(self.world.vacuum.x, self.world.vacuum.y) + end_state = State(self.world.doc_station.x, self.world.doc_station.y) + + # path_searcher = GoAnyDirectionBFS(self.world, start_state, end_state) + # path_searcher = RotateAndGoBFS(self.world, start_state, end_state) + path_searcher = RotateAndGoAStar(self.world, start_state, end_state) + if not path_searcher.search(): + print("No solution") + exit(0) + + path_searcher.actions.reverse() + while self.running: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + + if len(path_searcher.actions) > 0: + action_direction = path_searcher.actions.pop() + # self.handle_action1(action_direction) + self.handle_action2(action_direction) + + self.update() + self.renderer.render(self.world) + self.clock.tick(5) + + pygame.quit() + + def handle_action1(self, action): + if action == "UP": + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (0, -1)) + ) + elif action == "DOWN": + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (0, 1)) + ) + elif action == "LEFT": + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (-1, 0)) + ) + elif action == "RIGHT": + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (1, 0)) + ) + + def handle_action2(self, action): + if action == "GO": + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, self.world.vacuum.direction) + ) + elif action == "RR": + self.world.vacuum.direction = (-self.world.vacuum.direction[1], self.world.vacuum.direction[0]) + elif action == "RL": + self.world.vacuum.direction = (self.world.vacuum.direction[1], -self.world.vacuum.direction[0]) + + def process_input(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_LEFT: + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (-1, 0)) + ) + if event.key == pygame.K_RIGHT: + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (1, 0)) + ) + if event.key == pygame.K_UP: + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (0, -1)) + ) + if event.key == pygame.K_DOWN: + self.commands.append( + VacuumMoveCommand(self.world, self.world.vacuum, (0, 1)) + ) + + def update(self): + if config.getboolean("APP", "cat"): + self.commands.append(RandomCatMoveCommand(self.world, self.world.cat)) + for command in self.commands: + command.run() + self.commands.clear() + + +def generate_world(tiles_x: int, tiles_y: int) -> World: + world = World(tiles_x, tiles_y) + for _ in range(35): + temp_x = randint(0, tiles_x - 1) + temp_y = randint(0, tiles_y - 1) + world.add_entity(Garbage(temp_x, temp_y)) + world.vacuum = Vacuum(1, 1) + world.doc_station = Doc_Station(9, 8) + if config.getboolean("APP", "cat"): + world.cat = Cat(7, 8) + world.add_entity(world.cat) + world.add_entity(Entity(2, 8, "PLANT1")) + world.add_entity(Entity(4, 1, "PLANT1")) + world.add_entity(Entity(3, 4, "PLANT2")) + world.add_entity(Entity(8, 8, "PLANT2")) + world.add_entity(Entity(9, 3, "PLANT3")) + world.add_entity(Earring(5, 5)) + + + for x in range(world.width): + for y in range(world.height): + if world.is_garbage_at(x, y): + world.costs[x][y] = 1 + else: + world.costs[x][y] = 10 + return world + +if __name__ == "__main__": + app = Main() + if config["APP"]["movement"] == "human": + app.run() + elif config["APP"]["movement"] == "robot": + app.run_robot() diff --git a/requirements.txt b/requirements.txt index 98bd1d8..a9234a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -pygame -configparser -pandas -scikit-learn -joblib +pygame +configparser +pandas +scikit-learn +joblib # formaFormatting: Provider - black \ No newline at end of file diff --git a/view/renderer.py b/view/renderer.py index e21d270..241f5d2 100644 --- a/view/renderer.py +++ b/view/renderer.py @@ -1,198 +1,198 @@ -import random -from random import randint - -import pygame -import configparser -from pygame import Color - -from domain.entities.cat import Cat -from domain.entities.entity import Entity -from domain.world import World - -config = configparser.ConfigParser() -config.read("config.ini") - - -class Renderer: - def __init__( - self, - width=800, - height=800, - tiles_x=10, - tiles_y=10, - ): - self.width = width - self.height = height - - self.tiles_x = tiles_x - self.tiles_y = tiles_y - - self.tile_width = self.width / self.tiles_x - self.tile_height = self.height / self.tiles_y - - pygame.init() - - pygame.display.set_caption("AI Vacuum Cleaner") - self.screen = pygame.display.set_mode((self.width, self.height)) - self.font = pygame.font.SysFont("Arial", 26, bold=True) - - self.sprites = { - "VACUUM": pygame.transform.scale( - pygame.image.load("media/sprites/vacuum.png"), - (self.tile_width, self.tile_height), - ), - "DOC_STATION": pygame.transform.scale( - pygame.image.load("media/sprites/docking_station.png"), - (self.tile_width, self.tile_height), - ), - "WALL": pygame.transform.scale( - pygame.image.load("media/sprites/wall.png"), - (self.tile_width, self.tile_height), - ), - "TILE": pygame.transform.scale( - pygame.image.load("media/sprites/tile_cropped.jpeg"), - (self.tile_width, self.tile_height), - ), - "PEEL": pygame.transform.scale( - pygame.image.load("media/sprites/peel.webp"), - (self.tile_width, self.tile_height), - ), - "CAT_FRONT": pygame.transform.scale( - pygame.image.load("media/sprites/cat/standing_front.png"), - (self.tile_width, self.tile_height), - ), - "CAT_BACK": pygame.transform.scale( - pygame.image.load("media/sprites/cat/standing_back.png"), - (self.tile_width, self.tile_height), - ), - "CAT_LEFT": pygame.transform.scale( - pygame.image.load("media/sprites/cat/standing_left.png"), - (self.tile_width, self.tile_height), - ), - "CAT_RIGHT": pygame.transform.scale( - pygame.image.load("media/sprites/cat/standing_right.png"), - (self.tile_width, self.tile_height), - ), - "PLANT1": pygame.transform.scale( - pygame.image.load("media/sprites/plants/plant1.png"), - ( - self.tile_width + self.tile_width / 4, - self.tile_height + self.tile_height / 4, - ), - ), - "PLANT2": pygame.transform.scale( - pygame.image.load("media/sprites/plants/plant2.png"), - ( - self.tile_width + self.tile_width / 4, - self.tile_height + self.tile_height / 4, - ), - ), - "PLANT3": pygame.transform.scale( - pygame.image.load("media/sprites/plants/plant3.png"), - ( - self.tile_width + self.tile_width / 4, - self.tile_height + self.tile_height / 4, - ), - ), - "EARRING": pygame.transform.scale( - pygame.image.load("media/sprites/earrings.webp"), - ( - self.tile_width + self.tile_width / 4, - self.tile_height + self.tile_height / 4, - ), - ), - } - - self.cat_direction_sprite = { - 0: self.sprites["CAT_BACK"], - 1: self.sprites["CAT_RIGHT"], - 2: self.sprites["CAT_FRONT"], - 3: self.sprites["CAT_LEFT"], - } - - def render(self, world: World): - self.render_floor() - self.render_board() - for x in range(world.width): - for y in range(world.height): - for entity in world.dust[x][y]: - self.draw_entity(entity) - for x in range(world.width): - for y in range(world.height): - for entity in world.obstacles[x][y]: - self.draw_entity(entity) - self.draw_entity(world.vacuum) - self.draw_entity(world.doc_station) - if config.getboolean("APP", "cat"): - self.draw_entity(world.cat) - pygame.display.update() - - def line(self, x_1, y_1, x_2, y_2, color=None): - pygame.draw.line(self.screen, color, (x_1, y_1), (x_2, y_2)) - - def render_board(self, color=Color("black")): - for i in range(1, self.tiles_x): - self.line( - self.tile_width * i, 0, self.tile_width * i, self.height, color=color - ) - - for i in range(1, self.tiles_y): - self.line( - 0, self.tile_height * i, self.width, self.tile_height * i, color=color - ) - - def draw_entity(self, entity: Entity): - sprite = self.sprites.get(entity.type, None) - draw_pos = (entity.x * self.tile_width, entity.y * self.tile_height) - if "PEEL" in entity.type: - draw_pos = ( - (entity.x - 0.1) * self.tile_width, - (entity.y - 0.25) * self.tile_height, - ) - if "PLANT" in entity.type: - draw_pos = ( - (entity.x - 0.1) * self.tile_width, - (entity.y - 0.25) * self.tile_height, - ) - if "CAT" in entity.type and isinstance(entity, Cat): - sprite = self.cat_direction_sprite[entity.direction] - if "VACUUM" in entity.type: - # Add text displaying container filling level - text_surface = self.font.render( - f"Filling: {entity.container_filling}%", True, Color("black") - ) - text_pos = ( - draw_pos[0] + self.tile_width / 2 - text_surface.get_width() / 2, - draw_pos[1] + self.tile_height, - ) - self.screen.blit(text_surface, text_pos) - sprite = self.create_vacuum_sprite(entity) - if "DOC_STATION" in entity.type: - draw_pos = ( - (entity.x - 0.1) * self.tile_width, - (entity.y - 0.25) * self.tile_height, - ) - self.screen.blit(sprite, draw_pos) - - def create_vacuum_sprite(self, vacuum): - angles = { - (1, 0): 0, - (-1, 0): 180, - (0, 1): 270, - (0, -1): 90, - } - init_sprite = self.sprites.get(vacuum.type, None) - return pygame.transform.rotate(init_sprite, angles[vacuum.direction]) - - def draw_sprite(self, x: int, y: int, sprite_name: str): - self.screen.blit( - self.sprites[sprite_name], (x * self.tile_width, y * self.tile_height) - ) - - def fill_grid_with_sprite(self, sprite): - for tile_x in range(self.tiles_x): - for tile_y in range(self.tiles_y): - self.draw_sprite(tile_x, tile_y, sprite) - - def render_floor(self): - self.fill_grid_with_sprite("TILE") +import random +from random import randint + +import pygame +import configparser +from pygame import Color + +from domain.entities.cat import Cat +from domain.entities.entity import Entity +from domain.world import World + +config = configparser.ConfigParser() +config.read("config.ini") + + +class Renderer: + def __init__( + self, + width=800, + height=800, + tiles_x=10, + tiles_y=10, + ): + self.width = width + self.height = height + + self.tiles_x = tiles_x + self.tiles_y = tiles_y + + self.tile_width = self.width / self.tiles_x + self.tile_height = self.height / self.tiles_y + + pygame.init() + + pygame.display.set_caption("AI Vacuum Cleaner") + self.screen = pygame.display.set_mode((self.width, self.height)) + self.font = pygame.font.SysFont("Arial", 26, bold=True) + + self.sprites = { + "VACUUM": pygame.transform.scale( + pygame.image.load("media/sprites/vacuum.png"), + (self.tile_width, self.tile_height), + ), + "DOC_STATION": pygame.transform.scale( + pygame.image.load("media/sprites/docking_station.png"), + (self.tile_width, self.tile_height), + ), + "WALL": pygame.transform.scale( + pygame.image.load("media/sprites/wall.png"), + (self.tile_width, self.tile_height), + ), + "TILE": pygame.transform.scale( + pygame.image.load("media/sprites/tile_cropped.jpeg"), + (self.tile_width, self.tile_height), + ), + "PEEL": pygame.transform.scale( + pygame.image.load("media/sprites/peel.webp"), + (self.tile_width, self.tile_height), + ), + "CAT_FRONT": pygame.transform.scale( + pygame.image.load("media/sprites/cat/standing_front.png"), + (self.tile_width, self.tile_height), + ), + "CAT_BACK": pygame.transform.scale( + pygame.image.load("media/sprites/cat/standing_back.png"), + (self.tile_width, self.tile_height), + ), + "CAT_LEFT": pygame.transform.scale( + pygame.image.load("media/sprites/cat/standing_left.png"), + (self.tile_width, self.tile_height), + ), + "CAT_RIGHT": pygame.transform.scale( + pygame.image.load("media/sprites/cat/standing_right.png"), + (self.tile_width, self.tile_height), + ), + "PLANT1": pygame.transform.scale( + pygame.image.load("media/sprites/plants/plant1.png"), + ( + self.tile_width + self.tile_width / 4, + self.tile_height + self.tile_height / 4, + ), + ), + "PLANT2": pygame.transform.scale( + pygame.image.load("media/sprites/plants/plant2.png"), + ( + self.tile_width + self.tile_width / 4, + self.tile_height + self.tile_height / 4, + ), + ), + "PLANT3": pygame.transform.scale( + pygame.image.load("media/sprites/plants/plant3.png"), + ( + self.tile_width + self.tile_width / 4, + self.tile_height + self.tile_height / 4, + ), + ), + "EARRING": pygame.transform.scale( + pygame.image.load("media/sprites/earrings.webp"), + ( + self.tile_width + self.tile_width / 4, + self.tile_height + self.tile_height / 4, + ), + ), + } + + self.cat_direction_sprite = { + 0: self.sprites["CAT_BACK"], + 1: self.sprites["CAT_RIGHT"], + 2: self.sprites["CAT_FRONT"], + 3: self.sprites["CAT_LEFT"], + } + + def render(self, world: World): + self.render_floor() + self.render_board() + for x in range(world.width): + for y in range(world.height): + for entity in world.dust[x][y]: + self.draw_entity(entity) + for x in range(world.width): + for y in range(world.height): + for entity in world.obstacles[x][y]: + self.draw_entity(entity) + self.draw_entity(world.vacuum) + self.draw_entity(world.doc_station) + if config.getboolean("APP", "cat"): + self.draw_entity(world.cat) + pygame.display.update() + + def line(self, x_1, y_1, x_2, y_2, color=None): + pygame.draw.line(self.screen, color, (x_1, y_1), (x_2, y_2)) + + def render_board(self, color=Color("black")): + for i in range(1, self.tiles_x): + self.line( + self.tile_width * i, 0, self.tile_width * i, self.height, color=color + ) + + for i in range(1, self.tiles_y): + self.line( + 0, self.tile_height * i, self.width, self.tile_height * i, color=color + ) + + def draw_entity(self, entity: Entity): + sprite = self.sprites.get(entity.type, None) + draw_pos = (entity.x * self.tile_width, entity.y * self.tile_height) + if "PEEL" in entity.type: + draw_pos = ( + (entity.x - 0.1) * self.tile_width, + (entity.y - 0.25) * self.tile_height, + ) + if "PLANT" in entity.type: + draw_pos = ( + (entity.x - 0.1) * self.tile_width, + (entity.y - 0.25) * self.tile_height, + ) + if "CAT" in entity.type and isinstance(entity, Cat): + sprite = self.cat_direction_sprite[entity.direction] + if "VACUUM" in entity.type: + # Add text displaying container filling level + text_surface = self.font.render( + f"Filling: {entity.container_filling}%", True, Color("black") + ) + text_pos = ( + draw_pos[0] + self.tile_width / 2 - text_surface.get_width() / 2, + draw_pos[1] + self.tile_height, + ) + self.screen.blit(text_surface, text_pos) + sprite = self.create_vacuum_sprite(entity) + if "DOC_STATION" in entity.type: + draw_pos = ( + (entity.x - 0.1) * self.tile_width, + (entity.y - 0.25) * self.tile_height, + ) + self.screen.blit(sprite, draw_pos) + + def create_vacuum_sprite(self, vacuum): + angles = { + (1, 0): 0, + (-1, 0): 180, + (0, 1): 270, + (0, -1): 90, + } + init_sprite = self.sprites.get(vacuum.type, None) + return pygame.transform.rotate(init_sprite, angles[vacuum.direction]) + + def draw_sprite(self, x: int, y: int, sprite_name: str): + self.screen.blit( + self.sprites[sprite_name], (x * self.tile_width, y * self.tile_height) + ) + + def fill_grid_with_sprite(self, sprite): + for tile_x in range(self.tiles_x): + for tile_y in range(self.tiles_y): + self.draw_sprite(tile_x, tile_y, sprite) + + def render_floor(self): + self.fill_grid_with_sprite("TILE")