Merge pull request 'master' (#1) from s473616/sztuczna_inteligencja_2023_smieciarka:master into master

Reviewed-on: s464933/sztuczna_inteligencja_2023_smieciarka#1
This commit is contained in:
Maksymilian Szygenda 2023-04-23 15:33:38 +02:00
commit ca91fd4726
27 changed files with 422 additions and 25 deletions

View File

@ -1,2 +1,3 @@
# sztuczna_inteligencja_2023_smieciarka # sztuczna_inteligencja_2023_smieciarka
Symulacja inteligentnej śmieciarki. Śmieciarka zbiera śmieci z kubłów wystawionych przez mieszkańców, samodzielnie je segreguje i zawozi na wysypisko.

7
agentActionType.py Normal file
View File

@ -0,0 +1,7 @@
from enum import Enum
class AgentActionType (Enum):
MOVE_FORWARD = 0
TURN_LEFT = 1
TURN_RIGHT = 2
UNKNOWN = None

7
agentOrientation.py Normal file
View File

@ -0,0 +1,7 @@
from enum import Enum
class AgentOrientation (Enum):
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3

10
agentState.py Normal file
View File

@ -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

89
bfs.py Normal file
View File

@ -0,0 +1,89 @@
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
from turnCar import turn_left_orientation, turn_right_orientation
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[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)
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.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:
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 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

33
city.py Normal file
View File

@ -0,0 +1,33 @@
from typing import List
from garbageCan import GarbageCan
from street import Street
from gameContext import GameContext
class Node:
garbageCan: GarbageCan
id: int
def __init__(self, id: int, can: GarbageCan) -> None:
self.id
self.can = can
class City:
nodes: List[Node]
streets: List[Street]
def __init__(self) -> None:
self.nodes = []
self.streets = []
def add_node(self, node: Node) -> None:
self.nodes.append(node)
def add_street(self, street: Street) -> None:
self.streets.append(street)
def render_city(self, game_context: GameContext) -> None:
self._render_streets(game_context)
def _render_streets(self, game_context: GameContext) -> None:
for street in self.streets:
street.render(game_context)

View File

@ -1,4 +1,7 @@
from typing import Tuple, List, Dict
import pygame import pygame
from PIL import Image
from gridCellType import GridCellType
class GameContext: class GameContext:
dust_car_speed = 20 dust_car_speed = 20
@ -7,6 +10,24 @@ class GameContext:
dust_car_pygame = None dust_car_pygame = None
dust_car_pil = None dust_car_pil = None
canvas = None canvas = None
_cell_size: int = 30
city = None
grid: Dict[Tuple[int, int], GridCellType] = {}
dust_car = None
def __init__(self) -> None:
self._init_grid()
def _init_grid(self) -> None:
for i in range(1, 28):
for j in range(1, 28):
self.grid[(i, j)] = GridCellType.NOTHING
def render_in_cell(self, cell: Tuple[int, int], img_path: str):
img = Image.open(img_path)
pygame_img = pygame.image.frombuffer(img.tobytes(), (self._cell_size,self._cell_size), 'RGB')
start_x = (cell[0] - 1) * self._cell_size
start_y = (cell[1] - 1) * self._cell_size
self.canvas.blit(pygame_img, (start_x, start_y))
def startup(game_context: GameContext):
game_context.canvas.blit(game_context.dust_car_pygame, (game_context.dust_car_position_x, game_context.dust_car_position_y))

View File

@ -2,23 +2,4 @@ import pygame
from gameContext import GameContext from gameContext import GameContext
def handle_game_event(event, game_context: GameContext): def handle_game_event(event, game_context: GameContext):
dust_car_movement(event, game_context) pass
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))

21
garbage.py Normal file
View File

@ -0,0 +1,21 @@
from enum import Enum
class GarbageType (Enum):
PAPER = 0,
PLASTIC_AND_METAL = 1
GLASS = 3
BIO = 4
MIXED = 5
class Garbage:
img: str
def __init__(self, img: str) -> None:
self.img = img
class RecognizedGarbage (Garbage):
garbage_type: GarbageType
def __init__(self, src: Garbage, garbage_type: GarbageType) -> None:
super().__init__(src.img)
self.garbage_type = garbage_type

22
garbageCan.py Normal file
View File

@ -0,0 +1,22 @@
from garbage import Garbage
from typing import List, Tuple
from gameContext import GameContext
from gridCellType import GridCellType
class GarbageCan:
position: Tuple[int, int]
garbage: List[Garbage]
def __init__(self, position: Tuple[int, int]) -> None:
self.position = position
self.garbage = []
def add_garbage(self, garbage: Garbage) -> None:
self.garbage.append(garbage)
def remove_garbage(self, garbage: Garbage) -> None:
self.garbage.remove(garbage)
def render(self, game_context: GameContext) -> None:
game_context.render_in_cell(self.position, "imgs/container.png")
game_context.grid[self.position] = GridCellType.GARBAGE_CAN

50
garbageTruck.py Normal file
View File

