From f12eb5ba0dc44158552264e6690a464642e727e4 Mon Sep 17 00:00:00 2001 From: Pawel Felcyn Date: Sat, 22 Apr 2023 16:16:36 +0200 Subject: [PATCH 1/5] implement bfs algorythm --- agentOrientation.py | 7 ++++ bfs.py | 94 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 agentOrientation.py create mode 100644 bfs.py diff --git a/agentOrientation.py b/agentOrientation.py new file mode 100644 index 0000000..e9dc88a --- /dev/null +++ b/agentOrientation.py @@ -0,0 +1,7 @@ +from enum import Enum + +class AgentOrientation (Enum): + UP = 0 + RIGHT = 1 + DOWN = 2 + LEFT = 3 \ No newline at end of file diff --git a/bfs.py b/bfs.py new file mode 100644 index 0000000..eaa99fa --- /dev/null +++ b/bfs.py @@ -0,0 +1,94 @@ +from agentState import AgentState +from typing import Dict, Tuple +from gridCellType import GridCellType +from agentActionType import AgentActionType +from agentOrientation import AgentOrientation +from queue import Queue + +class Succ: + state: AgentState + action: AgentActionType + + def __init__(self, state: AgentState, action: AgentActionType) -> None: + self.state = state + self.action = action + +def find_path_to_nearest_can(startState: AgentState, grid: Dict[Tuple[int, int], GridCellType]) -> list[AgentActionType]: + q: Queue[list[Succ]] = Queue() + visited: list[Tuple[int, int]] = [] + startStates: list[Succ] = [Succ(startState, AgentActionType.UNKNOWN)] + q.put(startStates) + while not q.empty(): + currently_checked = q.get() + visited.append(currently_checked[-1].state.position) + if is_state_success(currently_checked[-1].state, grid): + return extract_actions(currently_checked) + successors = succ(currently_checked[-1].state) + for s in successors: + already_visited = False + for v in visited: + if v[0] == s.state.position[0] and v[1] == s.state.position[1]: + already_visited = True + break + if already_visited: + continue + if is_state_valid(s.state, grid): + new_list = currently_checked.copy() + new_list.append(s) + q.put(new_list) + return [] + + + +def extract_actions(successors: list[Succ]) -> list[AgentActionType]: + output: list[AgentActionType] = [] + for s in successors: + if s.action != AgentActionType.UNKNOWN: + output.append(s.action) + return output + +def succ(state: AgentState) -> list[Succ]: + result: list[Succ] = [] + result.append(Succ(AgentState(state.position, turn_left_orientation(state.orientation)), AgentActionType.TURN_LEFT)) + result.append(Succ(AgentState(state.position, turn_right_orientation(state.orientation)), AgentActionType.TURN_RIGHT)) + state_succ = move_forward_succ(state) + if state_succ != None: + result.append(move_forward_succ(state)) + return result + +def turn_left_orientation(orientation: AgentOrientation) -> AgentOrientation: + return (orientation - 1) % 4 + +def turn_right_orientation(orientation: AgentOrientation) -> AgentOrientation: + return (orientation + 1) % 4 + +def move_forward_succ(state: AgentState) -> Succ: + position = get_next_cell(state) + if position == None: + return None + return Succ(AgentState(position, state.orientation), AgentActionType.MOVE_FORWARD) + + +def get_next_cell(state: AgentState) -> Tuple[int, int]: + if state.orientation == AgentOrientation.UP: + if state.position[1] - 1 < 1: + return None + return (state.position[0], state.position[1] - 1) + if state.orientation == AgentOrientation.DOWN: + if state.position[1] + 1 > 27: + return None + return (state.position[0], state.position[1] + 1) + if state.orientation == AgentOrientation.LEFT: + if state.position[0] - 1 < 1: + return None + return (state.position[0] - 1, state.position[1]) + if state.position[0] + 1 > 27: + return None + return (state.position[0] + 1, state.position[1]) + +def is_state_success(state: AgentState, grid: Dict[Tuple[int, int], GridCellType]) -> bool: + next_cell = get_next_cell(state) + return grid[next_cell] == GridCellType.GARBAGE_CAN + +def is_state_valid(state: AgentState, grid: Dict[Tuple[int, int], GridCellType]) -> bool: + return grid[state.position] == GridCellType.STREET_HORIZONTAL or grid[state.position] == GridCellType.STREET_VERTICAL \ No newline at end of file From 7c44d653477cdfc754ad807d23202ab36ace8769 Mon Sep 17 00:00:00 2001 From: Pawel Felcyn Date: Sat, 22 Apr 2023 16:17:00 +0200 Subject: [PATCH 2/5] implement bfs algorythm --- agentActionType.py | 3 ++- agentState.py | 10 ++++++++++ gridCellType.py | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 agentState.py diff --git a/agentActionType.py b/agentActionType.py index b251b0c..abbf382 100644 --- a/agentActionType.py +++ b/agentActionType.py @@ -3,4 +3,5 @@ from enum import Enum class AgentActionType (Enum): MOVE_FORWARD = 0 TURN_LEFT = 1 - TURN_RIGHT = 2 \ No newline at end of file + TURN_RIGHT = 2 + UNKNOWN = None \ No newline at end of file diff --git a/agentState.py b/agentState.py new file mode 100644 index 0000000..1ac708d --- /dev/null +++ b/agentState.py @@ -0,0 +1,10 @@ +from agentOrientation import AgentOrientation +from typing import Tuple + +class AgentState: + orientation: AgentOrientation + position: Tuple[int, int] + + def __init__(self, position: Tuple[int, int], orientation: AgentOrientation) -> None: + self.orientation = orientation + self.position = position \ No newline at end of file diff --git a/gridCellType.py b/gridCellType.py index d8e5e42..68f37bf 100644 --- a/gridCellType.py +++ b/gridCellType.py @@ -4,4 +4,5 @@ class GridCellType(Enum): NOTHING = 0 STREET_VERTICAL = 1 STREET_HORIZONTAL = 2 - GARBAGE_CAN = 3 \ No newline at end of file + GARBAGE_CAN = 3 + VISITED_GARBAGE_CAN = 4 \ No newline at end of file From d0d9fb030938a73a5c09da3e709f69eefa0fc079 Mon Sep 17 00:00:00 2001 From: Pawel Felcyn Date: Sat, 22 Apr 2023 16:36:13 +0200 Subject: [PATCH 3/5] dust car instance --- gameContext.py | 1 + gameEventHandler.py | 21 +-------------------- garbageTruck.py | 22 ++++++++++++++++++---- startup.py | 8 +++++++- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/gameContext.py b/gameContext.py index 37939b0..b454bd2 100644 --- a/gameContext.py +++ b/gameContext.py @@ -13,6 +13,7 @@ class GameContext: _cell_size: int = 30 city = None grid: Dict[Tuple[int, int], GridCellType] = {} + dust_car = None def __init__(self) -> None: self._init_grid() diff --git a/gameEventHandler.py b/gameEventHandler.py index 479fb9e..85131c1 100644 --- a/gameEventHandler.py +++ b/gameEventHandler.py @@ -2,23 +2,4 @@ import pygame from gameContext import GameContext def handle_game_event(event, game_context: GameContext): - dust_car_movement(event, game_context) - return - -def dust_car_movement(event, game_context:GameContext): - if event.type != pygame.KEYDOWN: - return - (width, height) = game_context.dust_car_pil.size - if event.key == pygame.K_LEFT: - pygame.draw.rect(game_context.canvas, (0, 0, 0), (game_context.dust_car_position_x, game_context.dust_car_position_y, width, height)) - game_context.dust_car_position_x -= game_context.dust_car_speed - elif event.key == pygame.K_RIGHT: - pygame.draw.rect(game_context.canvas, (0, 0, 0), (game_context.dust_car_position_x, game_context.dust_car_position_y, width, height)) - game_context.dust_car_position_x += game_context.dust_car_speed - elif event.key == pygame.K_UP: - pygame.draw.rect(game_context.canvas, (0, 0, 0), (game_context.dust_car_position_x, game_context.dust_car_position_y, width, height)) - game_context.dust_car_position_y -= game_context.dust_car_speed - elif event.key == pygame.K_DOWN: - pygame.draw.rect(game_context.canvas, (0, 0, 0), (game_context.dust_car_position_x, game_context.dust_car_position_y, width, height)) - game_context.dust_car_position_y += game_context.dust_car_speed - game_context.canvas.blit(game_context.dust_car_pygame, (game_context.dust_car_position_x, game_context.dust_car_position_y)) + pass \ No newline at end of file diff --git a/garbageTruck.py b/garbageTruck.py index 8f578d9..5584adc 100644 --- a/garbageTruck.py +++ b/garbageTruck.py @@ -1,6 +1,7 @@ from typing import List, Tuple - +from agentOrientation import AgentOrientation from garbage import RecognizedGarbage +from gameContext import GameContext class GarbageTruck: position: Tuple[int, int] @@ -9,8 +10,9 @@ class GarbageTruck: glass: List[RecognizedGarbage] bio: List[RecognizedGarbage] mixed: List[RecognizedGarbage] - truckSpritePath = 'imgs/dust_car.png' - def __init__(self, position: List[int, int]) -> None: + orientation: AgentOrientation = AgentOrientation.RIGHT + + def __init__(self, position: Tuple[int, int]) -> None: self.position = position self.paper = [] self.plastic_and_metal = [] @@ -33,4 +35,16 @@ class GarbageTruck: self.bio.append(RecognizedGarbage) elif RecognizedGarbage.garbage_type == 5: - self.mixed.append(RecognizedGarbage) \ No newline at end of file + self.mixed.append(RecognizedGarbage) + + def render(self, game_context: GameContext) -> None: + path = None + if self.orientation == AgentOrientation.LEFT: + path = 'imgs/dust_car_left.png' + elif self.orientation == AgentOrientation.RIGHT: + path = 'imgs/dust_car_right.png' + elif self.orientation == AgentOrientation.UP: + path = 'imgs/dust_car_up.png' + elif self.orientation == AgentOrientation.DOWN: + path = 'imgs/dust_car_down.png' + game_context.render_in_cell(self.position, path) \ No newline at end of file diff --git a/startup.py b/startup.py index 64fe804..607bb9f 100644 --- a/startup.py +++ b/startup.py @@ -4,12 +4,18 @@ from PIL import Image import pygame from typing import Tuple, List from street import Street, StreetType +from garbageTruck import GarbageTruck def startup(game_context: GameContext): render_background(game_context) game_context.city = create_city() game_context.city.render_city(game_context) - game_context.canvas.blit(game_context.dust_car_pygame, (game_context.dust_car_position_x, game_context.dust_car_position_y)) + car = create_dust_car(game_context) + car.render(game_context) + game_context.dust_car = car + +def create_dust_car(game_context: GameContext) -> GarbageTruck: + return GarbageTruck((3, 3)) def render_background(game_context: GameContext): bg_img = Image.open("imgs/background.jpg") From c5e6eadcaed03b559871439af926089102ade8af Mon Sep 17 00:00:00 2001 From: Pawel Felcyn Date: Sat, 22 Apr 2023 17:46:08 +0200 Subject: [PATCH 4/5] add function for moving dust car --- bfs.py | 7 +------ main.py | 10 ++++++++++ movement.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ turnCar.py | 19 +++++++++++++++++++ 4 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 movement.py create mode 100644 turnCar.py diff --git a/bfs.py b/bfs.py index eaa99fa..6c1afb7 100644 --- a/bfs.py +++ b/bfs.py @@ -4,6 +4,7 @@ from gridCellType import GridCellType from agentActionType import AgentActionType from agentOrientation import AgentOrientation from queue import Queue +from turnCar import turn_left_orientation, turn_right_orientation class Succ: state: AgentState @@ -56,12 +57,6 @@ def succ(state: AgentState) -> list[Succ]: result.append(move_forward_succ(state)) return result -def turn_left_orientation(orientation: AgentOrientation) -> AgentOrientation: - return (orientation - 1) % 4 - -def turn_right_orientation(orientation: AgentOrientation) -> AgentOrientation: - return (orientation + 1) % 4 - def move_forward_succ(state: AgentState) -> Succ: position = get_next_cell(state) if position == None: diff --git a/main.py b/main.py index 467a645..88a0c48 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,8 @@ from gameEventHandler import handle_game_event from gameContext import GameContext from startup import startup from PIL import Image +from agentActionType import AgentActionType +from movement import move_dust_car pygame.init() @@ -17,6 +19,14 @@ game_context.dust_car_pygame = pygame.image.frombuffer(dust_car_pil.tobytes(), d game_context.canvas = canvas startup(game_context) +# test = [AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, +# AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, +# AgentActionType.MOVE_FORWARD, AgentActionType.TURN_RIGHT, AgentActionType.MOVE_FORWARD, +# AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, +# AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, AgentActionType.MOVE_FORWARD, +# AgentActionType.TURN_LEFT, AgentActionType.MOVE_FORWARD] + +# move_dust_car(test, game_context) exit = False diff --git a/movement.py b/movement.py new file mode 100644 index 0000000..39f0650 --- /dev/null +++ b/movement.py @@ -0,0 +1,48 @@ +from agentActionType import AgentActionType +import time +from turnCar import turn_left_orientation, turn_right_orientation +from garbageTruck import GarbageTruck +from typing import Tuple, Dict +from gridCellType import GridCellType +from gameContext import GameContext +from agentOrientation import AgentOrientation +import pygame + +def move_dust_car(actions: list[AgentActionType], game_context: GameContext) -> None: + for action in actions: + street_position = game_context.dust_car.position + has_to_render_street = False + if action == AgentActionType.TURN_LEFT: + game_context.dust_car.orientation = turn_left_orientation(game_context.dust_car.orientation) + elif action == AgentActionType.TURN_RIGHT: + game_context.dust_car.orientation = turn_right_orientation(game_context.dust_car.orientation) + elif action == AgentActionType.MOVE_FORWARD: + game_context.dust_car.position = calculate_next_position(game_context.dust_car) + has_to_render_street = True + game_context.dust_car.render(game_context) + if has_to_render_street: + if game_context.grid[street_position] == GridCellType.STREET_HORIZONTAL: + game_context.render_in_cell(street_position, "imgs/street_horizontal.png") + elif game_context.grid[street_position] == GridCellType.STREET_VERTICAL: + game_context.render_in_cell(street_position, "imgs/street_vertical.png") + pygame.display.update() + time.sleep(0.5) + + + +def calculate_next_position(car: GarbageTruck) -> Tuple[int, int]: + if car.orientation == AgentOrientation.UP: + if car.position[1] - 1 < 1: + return None + return (car.position[0], car.position[1] - 1) + if car.orientation == AgentOrientation.DOWN: + if car.position[1] + 1 > 27: + return None + return (car.position[0], car.position[1] + 1) + if car.orientation == AgentOrientation.LEFT: + if car.position[0] - 1 < 1: + return None + return (car.position[0] - 1, car.position[1]) + if car.position[0] + 1 > 27: + return None + return (car.position[0] + 1, car.position[1]) \ No newline at end of file diff --git a/turnCar.py b/turnCar.py new file mode 100644 index 0000000..f0a0c34 --- /dev/null +++ b/turnCar.py @@ -0,0 +1,19 @@ +from agentOrientation import AgentOrientation + +def turn_left_orientation(orientation: AgentOrientation) -> AgentOrientation: + if orientation == AgentOrientation.DOWN: + return AgentOrientation.RIGHT + if orientation == AgentOrientation.LEFT: + return AgentOrientation.DOWN + if orientation == AgentOrientation.UP: + return AgentOrientation.LEFT + return AgentOrientation.UP + +def turn_right_orientation(orientation: AgentOrientation) -> AgentOrientation: + if orientation == AgentOrientation.DOWN: + return AgentOrientation.LEFT + if orientation == AgentOrientation.LEFT: + return AgentOrientation.UP + if orientation == AgentOrientation.UP: + return AgentOrientation.RIGHT + return AgentOrientation.DOWN \ No newline at end of file From c22e86e22b840e824b4891a3b04c68f3751200fa Mon Sep 17 00:00:00 2001 From: Pawel Felcyn Date: Sat, 22 Apr 2023 18:06:50 +0200 Subject: [PATCH 5/5] fix bfs --- bfs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bfs.py b/bfs.py index 6c1afb7..9373df7 100644 --- a/bfs.py +++ b/bfs.py @@ -16,19 +16,19 @@ class Succ: def find_path_to_nearest_can(startState: AgentState, grid: Dict[Tuple[int, int], GridCellType]) -> list[AgentActionType]: q: Queue[list[Succ]] = Queue() - visited: list[Tuple[int, int]] = [] + visited: list[AgentState] = [] startStates: list[Succ] = [Succ(startState, AgentActionType.UNKNOWN)] q.put(startStates) while not q.empty(): currently_checked = q.get() - visited.append(currently_checked[-1].state.position) + visited.append(currently_checked[-1].state) if is_state_success(currently_checked[-1].state, grid): return extract_actions(currently_checked) successors = succ(currently_checked[-1].state) for s in successors: already_visited = False for v in visited: - if v[0] == s.state.position[0] and v[1] == s.state.position[1]: + if v.position[0] == s.state.position[0] and v.position[1] == s.state.position[1] and s.state.orientation == v.orientation: already_visited = True break if already_visited: