|
10 | 10 | #include "Organism.hpp" |
11 | 11 | #include "index/ISpatialIndex.hpp" |
12 | 12 |
|
| 13 | +/** |
| 14 | + * @brief The 2D simulation world that owns all objects and drives the tick loop. |
| 15 | + * |
| 16 | + * Environment manages a spatial index for efficient proximity queries and an |
| 17 | + * object map keyed by UUID. Each simulation tick runs three phases in order: |
| 18 | + * 1. **Interactions** -- close-range actions (eating, fighting) within size radius. |
| 19 | + * 2. **Reactions** -- movement decisions based on objects within reaction radius. |
| 20 | + * 3. **Post-iteration** -- life-span deduction, movement, and spatial-index sync. |
| 21 | + * |
| 22 | + * After the requested iterations complete, a cleanup pass removes dead organisms |
| 23 | + * and consumed food from the world. |
| 24 | + * |
| 25 | + * Both handleInteractions() and handleReactions() run single-threaded so that |
| 26 | + * Python strategy callbacks can safely acquire the GIL without deadlocks. |
| 27 | + */ |
13 | 28 | class Environment { |
14 | 29 | public: |
| 30 | + /** |
| 31 | + * @brief Construct an environment with the given dimensions. |
| 32 | + * @param width Horizontal extent of the world (x in [0, width]). |
| 33 | + * @param height Vertical extent of the world (y in [0, height]). |
| 34 | + * @param type Spatial-index implementation: "default" (brute-force) or "optimized" (quadtree). |
| 35 | + * @param numThreads Reserved for future multi-threaded support (currently unused). |
| 36 | + */ |
15 | 37 | Environment(int width, int height, std::string type = "default", int numThreads = 1); |
| 38 | + |
| 39 | + /** @brief Horizontal extent of the simulation area. */ |
16 | 40 | int getWidth() const { return width; } |
| 41 | + /** @brief Vertical extent of the simulation area. */ |
17 | 42 | int getHeight() const { return height; } |
18 | 43 |
|
| 44 | + /** |
| 45 | + * @brief Place an organism into the environment at the given coordinates. |
| 46 | + * @param organism Shared pointer to the organism. |
| 47 | + * @param x X-coordinate (must be within bounds). |
| 48 | + * @param y Y-coordinate (must be within bounds). |
| 49 | + * @throws std::out_of_range If (x, y) is outside the environment bounds. |
| 50 | + */ |
19 | 51 | void add(const std::shared_ptr<Organism>& organism, float x, float y); |
| 52 | + |
| 53 | + /** |
| 54 | + * @brief Place a food item into the environment at the given coordinates. |
| 55 | + * @param food Shared pointer to the food. |
| 56 | + * @param x X-coordinate (must be within bounds). |
| 57 | + * @param y Y-coordinate (must be within bounds). |
| 58 | + * @throws std::out_of_range If (x, y) is outside the environment bounds. |
| 59 | + */ |
20 | 60 | void add(const std::shared_ptr<Food>& food, float x, float y); |
21 | 61 |
|
| 62 | + /** |
| 63 | + * @brief Remove an organism from the environment and spatial index. |
| 64 | + * @param organism The organism to remove. |
| 65 | + * @throws std::runtime_error If the organism is not found. |
| 66 | + */ |
22 | 67 | void remove(const std::shared_ptr<Organism>& organism); |
| 68 | + |
| 69 | + /** |
| 70 | + * @brief Remove a food item from the environment and spatial index. |
| 71 | + * @param food The food to remove. |
| 72 | + * @throws std::runtime_error If the food is not found. |
| 73 | + */ |
23 | 74 | void remove(const std::shared_ptr<Food>& food); |
24 | 75 |
|
| 76 | + /** @brief Remove all objects and reset statistics (dead organisms, food consumption). */ |
25 | 77 | void reset(); |
26 | 78 |
|
27 | | - void simulateIteration(int, |
| 79 | + /** |
| 80 | + * @brief Run the simulation for a number of iterations. |
| 81 | + * @param iterations Number of ticks to simulate; stops early if the world is empty. |
| 82 | + * @param on_each_iteration Optional callback invoked after every tick (useful for rendering). |
| 83 | + */ |
| 84 | + void simulateIteration(int iterations, |
28 | 85 | std::function<void(const Environment&)> on_each_iteration = nullptr); |
29 | 86 |
|
| 87 | + /** @brief Snapshot of all living organisms currently in the environment. */ |
30 | 88 | std::vector<std::shared_ptr<Organism>> getAllOrganisms() const; |
| 89 | + /** @brief Snapshot of all remaining (uneaten) food items. */ |
31 | 90 | std::vector<std::shared_ptr<Food>> getAllFoods() const; |
| 91 | + /** @brief Snapshot of every environment object (organisms + food). */ |
32 | 92 | std::vector<std::shared_ptr<EnvironmentObject>> getAllObjects() const; |
| 93 | + /** @brief Organisms that have died during the simulation (accumulated across ticks). */ |
33 | 94 | std::vector<std::shared_ptr<Organism>> getDeadOrganisms() const; |
| 95 | + /** @brief Total number of food items consumed since the last reset(). */ |
34 | 96 | unsigned long getFoodConsumptionInIteration() const; |
35 | 97 |
|
36 | 98 | private: |
37 | 99 | int width, height; |
38 | | - std::string type; |
| 100 | + std::string type; ///< Spatial-index variant identifier ("default" or "optimized"). |
39 | 101 | std::unique_ptr<ISpatialIndex<boost::uuids::uuid>> spatialIndex; |
| 102 | + /// Maps object UUID -> shared_ptr; serves as the authoritative object store. |
40 | 103 | std::unordered_map<boost::uuids::uuid, std::shared_ptr<EnvironmentObject>> objectsMapper; |
41 | 104 |
|
42 | | - std::vector<std::shared_ptr<Organism>> deadOrganisms; |
43 | | - unsigned long foodConsumption = 0; |
| 105 | + std::vector<std::shared_ptr<Organism>> deadOrganisms; ///< Accumulated dead organisms. |
| 106 | + unsigned long foodConsumption = 0; ///< Eaten-food counter. |
44 | 107 |
|
45 | | - int numThreads = 1; |
| 108 | + int numThreads = 1; ///< Reserved for future multi-threaded tick processing. |
46 | 109 |
|
| 110 | + /** |
| 111 | + * @brief Validate that coordinates lie within the environment bounds. |
| 112 | + * @throws std::out_of_range If out of bounds. |
| 113 | + */ |
47 | 114 | void checkBounds(float x, float y) const; |
| 115 | + |
| 116 | + /** @brief Synchronise organism positions with the spatial index after movement. */ |
48 | 117 | void updatePositionsInSpatialIndex(); |
| 118 | + |
| 119 | + /** @brief Run close-range interaction phase for all living organisms. */ |
49 | 120 | void handleInteractions(); |
| 121 | + |
| 122 | + /** @brief Run reaction (movement-decision) phase for all living organisms. */ |
50 | 123 | void handleReactions(); |
| 124 | + |
| 125 | + /** @brief Invoke postIteration() on every object and sync positions. */ |
51 | 126 | void postIteration(); |
| 127 | + |
| 128 | + /** @brief Remove dead organisms and eaten food from the world. */ |
52 | 129 | void cleanUp(); |
53 | 130 | }; |
54 | 131 |
|
|
0 commit comments