@ -0,0 +1,50 @@
from typing import List, Tuple
from agentOrientation import AgentOrientation
from garbage import RecognizedGarbage
from gameContext import GameContext
class GarbageTruck:
position: Tuple[int, int]
paper: List[RecognizedGarbage]
plastic_and_metal: List[RecognizedGarbage]
glass: List[RecognizedGarbage]
bio: List[RecognizedGarbage]
mixed: List[RecognizedGarbage]
orientation: AgentOrientation = AgentOrientation.RIGHT
def __init__(self, position: Tuple[int, int]) -> None:
self.position = position
self.paper = []
self.plastic_and_metal = []
self.glass = []
self.bio = []
self.mixed = []
def sort_garbage(self, RecognizedGarbage) -> None:
if RecognizedGarbage.garbage_type == 0:
self.paper.append(RecognizedGarbage)
elif RecognizedGarbage.garbage_type == 1:
self.plastic_and_metal.append(RecognizedGarbage)
elif RecognizedGarbage.garbage_type == 3:
self.glass.append(RecognizedGarbage)
elif RecognizedGarbage.garbage_type == 4:
self.bio.append(RecognizedGarbage)
elif RecognizedGarbage.garbage_type == 5:
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)

8
gridCellType.py Normal file
View File

@ -0,0 +1,8 @@
from enum import Enum
class GridCellType(Enum):
NOTHING = 0
STREET_VERTICAL = 1
STREET_HORIZONTAL = 2
GARBAGE_CAN = 3
VISITED_GARBAGE_CAN = 4

BIN
imgs/background.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

BIN
imgs/container.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 B

BIN
imgs/dust_car_down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
imgs/dust_car_left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

BIN
imgs/dust_car_right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

BIN
imgs/dust_car_up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

BIN
imgs/street_horizontal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

BIN
imgs/street_vertical.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

15
main.py
View File

@ -1,15 +1,17 @@
import pygame import pygame
from gameEventHandler import handle_game_event from gameEventHandler import handle_game_event
from gameContext import GameContext from gameContext import GameContext
from gameContext import startup from startup import startup
from PIL import Image from PIL import Image
from agentActionType import AgentActionType
from movement import move_dust_car
pygame.init() pygame.init()
canvas = pygame.display.set_mode((800, 800)) canvas = pygame.display.set_mode((800, 800))
pygame.display.set_caption("Inteligentna śmieciarka") pygame.display.set_caption("Inteligentna śmieciarka")
dust_car_pil = Image.open('imgs/dust_car.png') dust_car_pil = Image.open('imgs/dust_car_right.png')
game_context = GameContext() game_context = GameContext()
game_context.dust_car_pil = dust_car_pil game_context.dust_car_pil = dust_car_pil
@ -17,6 +19,14 @@ game_context.dust_car_pygame = pygame.image.frombuffer(dust_car_pil.tobytes(), d
game_context.canvas = canvas game_context.canvas = canvas
startup(game_context) 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 exit = False
@ -26,5 +36,4 @@ while not exit:
exit = True exit = True
else: else:
handle_game_event(event, game_context) handle_game_event(event, game_context)
pygame.display.update() pygame.display.update()

48
movement.py Normal file
View File

@ -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])

44
startup.py Normal file
View File

@ -0,0 +1,44 @@
from gameContext import GameContext
from city import City
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)
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")
pygame_bg_image = pygame.image.frombuffer(bg_img.tobytes(), bg_img.size, 'RGB')
game_context.canvas.blit(pygame_bg_image, (0, 0))
def create_city() -> City:
city: City = City()
streets = create_streets()
for s in streets:
city.add_street(s)
return city
def create_streets() -> List[Street]:
streets = []
streets.append(Street(3, 30, 3, StreetType.HORIZONTAL))
streets.append(Street(4, 15, 10, StreetType.VERTICAL))
streets.append(Street(4, 10, 25, StreetType.VERTICAL))
streets.append(Street(11, 24, 10, StreetType.HORIZONTAL))
streets.append(Street(4, 9, 18, StreetType.VERTICAL))
streets.append(Street(1, 30, 16, StreetType.HORIZONTAL))
streets.append(Street(17, 30, 2, StreetType.VERTICAL))
streets.append(Street(3, 25, 23, StreetType.HORIZONTAL))
streets.append(Street(17, 30, 13, StreetType.VERTICAL))
streets.append(Street(17, 23, 25, StreetType.VERTICAL))
return streets

27
street.py Normal file
View File

@ -0,0 +1,27 @@
from enum import Enum
from typing import Tuple
from gameContext import GameContext
from gridCellType import GridCellType
class StreetType (Enum):
VERTICAL = 0
HORIZONTAL = 1
class Street:
street_type: StreetType
start_cell: int
end_cell: int
row_or_column: int
def __init__(self, start_cell: int, end_cell: int, row_or_column: int, street_type: StreetType) -> None:
self.start_cell = start_cell
self.end_cell = end_cell
self.street_type = street_type
self.row_or_column = row_or_column
def render(self, game_context: GameContext) -> None:
for i in range(self.start_cell, self.end_cell + 1):
img_str: str = 'imgs/street_vertical.png' if self.street_type == StreetType.VERTICAL else 'imgs/street_horizontal.png'
cell: Tuple[int, int] = (self.row_or_column, i) if self.street_type == StreetType.VERTICAL else (i, self.row_or_column)
game_context.render_in_cell(cell, img_str)
game_context.grid[cell] = GridCellType.STREET_HORIZONTAL if self.street_type == StreetType.HORIZONTAL else GridCellType.STREET_VERTICAL

19
turnCar.py Normal file
View File

@ -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