Adding a **Graphical User Interface (GUI)** to your agent simulation can make it more interactive and visually appealing. Both **Pygame** and **Tkinter** are popular Python libraries for creating GUIs, but they serve different purposes:
- **Pygame** is better suited for games and real-time visualizations.
- **Tkinter** is better for simple desktop applications with buttons, labels, and windows.
Since you're building a **mini-agent simulation game**, **Pygame** is likely the better choice for real-time visuals and interactivity.
---
## ✅ Using Pygame to Add a GUI
We'll extend the previous agent simulation and add a basic visual representation:
- Agents are shown as colored circles.
- Structures are shown as rectangles.
- Text is displayed for each agent's name and status.
---
### 🧱 Step-by-Step Overview
1. **Initialize Pygame** and set up the display.
2. **Draw agents** as colored circles.
3. **Draw structures** as rectangles.
4. **Display agent info** (name, job, energy).
5. Update the screen each simulation step.
---
### 🧠 Python Code with Pygame GUI
```python
import pygame
import random
import time
# Pygame initialization
pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mini Agent Simulation")
font = pygame.font.SysFont("Arial", 14)
clock = pygame.time.Clock()
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BLUE = (100, 100, 255)
GREEN = (100, 255, 100)
RED = (255, 100, 100)
class Agent:
def __init__(self, name, world, pos):
self.name = name
self.age = random.randint(18, 60)
self.job = random.choice(["Farmer", "Builder", "Teacher", "Doctor"])
self.home = None
self.location = "Town Center"
self.relationships = {}
self.energy = 100
self.world = world
self.pos = pos # (x, y) position on screen
self.color = (random.randint(100, 255), random.randint(100, 255), random.randint(100, 255))
def work(self):
print(f"{self.name} is working as a {self.job}.")
self.energy -= 10
def rest(self):
print(f"{self.name} is resting at home.")
self.energy += 20
def socialize(self):
other_agent = random.choice([a for a in self.world.agents if a != self])
print(f"{self.name} is talking with {other_agent.name}.")
self.relationships[other_agent.name] = self.relationships.get(other_agent.name, 0) + 1
def build(self, structure_type):
print(f"{self.name} is building a {structure_type}.")
self.world.add_structure(structure_type, self.name, self.pos)
self.energy -= 15
def decide_action(self):
if self.energy < 30:
self.rest()
elif random.random() < 0.3:
self.socialize()
elif random.random() < 0.2:
self.build(random.choice(["House", "School", "Clinic"]))
else:
self.work()
def draw(self, screen):
# Draw agent as a circle
pygame.draw.circle(screen, self.color, self.pos, 15)
# Draw name
name_text = font.render(self.name, True, BLACK)
screen.blit(name_text, (self.pos[0] - 20, self.pos[1] - 30))
# Draw energy
energy_text = font.render(f"{self.energy}", True, RED)
screen.blit(energy_text, (self.pos[0] - 5, self.pos[1] + 20))
class World:
def __init__(self):
self.agents = []
self.structures = []
def add_agent(self, agent):
self.agents.append(agent)
def add_structure(self, structure_type, built_by, pos):
self.structures.append({
"type": structure_type,
"built_by": built_by,
"pos": (pos[0], pos[1] + 50) # Offset so it doesn't overlap with agent
})
def draw(self, screen, font):
for s in self.structures:
rect = pygame.Rect(s["pos"][0], s["pos"][1], 40, 40)
pygame.draw.rect(screen, GREEN, rect)
label = font.render(s["type"], True, BLACK)
screen.blit(label, (s["pos"][0] - 10, s["pos"][1] - 20))
# Initialize World
world = World()
# Create Agents with random positions
names = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"]
positions = [(100, 100), (200, 150), (300, 100), (400, 200), (500, 150), (600, 100)]
agents = [Agent(name, world, pos) for name, pos in zip(names, positions)]
for a in agents:
world.add_agent(a)
# Simulation Loop
running = True
days = 10
day = 0
while running and day < days:
screen.fill(WHITE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Simulate day
print(f"\n=== Day {day + 1} ===")
for agent in agents:
agent.decide_action()
agent.draw(screen)
world.draw(screen, font)
pygame.display.flip()
clock.tick(1) # 1 frame per second (1 day per second)
day += 1
pygame.quit()
```
---
### 🧩 Code Explanation
- **Pygame Setup**: Initializes the screen, fonts, and colors.
- **Agent.draw()**: Draws each agent as a circle with their name and current energy.
- **World.draw()**: Draws structures as green rectangles with labels.
- **Simulation Loop**: Updates the screen each day and limits to 1 frame per second.
- **User Interaction**: Basic quit support with `pygame.QUIT`.
---
### ✅ Features You Can Add Next
- **Mouse click to select agent** and show detailed info.
- **Pathfinding** to move agents between locations.
- **Draggable camera** for larger maps.
- **Save/Load simulation state** using `pickle` or JSON.
- **Add more agent states** like health, hunger, happiness.
---
###