From afdcac8b561e1f8d324d7bdac4e29799dced777a Mon Sep 17 00:00:00 2001 From: Eikthyrnir Date: Fri, 21 Apr 2023 13:11:52 +0200 Subject: [PATCH] now the vacuum can only go straight and rotate left/right to change direction --- .gitignore | 5 ++- AI_brain/template_bfs.py | 78 +++++++++++++++++++++++++++++++++++++++ domain/entities/vacuum.py | 1 + main.py | 53 +++++++++++++++++--------- view/renderer.py | 11 ++++++ 5 files changed, 129 insertions(+), 19 deletions(-) create mode 100644 AI_brain/template_bfs.py diff --git a/.gitignore b/.gitignore index 8278ed1..7efaafe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ /venv .DS_Store /.vscode -__pycache__ \ No newline at end of file +__pycache__ + +#PyCharm +.idea/ \ No newline at end of file diff --git a/AI_brain/template_bfs.py b/AI_brain/template_bfs.py new file mode 100644 index 0000000..02a258d --- /dev/null +++ b/AI_brain/template_bfs.py @@ -0,0 +1,78 @@ +import queue + +from domain.commands.vacuum_move_command import VacuumMoveCommand +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 TemplateBFS: + 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 elem.state == self.goal_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 = [ + # ("GO", State(state.x + state.direction[0], state.y + state.direction[1], state.direction)), + # 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 diff --git a/domain/entities/vacuum.py b/domain/entities/vacuum.py index 1ccbc14..54b86e0 100644 --- a/domain/entities/vacuum.py +++ b/domain/entities/vacuum.py @@ -5,6 +5,7 @@ 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 diff --git a/main.py b/main.py index 8da28a6..0b23686 100644 --- a/main.py +++ b/main.py @@ -11,7 +11,8 @@ from domain.entities.vacuum import Vacuum from domain.entities.docking_station import Doc_Station from domain.world import World from view.renderer import Renderer -from AI_brain.movement import StateGraphSearchBFS, State +# from AI_brain.movement import StateGraphSearchBFS, State +from AI_brain.template_bfs import TemplateBFS, State config = configparser.ConfigParser() @@ -48,7 +49,8 @@ class Main: start_state = State(self.world.vacuum.x, self.world.vacuum.y) end_state = State(self.world.doc_station.x, self.world.doc_station.y) - SGS_BFS = StateGraphSearchBFS(self.world, start_state, end_state) + # SGS_BFS = StateGraphSearchBFS(self.world, start_state, end_state) + SGS_BFS = TemplateBFS(self.world, start_state, end_state) if not SGS_BFS.search(): print("No solution") exit(0) @@ -59,26 +61,41 @@ class Main: self.clock.tick(5) if len(SGS_BFS.actions) > 0: action_direction = SGS_BFS.actions.pop() - if action_direction == "UP": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (0, -1)) - ) - elif action_direction == "DOWN": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (0, 1)) - ) - elif action_direction == "LEFT": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (-1, 0)) - ) - elif action_direction == "RIGHT": - self.commands.append( - VacuumMoveCommand(self.world, self.world.vacuum, (1, 0)) - ) + # self.handle_action1(action_direction) + self.handle_action2(action_direction) + self.update() 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: diff --git a/view/renderer.py b/view/renderer.py index 84dabde..e8294cb 100644 --- a/view/renderer.py +++ b/view/renderer.py @@ -159,6 +159,7 @@ class Renderer: 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, @@ -166,6 +167,16 @@ class Renderer: ) 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)