This repository contains a Darwin World simulation implemented in Java. It models a complex ecosystem where animals roam a map, consume plants to gain energy, reproduce based on their health, and evolve over generations. The project demonstrates core Object-Oriented Programming principles and features a dynamic graphical user interface built with JavaFX to visualize the simulation and track statistics in real-time.
Reflecting on the architecture of the project, we have employed several design patterns to ensure modularity, maintainability, and clear separation of concerns:
-
Builder Pattern: Simplifies object creation.
- Used in the
Animalclass via theSpawnerstatic inner class. This allows for fluent configuration of an animal's initial state (position, energy, genotype, etc.) before spawning it into the world. It makes the instantiation code much more readable, especially given the number of parameters involved.
- Used in the
-
Facade Pattern: Simplifies interaction with complex subsystems.
- The
Simulationclass acts as a facade for the simulation logic. It encapsulates the complex operations of a single day (moving animals, eating, breeding, growing plants) into a cohesive interface. TheSimulationEngineinteracts with this facade rather than managing individual ecosystem details.
- The
-
Delegation (Composition over Inheritance): Favoring object composition.
- We favor delegation over inheritance in several places. For example,
Simulationdelegates movement logic and boundary checks to the specificWorldMapimplementation. This allows the simulation behavior to remain consistent while the map rules can vary independently.
- We favor delegation over inheritance in several places. For example,
-
SOLID Principles:
- Single Responsibility Principle (SRP): Classes are designed with a single focus. For example,
Genotypehandles only DNA logic,MapRendereris solely responsible for drawing the map, andStatisticsSaverdeals exclusively with CSV export. - Open/Closed Principle (OCP): The system is open for extension but closed for modification. The
WorldMapinterface allows for different map implementations (likeClassicMap) to be plugged into the simulation without rewriting the coreSimulationlogic. - Liskov Substitution Principle (LSP): Subtypes must be substitutable for their base types.
FastAnimalcan be used whereverAnimalis expected, andClassicMapcan be used whereverAbstractWorldMaporWorldMapis expected, without breaking the simulation. - Interface Segregation Principle (ISP): Interfaces like
MoveValidatorandMapChangeListenerare specific and focused. This prevents implementing classes from depending on methods they do not need. - Dependency Inversion Principle (DIP): High-level modules should not depend on low-level modules. The
Simulation(high-level) depends on theWorldMapabstraction, not on concrete map implementations likeClassicMap.
- Single Responsibility Principle (SRP): Classes are designed with a single focus. For example,
Graphic assets were used from the following resources:
- Animals: Free Top Down Hunt Animals Pixel Sprite Pack by CraftPix.net
- Map Tiles: Tiny Town by Kenney