Skip to content

Commit

Permalink
Initial commit: Added the first version of the Natural Selection Simu…
Browse files Browse the repository at this point in the history
…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
itallonardi committed Jul 25, 2024
1 parent c093bd9 commit 71bd8d5
Show file tree
Hide file tree
Showing 9 changed files with 537 additions and 2 deletions.
120 changes: 118 additions & 2 deletions README.md
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 added assets/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions assets/font.py
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)
112 changes: 112 additions & 0 deletions constants.py
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()
104 changes: 104 additions & 0 deletions main.py
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()
Loading

0 comments on commit 71bd8d5

Please sign in to comment.