diff --git a/res/map.txt b/res/map.txt index 795a6cf..232d116 100644 --- a/res/map.txt +++ b/res/map.txt @@ -1,13 +1,14 @@ -LRRRRRRRRRRRRRRRRR---R--- ----R------R------R---RRR- ----R------R------R---R--- -RRRR------RRRRRRRRRRRR--- -R--R-------------R------- -R--RRRRRRRRRRRRRRRH------ -R--R---R---R-----R------- -R--R---R---R-----RRRRRRR- -R--R-------------R------- -R--R-----R----R--R------- -R--R-----R----R--R------- -RRRRRRRRRRRRRRRRRRRRRRR-- -------------------------- \ No newline at end of file +MP------------------------ +ORRRRRRRRRRRRRRRRRR---R--- +SZ--R------R------R---RRR- +----R------R------R---R--- +-RRRR------RRRRRRRRRRRR--- +-R--R-------------R------- +-R--RRRRRRRRRRRRRRRH------ +-R--R---R---RH----R------- +-R--R---R---RH----RRRRRRR- +-R--R-------H-----R------- +-R--R-----R----R--R------- +-R--R-----R----R--R------- +-RRRRRRRRRRRRRRRRRRRRRRR-- +-------------------------- \ No newline at end of file diff --git a/res/tiles.png b/res/tiles.png index bebcfc0..8ff64a6 100644 Binary files a/res/tiles.png and b/res/tiles.png differ diff --git a/src/agent.py b/src/agent.py new file mode 100644 index 0000000..164815d --- /dev/null +++ b/src/agent.py @@ -0,0 +1,6 @@ +class Agent: + def __init__(self): + graph = [] + + def inform(self, coordinate_set): + pass diff --git a/src/main.py b/src/main.py index 571d486..7956d3b 100644 --- a/src/main.py +++ b/src/main.py @@ -1,191 +1,7 @@ -from pathlib import Path -import pygame as pg -from random import randint +from simulation import * +from agent import * - -class Entity: - def __init__(self, state, position, tile): - self.state = state - self.position = position - self.tile = tile - - def move(self, move_vector): - raise NotImplementedError() - - -class Agent(Entity): - def move(self, move_vector): - proposed_pos = self.position + move_vector - move_valid = True - - if proposed_pos != self.state.landfill_pos and proposed_pos not in self.state.roads_pos: - move_valid = False - if proposed_pos.x < 0 or proposed_pos.x >= self.state.world_limits.x: - move_valid = False - if proposed_pos.y < 0 or proposed_pos.y >= self.state.world_limits.y: - move_valid = False - - if move_valid: - self.position = proposed_pos - - -class SimulationState: - def __init__(self): - self.landfill_pos = [] - self.roads_pos = [] - self.houses_pos = [] - - map_path = Path("../res/map.txt") - with open(map_path, "r") as map_file: - map_data = map_file.readlines() - max_x = len(map_data[0].replace('\n', '')) - max_y = len(map_data) - for y in range(0, max_y): - for x in range(0, max_x): - tile = map_data[y].replace('\n', '')[x] - - if tile == "L": - self.landfill_pos.append(pg.Vector2(x, y)) - if tile == "R": - self.roads_pos.append(pg.Vector2(x, y)) - if tile == "H": - self.houses_pos.append(pg.Vector2(x, y)) - self.world_limits = pg.Vector2(max_x, max_y) - - self.entities = [Agent(self, self.landfill_pos[0], pg.Vector2(2, 0))] - - def update(self, move_agent): - for entity in self.entities: - entity.move(move_agent) - - -class Layer: - def __init__(self, sim, texture_file): - self.sim = sim - self.texture_atlas = pg.image.load(texture_file) - - def renderTile(self, surface, position, tile): - # pozycja na ekranie - sprite_pos = position.elementwise() * self.sim.cell_size - - # tekstura - pos_in_atlas = tile.elementwise() * self.sim.cell_size - texture = pg.Rect(int(pos_in_atlas.x), - int(pos_in_atlas.y), - self.sim.cell_size.x, - self.sim.cell_size.y) - - # render - surface.blit(self.texture_atlas, sprite_pos, texture) - - def render(self, surface): - raise NotImplementedError() - - -class EntityLayer(Layer): - def __init__(self, sim, texture_file, simulation_state, entities): - super().__init__(sim, texture_file) - self.simulation_state = simulation_state - self.entities = entities - - def render(self, surface): - for entity in self.entities: - self.renderTile(surface, entity.position, entity.tile) - - -class StructureLayer(Layer): - def __init__(self, sim, texture_file, simulation_state, structures_pos, tile): - super().__init__(sim, texture_file) - self.simulation_state = simulation_state - self.structures_pos = structures_pos - self.tile = tile - - def render(self, surface): - for position in self.structures_pos: - self.renderTile(surface, position, self.tile) - - -class Interface: - def __init__(self): - pg.init() - - # stan symulacji - self.simulation_state = SimulationState() - self.move_agent = pg.Vector2(0, 0) - - # rendering - self.cell_size = pg.Vector2(64, 64) - texture_file = Path("../res/tiles.png") - self.layers = [StructureLayer(self, texture_file, self.simulation_state, self.simulation_state.landfill_pos, pg.Vector2(3, 0)), - StructureLayer(self, texture_file, self.simulation_state, self.simulation_state.roads_pos, pg.Vector2(0, 0)), - StructureLayer(self, texture_file, self.simulation_state, self.simulation_state.houses_pos, pg.Vector2(1, 0)), - EntityLayer(self, texture_file, self.simulation_state, self.simulation_state.entities)] - - # okno - pg.display.set_caption("Inteligentna śmieciarka") - window_size = self.simulation_state.world_limits.elementwise() * self.cell_size - self.window = pg.display.set_mode((int(window_size.x), int(window_size.y))) - self.simulation_state.world_limits.elementwise() * self.cell_size - - # dla pętli - self.clock = pg.time.Clock() - self.run_simulation = True - - self.debug_mode = False - - def processUserInput(self): - self.move_agent = pg.Vector2(0, 0) - - for event in pg.event.get(): - if event.type == pg.QUIT: - self.run_simulation = False - break - elif event.type == pg.KEYDOWN: - if event.key == pg.K_ESCAPE: - self.run_simulation = False - break - if event.key == pg.K_BACKQUOTE: - self.debug_mode = not self.debug_mode - - if self.debug_mode: - if event.key == pg.K_RIGHT: - self.move_agent.x = 1 - if event.key == pg.K_LEFT: - self.move_agent.x = -1 - if event.key == pg.K_DOWN: - self.move_agent.y = 1 - if event.key == pg.K_UP: - self.move_agent.y = -1 - - def processSimulationInput(self): - moves = [pg.Vector2(-1, 0), pg.Vector2(1, 0), pg.Vector2(0, -1), pg.Vector2(0, 1)] - - self.move_agent = moves[randint(0,3)] - - def update(self): - self.simulation_state.update(self.move_agent) - - def render(self): - if not self.debug_mode: - self.window.fill((8, 68, 0)) - else: - self.window.fill((68, 8, 0)) - - for layer in self.layers: - layer.render(self.window) - - pg.display.update() - - def loop(self): - while self.run_simulation: - self.processUserInput() - if not self.debug_mode: - self.processSimulationInput() - self.update() - self.render() - self.clock.tick(24) - pg.quit() - - -simulation = Interface() -simulation.loop() +if __name__ == "__main__": + agent = Agent() + simulation = Interface(agent) + simulation.loop() diff --git a/src/simulation.py b/src/simulation.py new file mode 100644 index 0000000..4318ccf --- /dev/null +++ b/src/simulation.py @@ -0,0 +1,237 @@ +from pathlib import Path +import pygame as pg +from random import randint + +ROAD_SPRITE = pg.Vector2(0, 0) + +HOUSE_WITHOUT_TRASH_SPRITE = pg.Vector2(1, 0) +HOUSE_WITH_TRASH_SPRITE = pg.Vector2(1, 1) +HOUSE_SPRITES = {0: HOUSE_WITHOUT_TRASH_SPRITE, + 1: HOUSE_WITH_TRASH_SPRITE} + +TRUCK_SPRITE = pg.Vector2(2, 0) + +PAPER_DUMP_SPRITE = pg.Vector2(3, 0) +PLASTIC_DUMP_SPRITE = pg.Vector2(3, 1) +GLASS_DUMP_SPRITE = pg.Vector2(3, 2) +MIXED_DUMP_SPRITE = pg.Vector2(3, 3) +DUMP_SPRITES = {'paper': PAPER_DUMP_SPRITE, + 'glass': GLASS_DUMP_SPRITE, + 'plastic': PLASTIC_DUMP_SPRITE, + 'mixed': MIXED_DUMP_SPRITE} + + +class Entity: + def __init__(self, state, position): + self.state = state + self.position = position + + +class TruckEntity(Entity): + def __init__(self, state, position): + super().__init__(state, position) + self.tile = TRUCK_SPRITE + + def move(self, move_vector): + proposed_pos = self.position + move_vector + move_valid = True + + if proposed_pos not in self.state.roads_pos: + move_valid = False + if proposed_pos.x < 0 or proposed_pos.x >= self.state.world_limits.x: + move_valid = False + if proposed_pos.y < 0 or proposed_pos.y >= self.state.world_limits.y: + move_valid = False + + if move_valid: + self.position = proposed_pos + + +class HouseEntity(Entity): + def __init__(self, state, position): + super().__init__(state, position) + self.tile = HOUSE_SPRITES[0] + + +class DumpEntity(Entity): + def __init__(self, state, position, trash_type): + super().__init__(state, position) + self.tile = DUMP_SPRITES[trash_type] + + +class SimulationState: + def __init__(self): + self.roads_pos = [] + self.houses_pos = [] + self.entities = [] + + map_path = Path("../res/map.txt") + with open(map_path, "r") as map_file: + map_data = map_file.readlines() + max_x = len(map_data[0].replace('\n', '')) + max_y = len(map_data) + for y in range(0, max_y): + for x in range(0, max_x): + tile = map_data[y].replace('\n', '')[x] + + if tile == "O": + self.truck_origin = pg.Vector2(x, y) + self.entities.append(TruckEntity(self, self.truck_origin)) + self.roads_pos.append(pg.Vector2(x, y)) + if tile == "R": + self.roads_pos.append(pg.Vector2(x, y)) + if tile == "H": + self.houses_pos.append(pg.Vector2(x, y)) + self.entities.append(HouseEntity(self, pg.Vector2(x, y))) + if tile == "M": + self.paper_dump_pos = pg.Vector2(x, y) + self.entities.append(DumpEntity(self, pg.Vector2(x, y), 'paper')) + if tile == "P": + self.plastic_dump_pos = pg.Vector2(x, y) + self.entities.append(DumpEntity(self, pg.Vector2(x, y), 'plastic')) + if tile == "S": + self.glass_dump_pos = pg.Vector2(x, y) + self.entities.append(DumpEntity(self, pg.Vector2(x, y), 'glass')) + if tile == "Z": + self.mixed_dump_pos = pg.Vector2(x, y) + self.entities.append(DumpEntity(self, pg.Vector2(x, y), 'mixed')) + + self.world_limits = pg.Vector2(max_x, max_y) + + def update(self, move_agent): + for entity in self.entities: + if entity.__class__ is TruckEntity: + entity.move(move_agent) + break + + +class Layer: + def __init__(self, sim, texture_file): + self.sim = sim + self.texture_atlas = pg.image.load(texture_file) + + def renderTile(self, surface, position, tile): + # pozycja na ekranie + sprite_pos = position.elementwise() * self.sim.cell_size + + # tekstura + pos_in_atlas = tile.elementwise() * self.sim.cell_size + texture = pg.Rect(int(pos_in_atlas.x), + int(pos_in_atlas.y), + self.sim.cell_size.x, + self.sim.cell_size.y) + + # render + surface.blit(self.texture_atlas, sprite_pos, texture) + + def render(self, surface): + raise NotImplementedError() + + +class EntityLayer(Layer): + def __init__(self, sim, texture_file, simulation_state, entities): + super().__init__(sim, texture_file) + self.simulation_state = simulation_state + self.entities = entities + + def render(self, surface): + for entity in self.entities: + self.renderTile(surface, entity.position, entity.tile) + + +class StructureLayer(Layer): + def __init__(self, sim, texture_file, simulation_state, structures_pos, tile): + super().__init__(sim, texture_file) + self.simulation_state = simulation_state + self.structures_pos = structures_pos + self.tile = tile + + def render(self, surface): + for position in self.structures_pos: + self.renderTile(surface, position, self.tile) + + +class Interface: + def __init__(self, agent): + pg.init() + + # autonomiczny agent + self.agent = agent + + # stan symulacji + self.simulation_state = SimulationState() + self.move_agent = pg.Vector2(0, 0) + + # rendering + self.cell_size = pg.Vector2(64, 64) + texture_file = Path("../res/tiles.png") + self.layers = [StructureLayer(self, texture_file, self.simulation_state, + self.simulation_state.roads_pos, ROAD_SPRITE), + EntityLayer(self, texture_file, self.simulation_state, + self.simulation_state.entities)] + + # okno + pg.display.set_caption("Inteligentna śmieciarka") + window_size = self.simulation_state.world_limits.elementwise() * self.cell_size + self.window = pg.display.set_mode((int(window_size.x), int(window_size.y))) + self.simulation_state.world_limits.elementwise() * self.cell_size + + # dla pętli + self.clock = pg.time.Clock() + self.run_simulation = True + + self.debug_mode = False + + def processUserInput(self): + self.move_agent = pg.Vector2(0, 0) + + for event in pg.event.get(): + if event.type == pg.QUIT: + self.run_simulation = False + break + elif event.type == pg.KEYDOWN: + if event.key == pg.K_ESCAPE: + self.run_simulation = False + break + if event.key == pg.K_BACKQUOTE: + self.debug_mode = not self.debug_mode + + if self.debug_mode: + if event.key == pg.K_RIGHT: + self.move_agent.x = 1 + if event.key == pg.K_LEFT: + self.move_agent.x = -1 + if event.key == pg.K_DOWN: + self.move_agent.y = 1 + if event.key == pg.K_UP: + self.move_agent.y = -1 + + def processAgentInput(self): + moves = [pg.Vector2(-1, 0), pg.Vector2(1, 0), pg.Vector2(0, -1), pg.Vector2(0, 1)] + + self.move_agent = moves[randint(0, 3)] + + def update(self): + self.simulation_state.update(self.move_agent) + + def render(self): + if not self.debug_mode: + self.window.fill((89, 183, 53)) + else: + self.window.fill((180, 32, 42)) + + for layer in self.layers: + layer.render(self.window) + + pg.display.update() + + def loop(self): + self.agent.inform(set()) + while self.run_simulation: + self.processUserInput() + if not self.debug_mode: + self.processAgentInput() + self.update() + self.render() + self.clock.tick(24) + pg.quit()