Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ window:
panel:
width: 700
height: 700
x: 50
x: 100
y: 50
grid:
cell_size: 25
8 changes: 8 additions & 0 deletions src/area.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from enum import Enum
import food

class Area(Enum):
PLAINS = {"id": 1,
Expand Down Expand Up @@ -39,3 +40,10 @@ def __init__(self, config):
self.expansion_chance = config["expansion_chance"]
self.color = config["color"]
self.max_food_sources = config["max_food_sources"]

AREA_FOOD_SOURCE_MAPPING = {
Area.PLAINS: food.SimpleGrassPatch,
Area.FERTILE_VALLEY: food.FertileFruitTree,
Area.DESERT: food.CactusPads,
Area.BERRY_CORNER: food.BerryBush
}
57 changes: 54 additions & 3 deletions src/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import random
from typing import List, Tuple
import pygame
from food import SimpleGrassPatch, Food, BerryBush, FertileFruitTree, CactusPads
from food import FoodSource, SimpleGrassPatch, Food, BerryBush, FertileFruitTree, CactusPads
from agent import Agent
from area import Area
from terrain import generate_terrain
from typing import Type

class Environment:
"""
Expand All @@ -21,6 +22,7 @@ class Environment:
def __init__(self, grid_width: int, grid_height: int, pixel_width: int, pixel_height: int):
self.tick_counter = 0
self.running = True
self.pause_sim = False

self.grid_width = grid_width
self.grid_height = grid_height
Expand Down Expand Up @@ -56,6 +58,46 @@ def _create_empty_grid(self):
[0 for _ in range(self.grid_width)] for _ in range(self.grid_height)
]

def _cleanup_at(self, x: int, y: int):
"""Deletes food source and all food it has generated at location (x, y)."""
with self.data_lock:
for fs in self.food_sources:
if fs.x == x and fs.y == y:
fs.destroy()

self.food_sources = [fs for fs in self.food_sources if not fs.is_destroyed]

self.food_items = [f for f in self.food_items if not (f.x == x and f.y == y)]

def add_manual_food_source(self, grid_x: int, grid_y: int, source_type: Type[FoodSource]):
mapping = {
SimpleGrassPatch: Area.PLAINS,
BerryBush: Area.BERRY_CORNER,
FertileFruitTree: Area.FERTILE_VALLEY,
CactusPads: Area.DESERT
}

if source_type not in mapping:
return
cls, target_area = source_type, mapping[source_type]

self._cleanup_at(grid_x, grid_y)

with self.data_lock:
if 0 <= grid_x < self.grid_width and 0 <= grid_y < self.grid_height:
self.terrain[grid_y][grid_x] = target_area
new_source = cls(position=(grid_x, grid_y),
area=target_area,
env_area_counters=self.area_food_sources)
self.food_sources.append(new_source)
self.area_food_sources[target_area] += 1

def change_area_at(self, grid_x: int, grid_y: int, new_area: Area):
self._cleanup_at(grid_x, grid_y)

with self.data_lock:
if 0 <= grid_x < self.grid_width and 0 <= grid_y < self.grid_height:
self.terrain[grid_y][grid_x] = new_area
def is_food_source_at(self, x: int, y: int) -> bool:
"""Returns if food_source at location"""
return any(fs.x == x and fs.y == y and not fs.is_destroyed for fs in self.food_sources)
Expand Down Expand Up @@ -126,6 +168,10 @@ def _spawn_initial_agents(self):

def _simulation_loop(self):
while self.running:
time.sleep(0.01)

if self.pause_sim:
continue
with self.data_lock:
self.tick_counter += 1

Expand Down Expand Up @@ -176,7 +222,6 @@ def _simulation_loop(self):
agent.update(speed_modifier)
self._feed_agent(agent)

time.sleep(0.01)

def set_grid_cell(self, x: int, y: int, value: int):
if 0 <= x < self.grid_width and 0 <= y < self.grid_height:
Expand Down Expand Up @@ -225,9 +270,15 @@ def shutdown(self):
if self.simulation_thread.is_alive():
self.simulation_thread.join(timeout=1.0)

def pause(self):
self.pause_sim = True

def resume(self):
self.pause_sim = False

def get_agents(self):
return self.agents

#This function should deal with creating new agents
def create_agent(self, agent : Agent):
pass
Expand Down
29 changes: 27 additions & 2 deletions src/run.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
"""Main application entry point for the simulation."""
import pygame
import pygame_gui
from pygame_gui.elements import UIButton, UIPanel
import config
from environment import Environment

from area import Area
from food import FoodSource
from ui import UI

pygame.init()
pygame.display.set_caption("Simulation")
screen = pygame.display.set_mode((config.WINDOW_WIDTH, config.WINDOW_HEIGHT))

clock = pygame.time.Clock()

manager = pygame_gui.UIManager((config.WINDOW_WIDTH, config.WINDOW_HEIGHT))
env_ui = UI(
manager=manager,
x=config.PANEL_WIDTH + 2*config.PANEL_X,
y=0,
width=config.WINDOW_WIDTH - (config.PANEL_WIDTH + 2*config.PANEL_X),
height=config.WINDOW_HEIGHT
)

env = Environment(
grid_width=config.GRID_WIDTH,
Expand All @@ -23,13 +32,28 @@
running = True
while running:
dt = clock.tick(60) / 1000.0
mouse_pos = pygame.mouse.get_pos()

for event in pygame.event.get():
if event.type == pygame.QUIT:
env.shutdown()
running = False

if event.type == pygame.MOUSEBUTTONDOWN:
sim_rect = pygame.Rect(config.PANEL_X,
config.PANEL_Y,
config.PANEL_WIDTH,
config.PANEL_HEIGHT)
if sim_rect.collidepoint(mouse_pos):
grid_x = (mouse_pos[0] - config.PANEL_X) // config.CELL_SIZE
grid_y = (mouse_pos[1] - config.PANEL_Y) // config.CELL_SIZE
if env_ui.current_brush:
if isinstance(env_ui.current_brush, Area):
env.change_area_at(grid_x, grid_y, env_ui.current_brush)
elif isinstance(env_ui.current_brush, type(FoodSource)):
env.add_manual_food_source(grid_x, grid_y, env_ui.current_brush)
manager.process_events(event)
env_ui.process_events(event, env)

manager.update(dt)

Expand All @@ -43,6 +67,7 @@
)

manager.draw_ui(screen)

pygame.display.flip()

pygame.quit()
Loading
Loading