#pragma once #include #include #include #include #include template struct Agent { using F = std::function; virtual void move(float dt) = 0; virtual void step(float dt) = 0; virtual std::pair best() const = 0; Agent(F f) : f(f) {} protected: F f; }; template struct Particle : public Agent> { std::pair> best() const override { return {pb, pb_pos}; }; void move(float dt=1) override { position = position + velocity * dt; } void step(float dt=1) override { velocity = kviscosity * velocity + knostalgia * (pb_pos - position) + kpeer_pressure * (peer.best().second - position); float y = f(position); if(y < pb) { pb = y; pb_pos = position; } }; float kviscosity = 0.9f; float knostalgia = 2.5f; float kpeer_pressure = 0.5f; Particle(Agent>::F f, const Agent>& peer, vec position, vec velocity) : Agent>(f), position(position), velocity(velocity), pb_pos(position), peer(peer) { pb = f(position); } const vec &get_position() const { return position; }; private: vec position; vec velocity; vec pb_pos; float pb; const Agent>& peer; }; template struct Swarm : public Agent> { std::pair> best() const override { return {best_val, best_pos}; } void move(float dt=1) override { for(auto &p : particles) p.move(dt); } void step(float dt=1) override { if(particles.empty()) return; // find best before step() on each particle // otherwise, if this were in best(), each p.step() would update it const Particle *b = &particles[0]; for(const auto &p : particles) { if(b->best().first > p.best().first) b = &p; } best_val = b->best().first; best_pos = b->best().second; for(auto &p : particles) p.step(dt); } void add_particle(std::size_t n=1) { for(std::size_t i=0; i <= n; ++i) particles.push_back( Particle(this->_f, *this, vec(0), vec(10)) ); } void add_particle(const vec &pos, const vec &vel) { particles.push_back( Particle(this->f, *this, pos, vel) ); } const std::vector>& get_particles() { return particles; }; Swarm(Agent>::F f) : Agent>(f) {} private: vec best_pos; float best_val; std::vector> particles; };