-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit: Added the first version of the Natural Selection Simu…
…lation project This commit includes the initial setup of the project with the following structure: - \main.py\: Entry point of the program. Sets up the Pygame window, manages the main loop, and draws elements on the screen. - \constants.py\: Contains constants used throughout the project, such as sizes, colors, rates, and simulation parameters. - \ errain.py\: Responsible for drawing the terrain on the screen. - \organism.py\: Defines the Organism class, which represents the organisms in the simulation. Includes methods to move, eat, reproduce, and draw the organisms. - \utils.py\: Contains utility functions, such as creating food and drawing the organisms. - \�ssets\: Folder containing additional resources, such as font loading.
- Loading branch information
1 parent
c093bd9
commit 71bd8d5
Showing
9 changed files
with
537 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,118 @@ | ||
# natural-selection-simulation | ||
This project is a natural selection simulation using Pygame. Organisms move, reproduce, eat, and die in an environment with different terrain types, simulating evolution and adaptation. When reproducing, organisms pass their characteristics to offspring with variations, allowing evolution over time. | ||
# Natural Selection Simulation | ||
|
||
This project implements a natural selection simulation using the Pygame library. Organisms move, reproduce, eat, and eventually die in an environment with different types of terrain, simulating the basic principles of evolution and adaptation to the environment. When reproducing, organisms pass their characteristics to their offspring within a variation, allowing evolution over time. | ||
|
||
## Project Structure | ||
|
||
The project structure is organized as follows: | ||
|
||
``` | ||
natural-selection-simulation | ||
├── main.py | ||
├── constants.py | ||
├── terrain.py | ||
├── organism.py | ||
├── utils.py | ||
└── assets | ||
├── __init__.py | ||
└── font.py | ||
``` | ||
|
||
- `main.py`: Entry point of the program. Sets up the Pygame window, manages the main loop, and draws elements on the screen. | ||
- `constants.py`: Contains constants used throughout the project, such as sizes, colors, rates, and simulation parameters. | ||
- `terrain.py`: Responsible for drawing the terrain on the screen. | ||
- `organism.py`: Defines the Organism class, which represents the organisms in the simulation. Includes methods to move, eat, reproduce, and draw the organisms. | ||
- `utils.py`: Contains utility functions, such as creating food and drawing the organisms. | ||
- `assets`: Folder containing additional resources. In this case, it includes font loading. | ||
|
||
## Requirements | ||
|
||
- Python 3.x | ||
- Pygame | ||
|
||
## Installation | ||
|
||
1. Clone this repository: | ||
|
||
```sh | ||
git clone https://github.com/your-username/natural-selection-simulation.git | ||
``` | ||
|
||
2. Navigate to the project directory: | ||
|
||
```sh | ||
cd natural-selection-simulation | ||
``` | ||
|
||
3. Create a virtual environment (optional but recommended): | ||
|
||
```sh | ||
python -m venv venv | ||
source venv/bin/activate # Linux/Mac | ||
venv\Scripts\activate # Windows | ||
``` | ||
|
||
4. Install the dependencies: | ||
|
||
```sh | ||
pip install pygame | ||
``` | ||
|
||
## Running | ||
|
||
To run the project, use the following command: | ||
|
||
```sh | ||
python main.py | ||
``` | ||
|
||
## Functionality | ||
|
||
The simulation starts with an initial population of organisms that move randomly across the screen. They search for food, and upon finding it, consume it to gain energy. Organisms can reproduce and generate offspring with slightly modified characteristics. The simulation tracks and displays the maximum and minimum values of various organism characteristics over time. | ||
|
||
## Types of Terrain | ||
|
||
The simulation environment consists of three types of terrain: | ||
|
||
1. **Normal**: | ||
- Color: Light Gray `(169, 169, 169)` | ||
- Effect: Organisms lose energy at a normal rate when moving on this terrain. | ||
|
||
2. **Difficult**: | ||
- Color: Dark Gray `(105, 105, 105)` | ||
- Effect: Organisms lose energy at double the rate when moving on this terrain due to increased difficulty of movement. | ||
|
||
3. **Trap**: | ||
- Color: Black `(50, 50, 50)` | ||
- Effect: This terrain is dangerous for organisms. In addition to losing energy, they also lose health proportionally to their escape ability and speed. The lower the organism's escape ability and speed, the greater the damage suffered. | ||
|
||
Organisms adapt their behavior based on the type of terrain they encounter: | ||
|
||
- **Energy and Health Loss**: Moving through difficult and trap terrains increases the rate of energy loss and can decrease health, affecting the longevity and efficiency of organisms. | ||
|
||
## Customization | ||
|
||
You can adjust the simulation parameters in the `constants.py` file, such as mutation rate, food appearance intervals, and organism characteristics. | ||
|
||
## Contribution | ||
|
||
Contributions are welcome! Feel free to open issues or submit pull requests. | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License. See the `LICENSE` file for details. | ||
|
||
--- | ||
|
||
### Contact | ||
|
||
For questions or suggestions, contact: | ||
|
||
- Name: Itallo Nardi | ||
- Email: [email protected] | ||
|
||
--- | ||
|
||
### Acknowledgments | ||
|
||
Thank you for using this project! |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import pygame | ||
|
||
|
||
def load_font(): | ||
return pygame.font.Font(None, 16) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import pygame | ||
import sys | ||
import time | ||
import random | ||
from constants import WIDTH, HEIGHT, PANEL_WIDTH, BACKGROUND_COLOR, FPS, INITIAL_POPULATION, FOOD_APPEAR_INTERVAL, DEATH_ANIMATION_DURATION, record_highs, record_lows | ||
from terrain import draw_terrain | ||
from organism import Organism | ||
from utils import create_food | ||
from assets.font import load_font | ||
|
||
|
||
def draw_panel(screen, font, organism_count, food_count): | ||
panel_x = WIDTH | ||
pygame.draw.rect(screen, (50, 50, 50), (panel_x, 0, PANEL_WIDTH, HEIGHT)) | ||
|
||
text_lines = [ | ||
"Record Highs:", | ||
f"Speed: {record_highs['speed']:.2f}", | ||
f"Size: {record_highs['size']:.2f}", | ||
f"Energy Efficiency: {record_highs['energy_efficiency']:.2f}", | ||
f"Escape Ability: {record_highs['escape_ability']:.2f}", | ||
f"Recovery Ability: {record_highs['recovery_ability']:.2f}", | ||
f"Life Time: {record_highs['life_time']:.2f}", | ||
f"Organisms: {record_highs['max_organisms']}", | ||
f"Food: {record_highs['max_food']}", | ||
"", | ||
"Record Lows:", | ||
f"Speed: {record_lows['speed']:.2f}", | ||
f"Size: {record_lows['size']:.2f}", | ||
f"Energy Efficiency: {record_lows['energy_efficiency']:.2f}", | ||
f"Escape Ability: {record_lows['escape_ability']:.2f}", | ||
f"Recovery Ability: {record_lows['recovery_ability']:.2f}", | ||
f"Life Time: {record_lows['life_time']:.2f}", | ||
"", | ||
"Current Stats:", | ||
f"Current Organisms: {organism_count}", | ||
f"Current Food: {food_count}" | ||
] | ||
|
||
for i, line in enumerate(text_lines): | ||
text = font.render(line, True, (255, 255, 255)) | ||
screen.blit(text, (panel_x + 10, 10 + i * 20)) | ||
|
||
|
||
def main(): | ||
pygame.init() | ||
screen = pygame.display.set_mode((WIDTH + PANEL_WIDTH, HEIGHT)) | ||
clock = pygame.time.Clock() | ||
font = load_font() | ||
|
||
organisms = [Organism(random.randint(0, WIDTH), random.randint( | ||
0, HEIGHT), 2, 5, 0.5, 0.5, 0.1) for _ in range(INITIAL_POPULATION)] | ||
food_sources = [create_food() for _ in range(10)] | ||
last_food_time = pygame.time.get_ticks() | ||
|
||
while True: | ||
for event in pygame.event.get(): | ||
if event.type == pygame.QUIT: | ||
pygame.quit() | ||
sys.exit() | ||
|
||
screen.fill(BACKGROUND_COLOR) | ||
draw_terrain(screen) | ||
|
||
current_time = pygame.time.get_ticks() | ||
if current_time - last_food_time > FOOD_APPEAR_INTERVAL: | ||
food_sources.append(create_food()) | ||
last_food_time = current_time | ||
|
||
new_organisms = [] | ||
for organism in organisms: | ||
if organism.dead: | ||
if time.time() - organism.death_start_time > DEATH_ANIMATION_DURATION: | ||
continue # Skip dead organism after death animation | ||
else: | ||
organism.move(food_sources) | ||
organism.recover() | ||
if organism.energy <= 0 or organism.health <= 0: | ||
organism.die() | ||
continue | ||
for food in food_sources: | ||
if abs(organism.x - food[0]) < 5 and abs(organism.y - food[1]) < 5: | ||
organism.eat() | ||
food_sources.remove(food) | ||
break | ||
offspring = organism.reproduce() | ||
if offspring: | ||
new_organisms.append(offspring) | ||
new_organisms.append(organism) | ||
|
||
organisms = new_organisms | ||
organism_count = len(organisms) | ||
food_count = len(food_sources) | ||
|
||
record_highs['max_organisms'] = max( | ||
record_highs['max_organisms'], organism_count) | ||
record_highs['max_food'] = max(record_highs['max_food'], food_count) | ||
|
||
for organism in organisms: | ||
organism.draw(screen, font) | ||
|
||
for food in food_sources: | ||
pygame.draw.circle(screen, (255, 0, 0), food, 3) | ||
|
||
draw_panel(screen, font, organism_count, food_count) | ||
|
||
pygame.display.flip() | ||
clock.tick(FPS) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import pygame | ||
import sys | ||
import time | ||
from constants import DEATH_ANIMATION_DURATION, WIDTH, HEIGHT, PANEL_WIDTH, BACKGROUND_COLOR, FPS, INITIAL_POPULATION, FOOD_APPEAR_INTERVAL, record_highs | ||
from terrain import draw_terrain | ||
from organism import Organism | ||
from utils import create_food | ||
from assets.font import load_font | ||
import random | ||
|
||
|
||
def draw_panel(screen, font, organism_count, food_count): | ||
panel_x = WIDTH | ||
pygame.draw.rect(screen, (50, 50, 50), (panel_x, 0, PANEL_WIDTH, HEIGHT)) | ||
|
||
text_lines = [ | ||
"Record Highs:", | ||
f"Speed: {record_highs['speed']:.2f}", | ||
f"Size: {record_highs['size']:.2f}", | ||
f"Energy Efficiency: {record_highs['energy_efficiency']:.2f}", | ||
f"Escape Ability: {record_highs['escape_ability']:.2f}", | ||
f"Recovery Ability: {record_highs['recovery_ability']:.2f}", | ||
f"Life Time: {record_highs['life_time']:.2f}", | ||
f"Organisms: {record_highs['max_organisms']}", | ||
f"Food: {record_highs['max_food']}", | ||
"", | ||
"Current Stats:", | ||
f"Current Organisms: {organism_count}", | ||
f"Current Food: {food_count}" | ||
] | ||
|
||
for i, line in enumerate(text_lines): | ||
text = font.render(line, True, (255, 255, 255)) | ||
screen.blit(text, (panel_x + 10, 10 + i * 20)) | ||
|
||
|
||
def main(): | ||
pygame.init() | ||
screen = pygame.display.set_mode((WIDTH + PANEL_WIDTH, HEIGHT)) | ||
clock = pygame.time.Clock() | ||
font = load_font() | ||
|
||
organisms = [Organism(random.randint(0, WIDTH), random.randint( | ||
0, HEIGHT), 2, 5, 0.5, 0.5, 0.1) for _ in range(INITIAL_POPULATION)] | ||
food_sources = [create_food() for _ in range(10)] | ||
last_food_time = pygame.time.get_ticks() | ||
|
||
while True: | ||
for event in pygame.event.get(): | ||
if event.type == pygame.QUIT: | ||
pygame.quit() | ||
sys.exit() | ||
|
||
screen.fill(BACKGROUND_COLOR) | ||
draw_terrain(screen) | ||
|
||
current_time = pygame.time.get_ticks() | ||
if current_time - last_food_time > FOOD_APPEAR_INTERVAL: | ||
food_sources.append(create_food()) | ||
last_food_time = current_time | ||
|
||
new_organisms = [] | ||
for organism in organisms: | ||
if organism.dead: | ||
if time.time() - organism.death_start_time > DEATH_ANIMATION_DURATION: | ||
continue # Skip dead organism after death animation | ||
else: | ||
organism.move(food_sources) | ||
organism.recover() | ||
if organism.energy <= 0 or organism.health <= 0: | ||
organism.die() | ||
continue | ||
for food in food_sources: | ||
if abs(organism.x - food[0]) < 5 and abs(organism.y - food[1]) < 5: | ||
organism.eat() | ||
food_sources.remove(food) | ||
break | ||
offspring = organism.reproduce() | ||
if offspring: | ||
new_organisms.append(offspring) | ||
new_organisms.append(organism) | ||
|
||
organisms = new_organisms | ||
organism_count = len(organisms) | ||
food_count = len(food_sources) | ||
|
||
record_highs['max_organisms'] = max( | ||
record_highs['max_organisms'], organism_count) | ||
record_highs['max_food'] = max(record_highs['max_food'], food_count) | ||
|
||
for organism in organisms: | ||
organism.draw(screen, font) | ||
|
||
for food in food_sources: | ||
pygame.draw.circle(screen, (255, 0, 0), food, 3) | ||
|
||
draw_panel(screen, font, organism_count, food_count) | ||
|
||
pygame.display.flip() | ||
clock.tick(FPS) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.