print pheros + ants drop pheros + return to base
This commit is contained in:
107
src/ant.cpp
107
src/ant.cpp
@ -1,43 +1,32 @@
|
||||
#include "ant.hpp"
|
||||
|
||||
std::tuple<int, int> direction_to_offset(direction dir) {
|
||||
switch (dir) {
|
||||
case direction::NORTH:
|
||||
return std::make_tuple<int, int>(0, 1);
|
||||
case direction::EAST:
|
||||
return std::make_tuple<int, int>(1, 0);
|
||||
case direction::SOUTH:
|
||||
return std::make_tuple<int, int>(0, -1);
|
||||
case direction::WEST:
|
||||
return std::make_tuple<int, int>(-1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should every ant have its own random generators? Why not initialize with coordinates and put the random numbers in there (from main)
|
||||
Ant::Ant(PheromoneMap& pheromones, double x, double y)
|
||||
: WorldObject(x, y, 3, sf::Color::Black), pheromones(pheromones) {
|
||||
Ant::Ant(PheromoneMap& pheromones)
|
||||
: WorldObject(0, 0, 3, sf::Color::Black), pheromones(pheromones) {
|
||||
std::random_device rd; // obtain a random number from hardware
|
||||
std::mt19937 gen(rd()); // seed the generator
|
||||
|
||||
std::uniform_real_distribution<> degree_distribution(0, 2 * std::numbers::pi);
|
||||
direction = degree_distribution(gen);
|
||||
}
|
||||
|
||||
Ant::Ant(PheromoneMap& pheromones, unsigned int direction)
|
||||
: WorldObject(0, 0, 3, sf::Color::Black), direction(direction),
|
||||
pheromones(pheromones) {
|
||||
std::random_device device; // obtain a random number from hardware
|
||||
std::mt19937 generator(device()); // seed the generator
|
||||
|
||||
std::uniform_int_distribution<> width_distribution(0, WIDTH);
|
||||
x = width_distribution(generator);
|
||||
x = width_distribution(gen);
|
||||
|
||||
std::uniform_int_distribution<> height_distribution(0, HEIGHT);
|
||||
y = height_distribution(generator);
|
||||
y = height_distribution(gen);
|
||||
|
||||
updateAppearance();
|
||||
}
|
||||
|
||||
Ant::Ant(PheromoneMap& pheromones)
|
||||
: WorldObject(0, 0, 3, sf::Color::Black), pheromones(pheromones) {
|
||||
std::random_device device; // obtain a random number from hardware
|
||||
std::mt19937 generator(device()); // seed the generator
|
||||
|
||||
std::uniform_int_distribution<> width_distribution(0, WIDTH);
|
||||
x = width_distribution(generator);
|
||||
|
||||
std::uniform_int_distribution<> height_distribution(0, HEIGHT);
|
||||
y = height_distribution(generator);
|
||||
|
||||
std::uniform_real_distribution<> degree_distribution(0, 2 * std::numbers::pi);
|
||||
direction = degree_distribution(generator);
|
||||
std::uniform_int_distribution<> dir_distribution(0, 3);
|
||||
dir = (direction)dir_distribution(gen);
|
||||
|
||||
updateAppearance();
|
||||
}
|
||||
@ -51,32 +40,60 @@ void Ant::update() {
|
||||
|
||||
// Respect borders
|
||||
if (isOffScreen()) {
|
||||
direction += std::numbers::pi / 2;
|
||||
dir = (direction)((dir + 2) % 4);
|
||||
|
||||
x += std::cos(direction) * speed;
|
||||
y += std::sin(direction) * speed;
|
||||
x += std::get<0>(direction_to_offset(dir)) * speed;
|
||||
y += std::get<1>(direction_to_offset(dir)) * speed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
updateAppearance();
|
||||
if (has_food) {
|
||||
dropPheromone();
|
||||
}
|
||||
}
|
||||
|
||||
void Ant::move() {
|
||||
// TODO: Should this random generator be created on every move?
|
||||
std::random_device device; // obtain a random number from hardware
|
||||
std::mt19937 generator(device()); // seed the generator
|
||||
|
||||
// Move
|
||||
std::uniform_real_distribution<> degree_distribution(-std::numbers::pi, std::numbers::pi);
|
||||
|
||||
direction += degree_distribution(generator) * (1.0 / determination); // Normalize with determination to smooth movement
|
||||
if (direction > 2 * std::numbers::pi) {
|
||||
direction -= 2 * std::numbers::pi;
|
||||
for (const auto& world_obj : umwelt) {
|
||||
if (world_obj->has_pheromones() && collides(*world_obj)) {
|
||||
has_food = true;
|
||||
} else if (collides(*world_obj)) {
|
||||
has_food = false;
|
||||
}
|
||||
}
|
||||
|
||||
x += std::cos(direction) * speed;
|
||||
y += std::sin(direction) * speed;
|
||||
// TODO: Should this random generator be created on every move or should the ant carry it always?
|
||||
std::random_device device; // obtain a random number from hardware
|
||||
std::mt19937 gen(device()); // seed the generator
|
||||
|
||||
if (has_food) {
|
||||
move_to_base();
|
||||
} else {
|
||||
// Change direction randomly
|
||||
std::uniform_int_distribution<> dir_distribution(-1, 1);
|
||||
if (dir_distribution(gen) == 0) {
|
||||
// Change direction less often (1/3 of the time)
|
||||
dir = (direction)(((unsigned int)dir + (dir_distribution(gen) + 4)) % 4); // + 4 so the value won't become negative
|
||||
}
|
||||
}
|
||||
|
||||
// Move
|
||||
x += std::get<0>(direction_to_offset(dir)) * speed;
|
||||
y += std::get<1>(direction_to_offset(dir)) * speed;
|
||||
}
|
||||
|
||||
// TODO: Replace umwelt with direct references to base/food and update this
|
||||
void Ant::move_to_base() {
|
||||
if (x < WIDTH / 2) {
|
||||
dir = direction::EAST;
|
||||
} else if (y < HEIGHT / 2) {
|
||||
dir = direction::NORTH;
|
||||
} else if (x > WIDTH / 2) {
|
||||
dir = direction::WEST;
|
||||
} else if (y > HEIGHT / 2) {
|
||||
dir = direction::SOUTH;
|
||||
}
|
||||
}
|
||||
|
||||
void Ant::updateAppearance() {
|
||||
|
22
src/ant.hpp
22
src/ant.hpp
@ -6,13 +6,12 @@
|
||||
#include "main.hpp"
|
||||
#include "pheromone_map.hpp"
|
||||
#include "world_object.hpp"
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <numbers>
|
||||
#include <random>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
constexpr unsigned int speed = 1;
|
||||
|
||||
@ -26,31 +25,30 @@ typedef enum {
|
||||
WEST
|
||||
} direction;
|
||||
|
||||
std::tuple<int, int> direction_to_offset(direction dir);
|
||||
|
||||
class Ant : public WorldObject {
|
||||
private:
|
||||
// TODO: Switch direction to only N, E, S, W
|
||||
direction dir; // in radians
|
||||
direction dir;
|
||||
bool has_food = false;
|
||||
|
||||
// TODO: Should this be here or just global?
|
||||
PheromoneMap& pheromones;
|
||||
|
||||
// TODO: Leave continuous trail and remove this
|
||||
unsigned int next_pheromone_drop = 0;
|
||||
|
||||
public:
|
||||
// Contains the WorldObjects (other ants, base, food)
|
||||
// TODO: Is this even needed?
|
||||
// Contains the WorldObjects (other ants?, base, food)
|
||||
// TODO: Replace this with direct refereces to base/food
|
||||
std::vector<std::shared_ptr<WorldObject>> umwelt;
|
||||
|
||||
Ant(PheromoneMap& pheromones, double x, double y); // Just random direction
|
||||
Ant(PheromoneMap& pheromones, unsigned int direction); // Just random position
|
||||
explicit Ant(PheromoneMap& pheromones); // All random
|
||||
Ant(PheromoneMap& pheromones);
|
||||
|
||||
void addToUmwelt(const std::shared_ptr<WorldObject>& object);
|
||||
void update() override;
|
||||
void move();
|
||||
void move_to_base();
|
||||
void updateAppearance();
|
||||
void dropPheromone(); // red
|
||||
bool has_pheromones() override { return false; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -9,6 +9,7 @@ public:
|
||||
Colony(double x, double y);
|
||||
|
||||
void update() override;
|
||||
bool has_pheromones() override { return false; }
|
||||
};
|
||||
|
||||
#endif // __COLONY_H_
|
||||
|
@ -9,6 +9,7 @@ public:
|
||||
Food(double x, double y);
|
||||
|
||||
void update() override;
|
||||
bool has_pheromones() override { return true; }
|
||||
};
|
||||
|
||||
#endif // __FOOD_H_
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int main() {
|
||||
sf::ContextSettings settings;
|
||||
settings.antialiasingLevel = 8;
|
||||
|
||||
@ -26,7 +26,8 @@ int main(int argc, char* argv[]) {
|
||||
std::shared_ptr<Colony> colony = std::make_shared<Colony>(WIDTH / 2, HEIGHT / 2);
|
||||
std::shared_ptr<Food> foodA = std::make_shared<Food>(50, 50);
|
||||
|
||||
for (int i = 0; i < ANTCOUNT; ++i) {
|
||||
// Init ants
|
||||
for (auto i = 0U; i < ANTCOUNT; ++i) {
|
||||
ants.push_back(std::make_unique<Ant>(pheromones));
|
||||
}
|
||||
for (std::unique_ptr<Ant> const& ant : ants) {
|
||||
@ -54,7 +55,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Render
|
||||
window.clear(sf::Color::White);
|
||||
pheromones.draw();
|
||||
window.draw(pheromones.vertex_array());
|
||||
for (std::unique_ptr<Ant> const& obj : ants) {
|
||||
window.draw(obj->appearance);
|
||||
}
|
||||
|
@ -1,19 +1,27 @@
|
||||
#include "pheromone_map.hpp"
|
||||
|
||||
void PheromoneMap::place(double x, double y) {
|
||||
void PheromoneMap::place(unsigned int x, unsigned int y) {
|
||||
pheromones[x][y] = 1.0;
|
||||
}
|
||||
|
||||
// Decays the pheromone intensity
|
||||
void PheromoneMap::update() {
|
||||
for (auto x = 0; x < WIDTH; ++x) {
|
||||
for (auto y = 0; y < HEIGHT; ++y) {
|
||||
// TODO: Use defined pheromone decay rate instead of magic 0.01
|
||||
pheromones[x][y] = std::max(0.0, pheromones[x][y] - 0.01);
|
||||
for (auto x = 0U; x < WIDTH; ++x) {
|
||||
for (auto y = 0U; y < HEIGHT; ++y) {
|
||||
// TODO: Use defined pheromone decay rate instead of magic number
|
||||
pheromones[x][y] = std::max(0.0, pheromones[x][y] - 0.001);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PheromoneMap::draw() {
|
||||
// TODO: This should convert the 2d pheromone map to a sfml VertexArray to be drawn to the window (below the ants/base/food)
|
||||
// TODO: Represent pheromones as VertexArray directly to skip conversion every frame
|
||||
sf::VertexArray PheromoneMap::vertex_array() const {
|
||||
sf::VertexArray arr = sf::VertexArray(sf::Points, WIDTH * HEIGHT);
|
||||
for (auto x = 0U; x < WIDTH; ++x) {
|
||||
for (auto y = 0U; y < HEIGHT; ++y) {
|
||||
arr[x + y * WIDTH].position = sf::Vector2f(x, y);
|
||||
arr[x + y * WIDTH].color = sf::Color(0, 0, 255, 255 * pheromones[x][y]);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
@ -3,14 +3,15 @@
|
||||
|
||||
#include "main.hpp"
|
||||
#include <array>
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
class PheromoneMap {
|
||||
public:
|
||||
std::array<std::array<double, HEIGHT>, WIDTH> pheromones;
|
||||
|
||||
void place(double x, double y);
|
||||
void place(unsigned int x, unsigned int y);
|
||||
void update();
|
||||
void draw();
|
||||
sf::VertexArray vertex_array() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,7 @@ public:
|
||||
double angle(const WorldObject& other) const;
|
||||
|
||||
virtual void update() = 0; // pure virtual: has to be overridden
|
||||
virtual bool has_pheromones() = 0;
|
||||
};
|
||||
|
||||
#endif // __OBJECT_H_
|
||||
|
Reference in New Issue
Block a user