-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimulation.py
More file actions
158 lines (131 loc) · 4.71 KB
/
Copy pathsimulation.py
File metadata and controls
158 lines (131 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from time import sleep
from typing import TYPE_CHECKING
from actions.init import PopulateMapAction
from actions.turn import (
ApplyHungerAction,
MoveCreaturesAction,
SpawnGrassAction,
)
from config import config
from rendering import MapRenderer
from utils.menu import (
show_pause_menu,
show_step_menu,
)
if TYPE_CHECKING:
from world import Map
class Simulation:
def __init__(self, world_map: "Map") -> None:
self.world_map = world_map
self.init_actions = [PopulateMapAction()]
self.turn_actions = [
MoveCreaturesAction(),
ApplyHungerAction(),
SpawnGrassAction(),
]
self.turn_count = 0
self._is_stopped = False
def start_simulation(self, mode: str) -> None:
"""
Start the simulation in the specified mode.
Args:
mode: Simulation mode - "step" for step-by-step,
"auto" for automatic
"""
for action in self.init_actions:
action.execute(self.world_map)
MapRenderer.render_frame(self.world_map, self.turn_count)
if mode == "step":
self._run_step_mode()
elif mode == "auto":
self._run_auto_mode()
print("\n=== Simulation end ===\n")
if self._is_stopped:
print("Simulation stopped by user.")
else:
print(self._get_simulation_end_message())
def next_turn(self, with_delay: bool = True) -> None:
"""
Execute the next turn of the simulation.
Args:
with_delay: Whether to wait for a delay before the next turn
"""
self.turn_count += 1
if with_delay:
sleep(config.turn_delay)
for action in self.turn_actions:
action.execute(self.world_map)
MapRenderer.render_frame(self.world_map, self.turn_count)
def stop(self) -> None:
"""Stop the simulation."""
self._is_stopped = True
@staticmethod
def _show_step_menu() -> str:
"""Show the step mode menu and get user choice."""
return show_step_menu()
@staticmethod
def _show_pause_menu() -> str:
"""Show the pause menu and get user choice."""
return show_pause_menu()
@property
def _is_running(self) -> bool:
"""Check if the simulation should continue running."""
return not self._is_stopped and self._is_simulation_running
def _run_step_mode(self) -> None:
"""Run simulation in step-by-step mode with user control."""
while self._is_running:
choice = self._show_step_menu()
if choice in {"1", ""}:
self.next_turn(with_delay=False)
elif choice == "2":
self.stop()
break
else:
print("Invalid choice. Please try again.")
def _run_auto_mode(self) -> None:
"""Run simulation in automatic mode with pause capability."""
print("\n[AUTOMATIC MODE] Simulation started.")
print("Press Ctrl+C to pause and control.")
self._run_simulation_loop()
def _run_simulation_loop(self) -> None:
"""
Run the main simulation loop
with keyboard interrupt handling for pausing.
"""
try:
while self._is_running:
self.next_turn(with_delay=True)
except KeyboardInterrupt:
self._handle_pause_menu()
def _handle_pause_menu(self) -> None:
"""Handle the pause menu and user choices."""
while True:
choice = self._show_pause_menu()
if choice == "1":
print("\n[CONTINUE] Simulation resumed.")
print("Press Ctrl+C to pause and control.")
self._run_simulation_loop()
break
elif choice == "2":
print("\n[STOP] Simulation stopped.")
self.stop()
break
else:
print("Invalid choice. Please try again.")
@property
def _is_simulation_running(self) -> bool:
"""
Check if simulation conditions are met to continue.
Returns:
True if both herbivores and predators exist, False otherwise
"""
herbivores, predators = self.world_map.get_creatures_count()
return herbivores > 0 and predators > 0
def _get_simulation_end_message(self) -> str:
"""Get appropriate simulation end message based on final state."""
herbivores, predators = self.world_map.get_creatures_count()
if herbivores == 0:
return "All herbivores died. Predators won!"
if predators == 0:
return "All predators died. Herbivores survived!"
return "Simulation completed."