├── .DS_Store
├── assets
├── .DS_Store
├── fox.png
├── tree.png
├── wolf.png
├── rabbit.png
└── sources.txt
├── __pycache__
├── gui.cpython-312.pyc
├── settings.cpython-312.pyc
├── simulation.cpython-312.pyc
└── visualisation.cpython-312.pyc
├── main.py
├── settings.py
├── gui.py
├── visualisation.py
├── README.md
└── simulation.py
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/.DS_Store
--------------------------------------------------------------------------------
/assets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/assets/.DS_Store
--------------------------------------------------------------------------------
/assets/fox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/assets/fox.png
--------------------------------------------------------------------------------
/assets/tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/assets/tree.png
--------------------------------------------------------------------------------
/assets/wolf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/assets/wolf.png
--------------------------------------------------------------------------------
/assets/rabbit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/assets/rabbit.png
--------------------------------------------------------------------------------
/__pycache__/gui.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/__pycache__/gui.cpython-312.pyc
--------------------------------------------------------------------------------
/__pycache__/settings.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/__pycache__/settings.cpython-312.pyc
--------------------------------------------------------------------------------
/__pycache__/simulation.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/__pycache__/simulation.cpython-312.pyc
--------------------------------------------------------------------------------
/__pycache__/visualisation.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YPAndrew0907/Animal-Simulation-game/HEAD/__pycache__/visualisation.cpython-312.pyc
--------------------------------------------------------------------------------
/assets/sources.txt:
--------------------------------------------------------------------------------
1 | Fox :
2 | Fox icons created by Freepik - Flaticon
3 |
4 | Wolf :
5 | Wolf icons created by Freepik - Flaticon
6 |
7 | Rabbit :
8 | Rabbit icons created by Freepik - Flaticon
9 |
10 | Tree :
11 | Tree icons created by Freepik - Flaticon
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import pygame
2 | import simulation
3 | from settings import *
4 | from simulation import Simulation
5 | from visualisation import Visualisation
6 |
7 | pygame.init()
8 |
9 | simulation = Simulation()
10 | visualisation = Visualisation()
11 |
12 | if __name__ == "__main__":
13 | print("Press to run one step, press to run continuously")
14 | while True:
15 | visualisation.draw(simulation)
16 | keys_just_pressed = visualisation.events()
17 | keys_pressed = pygame.key.get_pressed()
18 | if keys_pressed[pygame.K_UP]:
19 | simulation.run_simulation_one_step()
20 | if pygame.K_SPACE in keys_just_pressed:
21 | simulation.run_simulation_one_step()
22 | visualisation.update()
23 |
--------------------------------------------------------------------------------
/settings.py:
--------------------------------------------------------------------------------
1 | from pygame import font
2 | # Screen
3 | WINDOW_NAME = "Nature simulation v1"
4 | VISUALISATION_WIDTH = 888
5 | VISUALISATION_HEIGHT = 888
6 | VISUALISATION_PANEL_WIDTH = 240
7 |
8 | # Constants for different entities
9 | TREE = '🌳'
10 | RABBIT = '🐇'
11 | FOX = '🦊'
12 | WOLF = '🐺'
13 | EMPTY = ' '
14 |
15 | # Grid dimensions
16 | WIDTH = 60
17 | HEIGHT = 60
18 |
19 | # Colors
20 | WHITE = (255, 255, 255)
21 | LIGHT_WHITE = (222, 222, 222)
22 | BLACK = (0, 0, 0)
23 | GREY = (83, 92, 104)
24 | ORANGE = (240, 147, 43)
25 | YELLOW = (249, 202, 36)
26 | GREEN = (106, 176, 76)
27 | LIGHT_GREEN = (186, 220, 88)
28 | LIGHT_BLUE = (126, 214, 223)
29 | DARK_BLUE = (48, 51, 107)
30 |
31 | # Fonts
32 | font.init()
33 | SMALL_FONT = font.SysFont("coopbl", 34)
34 | MEDIUM_FONT = font.SysFont("coopbl", 42)
35 | BIG_FONT = font.SysFont("coopbl", 52)
36 |
37 |
--------------------------------------------------------------------------------
/gui.py:
--------------------------------------------------------------------------------
1 | import pygame
2 | from settings import *
3 |
4 | def draw_text(surface, text, x, y, font=MEDIUM_FONT, color=WHITE, shadow=BLACK):
5 | text_obj = font.render(text, 1, color)
6 | if shadow:
7 | shadow_text_obj = font.render(text, 1, shadow)
8 | shadow_text_rect = shadow_text_obj.get_rect()
9 | shadow_text_rect.center = (x+2, y+2)
10 | surface.blit(shadow_text_obj, shadow_text_rect)
11 | text_rect = text_obj.get_rect()
12 | text_rect.center = (x, y)
13 | surface.blit(text_obj, text_rect)
14 |
15 | is_mouse_just_clicked = False
16 | def button(surface, text, x, y, font=BIG_FONT, width=160, height=60, color=LIGHT_WHITE,
17 | highlight_color=WHITE, text_color=BLACK, text_shadow=False, elevation=6, button_shadow=BLACK):
18 | global is_mouse_just_clicked
19 | rect = pygame.Rect(x-width//2, y-height//2, width, height)
20 | mouse_pos = pygame.mouse.get_pos()
21 | mouse_clicked = pygame.mouse.get_pressed()[0]
22 | if mouse_clicked == False:
23 | is_mouse_just_clicked = False
24 | draw_shadow = True
25 | if rect.collidepoint(mouse_pos):
26 | color = highlight_color
27 | if mouse_clicked and is_mouse_just_clicked == False:
28 | is_mouse_just_clicked = True
29 | return True
30 | if mouse_clicked:
31 | rect.x -= elevation
32 | rect.y -= elevation
33 | x -= elevation
34 | y -= elevation
35 | draw_shadow = False
36 | if draw_shadow:
37 | pygame.draw.rect(surface, button_shadow, (rect.x-elevation, rect.y-elevation, rect.w, rect.h), border_radius=16)
38 |
39 | pygame.draw.rect(surface, color, rect, border_radius=16)
40 | draw_text(surface, text, x, y, font, text_color, text_shadow)
41 |
--------------------------------------------------------------------------------
/visualisation.py:
--------------------------------------------------------------------------------
1 | import pygame
2 | import sys
3 | from settings import *
4 | import gui
5 |
6 | def load_image(path, width, height):
7 | image = pygame.image.load(path).convert_alpha()
8 | image = pygame.transform.smoothscale(image, (width, height))
9 | return image
10 |
11 | class Visualisation:
12 | def __init__(self):
13 | self.mainClock = pygame.time.Clock()
14 | self.SCREEN = pygame.display.set_mode((VISUALISATION_WIDTH + VISUALISATION_PANEL_WIDTH, VISUALISATION_HEIGHT), 0, 32)
15 | pygame.display.set_caption(WINDOW_NAME)
16 |
17 | self.cell_width = VISUALISATION_WIDTH // WIDTH
18 | self.cell_height = VISUALISATION_HEIGHT // HEIGHT
19 |
20 | # images
21 | self.tree_image = load_image("assets/tree.png", self.cell_width, self.cell_height)
22 | self.rabbit_image = load_image("assets/rabbit.png", self.cell_width//1.2, self.cell_height//1.2)
23 | self.fox_image = load_image("assets/fox.png", self.cell_width, self.cell_height)
24 | self.wolf_image = load_image("assets/wolf.png", self.cell_width, self.cell_height)
25 |
26 | self.transition_speed = 1000 # ms
27 | self.start_transition_time = 0
28 |
29 |
30 |
31 | def draw_panel(self, simulation):
32 | # draw the background
33 | pygame.draw.rect(self.SCREEN, DARK_BLUE, (VISUALISATION_WIDTH, 0, VISUALISATION_PANEL_WIDTH, VISUALISATION_HEIGHT))
34 | text_x_pos = VISUALISATION_WIDTH + VISUALISATION_PANEL_WIDTH // 2
35 | # draw the title
36 | gui.draw_text(self.SCREEN, WINDOW_NAME, text_x_pos, 50, font=SMALL_FONT, color=YELLOW)
37 | # draw the stats
38 | gui.draw_text(self.SCREEN, f"Step: {simulation.step}", text_x_pos, 150)
39 | pygame.draw.line(self.SCREEN, GREY, (VISUALISATION_WIDTH, 190), (VISUALISATION_WIDTH + VISUALISATION_PANEL_WIDTH, 190), 2)
40 | gui.draw_text(self.SCREEN, f"Trees: {len(simulation.trees)}", text_x_pos, 225, color=GREEN)
41 | gui.draw_text(self.SCREEN, f"Rabbits: {len(simulation.rabbits)}", text_x_pos, 260, color=WHITE)
42 | gui.draw_text(self.SCREEN, f"Foxes: {len(simulation.foxes)}", text_x_pos, 295, color=ORANGE)
43 | gui.draw_text(self.SCREEN, f"Wolves: {len(simulation.wolves)}", text_x_pos, 330, color=GREY)
44 | pygame.draw.line(self.SCREEN, GREY, (VISUALISATION_WIDTH, 370), (VISUALISATION_WIDTH + VISUALISATION_PANEL_WIDTH, 370), 2)
45 |
46 | # draw the buttons
47 | if gui.button(self.SCREEN, "Next", text_x_pos, 640):
48 | simulation.run_simulation_one_step()
49 | self.start_transition_time = pygame.time.get_ticks()
50 |
51 |
52 |
53 | def draw_simulation(self, simulation):
54 | pygame.draw.rect(self.SCREEN, LIGHT_GREEN, (0, 0, VISUALISATION_WIDTH, VISUALISATION_HEIGHT))
55 | for y in range(HEIGHT):
56 | for x in range(WIDTH):
57 | cell = simulation.grid[y][x]
58 | rect = pygame.rect.Rect(x * self.cell_width, y * self.cell_height, self.cell_width, self.cell_height)
59 | center_rect = rect.center
60 | if cell == TREE:
61 | # pygame.draw.rect(self.SCREEN, GREEN, rect)
62 | self.SCREEN.blit(self.tree_image, self.tree_image.get_rect(center=center_rect))
63 | pass
64 | elif cell == RABBIT:
65 | # pygame.draw.rect(self.SCREEN, WHITE, rect)
66 | self.SCREEN.blit(self.rabbit_image, self.rabbit_image.get_rect(center=center_rect))
67 | pass
68 | elif cell == FOX:
69 | # pygame.draw.rect(self.SCREEN, ORANGE, rect)
70 | self.SCREEN.blit(self.fox_image, self.fox_image.get_rect(center=center_rect))
71 | pass
72 | elif cell == WOLF:
73 | # pygame.draw.rect(self.SCREEN, GREY, rect)
74 | self.SCREEN.blit(self.wolf_image, self.wolf_image.get_rect(center=center_rect))
75 |
76 | def draw(self, simulation):
77 | self.draw_simulation(simulation)
78 | self.draw_panel(simulation)
79 |
80 |
81 | def events(self):
82 | keys_pressed = []
83 | for event in pygame.event.get():
84 | if event.type == pygame.QUIT:
85 | pygame.quit()
86 | sys.exit()
87 | if event.type == pygame.KEYDOWN:
88 | if event.key == pygame.K_ESCAPE:
89 | pygame.quit()
90 | sys.exit()
91 | keys_pressed.append(event.key)
92 | return keys_pressed
93 |
94 | def update(self):
95 | pygame.display.update()
96 | self.mainClock.tick(90)
97 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Animal Simulation Game - Enhanced Operation Instructions
2 |
3 | ## Introduction
4 |
5 | Welcome to **Animal Simulation Game**, where you can explore a dynamic ecosystem of interacting animals and enjoy learning about nature's complexity! This guide aims to provide you with detailed instructions on how to play the game, understand its controls, and enhance your simulation experience.
6 |
7 | ---
8 |
9 | ## Table of Contents
10 | 1. [Getting Started](#getting-started)
11 | 2. [Game Controls](#game-controls)
12 | - [Step-by-Step Simulation](#step-by-step-simulation)
13 | - [Continuous Simulation](#continuous-simulation)
14 | 3. [What Happens in the Simulation](#what-happens-in-the-simulation)
15 | 4. [In-Game Tooltips](#in-game-tooltips)
16 | 5. [Additional Resources](#additional-resources)
17 |
18 | ---
19 |
20 | ## Getting Started
21 |
22 | 1. **Installation**:
23 | - Ensure you have Python installed on your system.
24 | - Install the required dependencies by running:
25 | ```bash
26 | pip install -r requirements.txt
27 | ```
28 | - Start the game by running:
29 | ```bash
30 | python main.py
31 | ```
32 |
33 | 2. **Objective**:
34 | - Observe and interact with a simulation of animals such as rabbits, foxes, and wolves in a dynamically evolving ecosystem.
35 |
36 | ---
37 |
38 | ## Game Controls
39 |
40 | Here’s a detailed breakdown of how to control the simulation:
41 |
42 | ### Step-by-Step Simulation
43 | - **Key**: Press `SPACE`
44 | - **What It Does**: Advances the simulation by **one step**, during which:
45 | - Animals **move** to a new position based on their behavior and environment.
46 | - Predators like foxes and wolves may **hunt** nearby prey (e.g., rabbits).
47 | - Animals consume resources (e.g., food) and their **health** updates accordingly.
48 | - Reproductive events or population changes may occur depending on environmental factors.
49 |
50 | ### Continuous Simulation
51 | - **Key**: Press `ENTER`
52 | - **What It Does**: Runs the simulation **continuously** in real-time, where:
53 | - The ecosystem evolves without user intervention.
54 | - You can observe interactions like hunting, movement, and population dynamics seamlessly.
55 | - Animals will continue to move, eat, and reproduce until stopped.
56 | - **Stop Continuous Simulation**: Press `ENTER` again to pause the simulation.
57 |
58 | ### Other Controls
59 | - **Reset Simulation**: Press `R` to reset the game to its initial state.
60 | - **Exit Game**: Press `ESC` to close the game.
61 |
62 | ---
63 |
64 | ## What Happens in the Simulation
65 |
66 | Here’s what you can expect during gameplay:
67 |
68 | - **Animal Movement**:
69 | - Rabbits move randomly to find food and avoid predators.
70 | - Foxes and wolves hunt prey, using strategic movements.
71 | - **Hunting & Survival**:
72 | - Predators hunt nearby prey based on proximity and energy levels.
73 | - Prey animals may escape based on speed and surroundings.
74 | - **Reproduction**:
75 | - Animals reproduce when conditions are favorable (e.g., sufficient food and health).
76 | - **Population Dynamics**:
77 | - Watch as populations rise and fall based on the balance of predators and prey.
78 |
79 | ---
80 |
81 | ## In-Game Tooltips
82 |
83 | To assist new players, we’ve added **in-game tooltips**:
84 | - When you start the game, a popup explains the controls.
85 | - Tooltips display instructions like:
86 | - **"Press SPACE to advance the simulation step-by-step."**
87 | - **"Press ENTER to run the simulation continuously."**
88 |
89 | ---
90 |
91 | ## Additional Resources
92 |
93 | - **Video/GIF Demonstration**: Check out our [demo video](#) to see the simulation in action!
94 | - **FAQs**:
95 | - What is a simulation step?
96 | - A single moment in time where animals act based on their programmed behaviors.
97 | - How do I stop a continuous simulation?
98 | - Press `ENTER` again to pause.
99 |
100 | ---
101 |
102 | We hope these detailed instructions make the game more enjoyable and accessible for all players. If you have any questions or ideas, feel free to open an issue or contribute to the project!
103 |
104 | Happy Simulating! 😊
105 |
--------------------------------------------------------------------------------
/simulation.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 | import os
4 | import copy
5 | from collections import deque
6 | from settings import *
7 |
8 | class Simulation:
9 | def __init__(self):
10 |
11 |
12 | # Entity states
13 | self.rabbits = {} # Key: position (i, j), Value: hunger level
14 | self.foxes = {} # Key: position (i, j), Value: hunger level
15 | self.wolves = {} # Key: position (i, j), Value: hunger level
16 |
17 | self.trees = {} # Key: position (i, j), Value: regrowth timer
18 |
19 | self.grid = self.create_empty_grid(WIDTH, HEIGHT)
20 | self.populate_grid()
21 |
22 | self.step = 0
23 |
24 | def create_empty_grid(self, width, height):
25 | return [[EMPTY for _ in range(width)] for _ in range(height)]
26 |
27 | # Function to randomly populate the grid
28 | def populate_grid(self):
29 | # Place specific numbers of rabbits first
30 | placed_rabbits = 0
31 |
32 | while placed_rabbits < 1968:
33 | i, j = random.randint(0, HEIGHT - 1), random.randint(0, WIDTH - 1)
34 | if self.grid[i][j] == EMPTY:
35 | self.grid[i][j] = RABBIT
36 | self.rabbits[(i, j)] = 0 # Initial hunger level for rabbits
37 | placed_rabbits += 1
38 |
39 | # Now populate the rest of the grid randomly, including foxes and wolves
40 | # Make sure not to overwrite the rabbits you've already placed
41 | for i in range(HEIGHT):
42 | for j in range(WIDTH):
43 | if self.grid[i][j] == EMPTY:
44 | rand_num = random.random()
45 | if rand_num < 0.1:
46 | self.grid[i][j] = TREE
47 | elif rand_num < 0.12:
48 | self.grid[i][j] = FOX
49 | self.foxes[(i, j)] = 0 # Initial hunger level for foxes
50 | elif rand_num < 0.14:
51 | self.grid[i][j] = WOLF
52 | self.wolves[(i, j)] = 0 # Initial hunger level for wolves
53 |
54 |
55 | # Function to find nearest entity of a specific type
56 | def find_nearest(self, start_pos, entity_type):
57 | visited = set()
58 | queue = deque([start_pos])
59 |
60 | while queue:
61 | current_pos = queue.popleft()
62 | i, j = current_pos
63 |
64 | # Check if the current position is the target entity
65 | if self.grid[i][j] == entity_type:
66 | return current_pos
67 |
68 | # Add adjacent positions to the queue
69 | for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:
70 | if 0 <= x < HEIGHT and 0 <= y < WIDTH and (x, y) not in visited:
71 | visited.add((x, y))
72 | queue.append((x, y))
73 |
74 | # Return None if no entity found
75 | return None
76 |
77 | def reproduce_rabbits(self, position):
78 | # Check if the rabbit at the given position is not hungry
79 | if self.rabbits[position] == 0:
80 | # Find an adjacent empty cell for the new rabbit
81 | i, j = position
82 | adjacent_positions = [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]
83 | random.shuffle(adjacent_positions)
84 | for new_i, new_j in adjacent_positions:
85 | if 0 <= new_i < HEIGHT and 0 <= new_j < WIDTH and self.grid[new_i][new_j] == EMPTY:
86 | self.grid[new_i][new_j] = RABBIT
87 | self.rabbits[(new_i, new_j)] = 0 # New rabbit is not hungry
88 | break
89 |
90 |
91 |
92 | def move_rabbits(self):
93 | new_rabbits = {}
94 |
95 | for position in list(self.rabbits.keys()):
96 | i, j = position
97 |
98 | # Check if the rabbit still exists at this position
99 | if self.grid[i][j] != RABBIT:
100 | continue
101 |
102 | # Determine the movement of the rabbit
103 | new_positions = [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]
104 | random.shuffle(new_positions) # Randomize potential new positions
105 |
106 | moved = False
107 | for new_i, new_j in new_positions:
108 | if 0 <= new_i < HEIGHT and 0 <= new_j < WIDTH:
109 | if self.grid[new_i][new_j] == TREE:
110 | # Rabbit eats the tree and resets hunger
111 | self.rabbits[position] = 0
112 | self.grid[new_i][new_j] = RABBIT
113 | self.grid[i][j] = EMPTY
114 | new_rabbits[(new_i, new_j)] = self.rabbits[position]
115 | self.trees[(new_i, new_j)] = 3 # Set the regrowth timer for the tree
116 | moved = True
117 | break
118 | elif self.grid[new_i][new_j] == EMPTY:
119 | # Increase hunger if not eating
120 | self.rabbits[position] += 1
121 | self.grid[new_i][new_j] = RABBIT
122 | self.grid[i][j] = EMPTY
123 | new_rabbits[(new_i, new_j)] = self.rabbits[position]
124 | moved = True
125 | break
126 |
127 | # Reproduce if the rabbit has not moved and is not hungry
128 | if not moved:
129 | self.reproduce_rabbits(position)
130 |
131 | self.rabbits = new_rabbits
132 |
133 | def reproduce_rabbits(self, position):
134 | reproduction_hunger_threshold = 0 # Rabbits can reproduce when not hungry
135 |
136 | if self.rabbits.get(position, 0) <= reproduction_hunger_threshold:
137 | i, j = position
138 | adjacent_positions = [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]
139 |
140 | for new_i, new_j in adjacent_positions:
141 | if 0 <= new_i < HEIGHT and 0 <= new_j < WIDTH and self.grid[new_i][new_j] == EMPTY:
142 | self.grid[new_i][new_j] = RABBIT
143 | self.rabbits[(new_i, new_j)] = 0 # New rabbit is not hungry
144 |
145 |
146 | def is_closer(self, pos1, pos2, reference):
147 | """ Check if pos1 is closer to the reference point than pos2. """
148 | return self.distance(pos1, reference) < self.distance(pos2, reference)
149 |
150 | def distance(self, pos1, pos2):
151 | """ Calculate exact distance between two points. """
152 | return ((pos1[0] - pos2[0])**2 + (pos1[1] - pos2[1])**2)**0.5
153 |
154 |
155 |
156 | def regrow_trees(self):
157 | trees_to_regrow = []
158 | for position, timer in self.trees.items():
159 | if timer > 0:
160 | self.trees[position] -= 1
161 | elif self.trees[position] == 0:
162 | # only regrow if the cell is empty
163 | if self.grid[position[0]][position[1]] == EMPTY:
164 | trees_to_regrow.append(position)
165 |
166 | for position in trees_to_regrow:
167 | i, j = position
168 | self.grid[i][j] = TREE
169 | del self.trees[position] # Remove the tree from the regrowth tracking
170 |
171 |
172 | def move_foxes(self):
173 | new_foxes = {}
174 | for position in list(self.foxes.keys()):
175 | i, j = position
176 |
177 | # Check if the fox still exists at this position
178 | if self.grid[i][j] != FOX:
179 | continue
180 |
181 | # Implement smarter hunting behavior
182 | nearest_rabbit = self.find_nearest(position, RABBIT)
183 |
184 | # Determine the best move for hunting
185 | if nearest_rabbit:
186 | best_move = None
187 | min_distance = float('inf')
188 | for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:
189 | if 0 <= x < HEIGHT and 0 <= y < WIDTH and self.grid[x][y] in [EMPTY, RABBIT]:
190 | dist = self.distance((x, y), nearest_rabbit)
191 | if dist < min_distance:
192 | min_distance = dist
193 | best_move = (x, y)
194 |
195 | if best_move:
196 | new_i, new_j = best_move
197 | if self.grid[new_i][new_j] == RABBIT:
198 | self.foxes[position] = 0 # Reset hunger
199 | # Remove the eaten rabbit
200 | self.rabbits.pop(nearest_rabbit, None)
201 | else:
202 | self.foxes[position] += 1 # Increase hunger
203 |
204 | self.grid[i][j] = EMPTY
205 | self.grid[new_i][new_j] = FOX
206 | new_foxes[best_move] = self.foxes[position]
207 | else:
208 | # Move randomly if no rabbit is within range
209 | random_move = random.choice([(i-1, j), (i+1, j), (i, j-1), (i, j+1)])
210 | if 0 <= random_move[0] < HEIGHT and 0 <= random_move[1] < WIDTH and self.grid[random_move[0]][random_move[1]] == EMPTY:
211 | self.grid[i][j] = EMPTY
212 | self.grid[random_move[0]][random_move[1]] = FOX
213 | new_foxes[random_move] = self.foxes[position]
214 | else:
215 | # Move randomly if no rabbit is found
216 | random_move = random.choice([(i-1, j), (i+1, j), (i, j-1), (i, j+1)])
217 | if 0 <= random_move[0] < HEIGHT and 0 <= random_move[1] < WIDTH and self.grid[random_move[0]][random_move[1]] == EMPTY:
218 | self.grid[i][j] = EMPTY
219 | self.grid[random_move[0]][random_move[1]] = FOX
220 | new_foxes[random_move] = self.foxes[position]
221 |
222 | self.foxes = new_foxes
223 |
224 | def move_wolves(self):
225 | new_wolves = {}
226 | for position in list(self.wolves.keys()):
227 | i, j = position
228 |
229 | # Check if the wolf still exists at this position
230 | if self.grid[i][j] != WOLF:
231 | continue
232 | # Find nearest rabbit and fox
233 | nearest_rabbit = self.find_nearest(position, RABBIT)
234 | nearest_fox = self.find_nearest(position, FOX)
235 | # Determine the closest prey
236 | nearest_prey = None
237 | if nearest_rabbit and nearest_fox:
238 | if self.is_closer(nearest_rabbit, nearest_fox, position):
239 | nearest_prey = nearest_rabbit
240 | else:
241 | nearest_prey = nearest_fox
242 | elif nearest_rabbit:
243 | nearest_prey = nearest_rabbit
244 | elif nearest_fox:
245 | nearest_prey = nearest_fox
246 |
247 | # Move towards the nearest prey
248 | new_positions = []
249 | if nearest_prey:
250 | for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:
251 | if 0 <= x < HEIGHT and 0 <= y < WIDTH and self.grid[x][y] in [EMPTY, RABBIT, FOX]:
252 | if self.is_closer((x, y), position, nearest_prey):
253 | new_positions.append((x, y))
254 | # Move wolf if possible
255 | if new_positions:
256 | new_pos = random.choice(new_positions)
257 | new_i, new_j = new_pos
258 |
259 | # Eat prey if present
260 | if self.grid[new_i][new_j] in [RABBIT, FOX]:
261 | self.wolves[position] = 0 # Reset hunger
262 | else:
263 | self.wolves[position] += 1 # Increase hunger
264 |
265 | self.grid[i][j] = EMPTY
266 | self.grid[new_i][new_j] = WOLF
267 | new_wolves[new_pos] = self.wolves[position]
268 | else: # the wolf can't move
269 | new_wolves[position] = self.wolves[position]
270 | self.wolves = new_wolves
271 |
272 | def display_grid(self):
273 | os.system('cls' if os.name == 'nt' else 'clear') # Clear the console for each new display
274 | for row in self.grid:
275 | print(' '.join(row))
276 | print("\nSimulation Step Completed. Press Ctrl+C to stop.")
277 |
278 | def run_simulation_one_step(self):
279 |
280 | self.move_rabbits()
281 | self.move_foxes()
282 | self.move_wolves()
283 | self.regrow_trees()
284 | # self.display_grid()
285 | self.step += 1
286 |
287 |
288 | # if __name__ == "__main__":
289 | # run_simulation()
290 |
--------------------------------------------------------------------------------