From 27cbcf62c4608f9d3a408e903863f3f5e7e47ff0 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 30 Nov 2017 15:53:56 +0100 Subject: [PATCH] introduce random genetic mutations --- src/blobs.cpp | 3 ++ src/creature/BlobBackgroundTask.hpp | 27 ++++++++++ src/creature/Creature.hpp | 9 +++- src/creature/creature.cpp | 11 ++++- src/creature/goal.cpp | 76 +++++++++++++++++++++++++---- src/math/Distribution.hpp | 2 + src/math/GaloisLFSR.hpp | 2 +- 7 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 src/creature/BlobBackgroundTask.hpp diff --git a/src/blobs.cpp b/src/blobs.cpp index 836c51d..f628a1b 100644 --- a/src/blobs.cpp +++ b/src/blobs.cpp @@ -99,6 +99,9 @@ int main(int argc, char *argv[]) { auto blob = new creature::Creature(sim); blob->Name(assets.name.Sequential()); Spawn(*blob, planet); + // decrease chances of ur-blob dying without splitting + blob->GetProperties().Youth().fertility = 1.0; + blob->GetProperties().Adult().fertility = 1.0; blob->BuildVAO(); app::MasterState state(assets, sim); diff --git a/src/creature/BlobBackgroundTask.hpp b/src/creature/BlobBackgroundTask.hpp new file mode 100644 index 0000000..5cdae79 --- /dev/null +++ b/src/creature/BlobBackgroundTask.hpp @@ -0,0 +1,27 @@ +#ifndef BLOBS_CREATURE_BLOBBACKGROUNDTASK_HPP_ +#define BLOBS_CREATURE_BLOBBACKGROUNDTASK_HPP_ + +#include "Goal.hpp" + + +namespace blobs { +namespace creature { + +class BlobBackgroundTask +: public Goal { + +public: + explicit BlobBackgroundTask(Creature &); + ~BlobBackgroundTask() override; + +public: + std::string Describe() const override; + void Tick(double dt) override; + void Action() override; + +}; + +} +} + +#endif diff --git a/src/creature/Creature.hpp b/src/creature/Creature.hpp index d3cd86c..3cff2e0 100644 --- a/src/creature/Creature.hpp +++ b/src/creature/Creature.hpp @@ -77,8 +77,10 @@ public: double Age() const noexcept; std::string AgeName() const; double AgeLerp(double from, double to) const noexcept; - // change of giving birth per tick + // chance of giving birth per tick double Fertility() const noexcept; + // chance of random genetic mutation per tick + double Mutability() const noexcept; void Health(double h) noexcept { health = h; } double Health() const noexcept { return health; } @@ -91,6 +93,10 @@ public: Memory &GetMemory() noexcept { return memory; } const Memory &GetMemory() const noexcept { return memory; } + /// constantly active goal. every creature in the simulation is required to have one + void SetBackgroundTask(std::unique_ptr &&g) { bg_task = std::move(g); } + Goal &BackgroundTask() { return *bg_task; } + void AddNeed(std::unique_ptr &&n) { needs.emplace_back(std::move(n)); } const std::vector> &Needs() const noexcept { return needs; } @@ -135,6 +141,7 @@ private: Memory memory; + std::unique_ptr bg_task; std::vector> needs; std::vector> goals; diff --git a/src/creature/creature.cpp b/src/creature/creature.cpp index 57c1f53..74d5751 100644 --- a/src/creature/creature.cpp +++ b/src/creature/creature.cpp @@ -5,6 +5,7 @@ #include "Situation.hpp" #include "Steering.hpp" +#include "BlobBackgroundTask.hpp" #include "Goal.hpp" #include "IdleGoal.hpp" #include "InhaleNeed.hpp" @@ -44,6 +45,7 @@ Creature::Creature(world::Simulation &sim) , on_death() , removable(false) , memory(*this) +, bg_task() , needs() , goals() , situation() @@ -127,7 +129,11 @@ double Creature::AgeLerp(double from, double to) const noexcept { } double Creature::Fertility() const noexcept { - return AgeLerp(CurProps().fertility, NextProps().fertility) / 3600.0; + return AgeLerp(CurProps().fertility, NextProps().fertility) * (1.0 / 3600.0); +} + +double Creature::Mutability() const noexcept { + return GetProperties().mutability * (1.0 / 3600.0); } void Creature::AddGoal(std::unique_ptr &&g) { @@ -175,6 +181,8 @@ void Creature::Tick(double dt) { situation.SetState(state); } + bg_task->Tick(dt); + bg_task->Action(); memory.Tick(dt); for (auto &need : needs) { need->Tick(dt); @@ -485,6 +493,7 @@ void Genome::Configure(Creature &c) const { c.Density(mass / volume); c.GetSteering().MaxAcceleration(1.4 * std::atan(c.GetProperties().strength)); c.GetSteering().MaxSpeed(4.4 * std::atan(c.GetProperties().dexerty)); + c.SetBackgroundTask(std::unique_ptr(new BlobBackgroundTask(c))); c.AddGoal(std::unique_ptr(new IdleGoal(c))); } diff --git a/src/creature/goal.cpp b/src/creature/goal.cpp index daf8f90..9d3e125 100644 --- a/src/creature/goal.cpp +++ b/src/creature/goal.cpp @@ -1,3 +1,4 @@ +#include "BlobBackgroundTask.hpp" #include "Goal.hpp" #include "IdleGoal.hpp" #include "LocateResourceGoal.hpp" @@ -16,6 +17,71 @@ namespace blobs { namespace creature { +BlobBackgroundTask::BlobBackgroundTask(Creature &c) +: Goal(c) { +} + +BlobBackgroundTask::~BlobBackgroundTask() { +} + +std::string BlobBackgroundTask::Describe() const { + return "being a blob"; +} + +void BlobBackgroundTask::Tick(double dt) { +} + +void BlobBackgroundTask::Action() { + // check if eligible to split + if (GetCreature().Mass() > GetCreature().GetProperties().Birth().mass * 1.8) { + double fert = GetCreature().Fertility(); + double rand = Assets().random.UNorm(); + if (fert > rand) { + std::cout << "[" << int(GetCreature().GetSimulation().Time()) + << "s] " << GetCreature().Name() << " split" << std::endl; + Split(GetCreature()); + return; + } + } + // check for random property mutation + if (GetCreature().Mutability() > Assets().random.UNorm()) { + double amount = 1.0 + (Assets().random.SNorm() * 0.05); + auto &props = GetCreature().GetGenome().properties; + double r = Assets().random.UNorm(); + math::Distribution *d = nullptr; + if (Assets().random.UNorm() < 0.5) { + auto &set = props.props[(int(Assets().random.UNorm() * 4.0) % 4) + 1]; + if (r < 0.25) { + d = &set.age; + } else if (r < 0.5) { + d = &set.mass; + } else if (r < 0.75) { + d = &set.fertility; + } else { + d = &set.highlight; + } + } else { + if (r < 0.2) { + d = &props.strength; + } else if (r < 0.4) { + d = &props.stamina; + } else if (r < 0.6) { + d = &props.dexerty; + } else if (r < 0.8) { + d = &props.intelligence; + } else { + d = &props.mutability; + } + } + if (Assets().random.UNorm() < 0.5) { + d->Mean(d->Mean() * amount); + } else { + d->StandardDeviation(d->StandardDeviation() * amount); + } + } +} + + Goal::Goal(Creature &c) : c(c) , on_complete() @@ -88,16 +154,6 @@ void IdleGoal::Tick(double dt) { } void IdleGoal::Action() { - // check if eligible to split - if (GetCreature().Mass() > GetCreature().GetProperties().Birth().mass * 1.8) { - double fert = GetCreature().Fertility(); - double rand = Assets().random.UNorm(); - if (fert > rand) { - std::cout << "[" << int(GetCreature().GetSimulation().Time()) - << "s] " << GetCreature().Name() << " split" << std::endl; - Split(GetCreature()); - } - } } diff --git a/src/math/Distribution.hpp b/src/math/Distribution.hpp index 7f444f8..6ef9ece 100644 --- a/src/math/Distribution.hpp +++ b/src/math/Distribution.hpp @@ -16,7 +16,9 @@ public: { } public: + void Mean(double m) noexcept { mean = m; } double Mean() const noexcept { return mean; } + void StandardDeviation(double d) noexcept { stddev = d; } double StandardDeviation() const noexcept { return stddev; } double Variance() const noexcept { return stddev * stddev; } diff --git a/src/math/GaloisLFSR.hpp b/src/math/GaloisLFSR.hpp index 4ce278f..d380e24 100644 --- a/src/math/GaloisLFSR.hpp +++ b/src/math/GaloisLFSR.hpp @@ -60,7 +60,7 @@ public: } double UNorm() noexcept { - return double(Next()) / double(std::numeric_limits::max()); + return double(Next()) * (1.0 / double(std::numeric_limits::max())); } template -- 2.39.2