]> git.localhorst.tv Git - blobs.git/commitdiff
introduce random genetic mutations
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 30 Nov 2017 14:53:56 +0000 (15:53 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 30 Nov 2017 14:53:56 +0000 (15:53 +0100)
src/blobs.cpp
src/creature/BlobBackgroundTask.hpp [new file with mode: 0644]
src/creature/Creature.hpp
src/creature/creature.cpp
src/creature/goal.cpp
src/math/Distribution.hpp
src/math/GaloisLFSR.hpp

index 836c51d335845b0f79e74caf891c6bc3f9ae4732..f628a1bfcb02f58b151aba54ba22974df6a66e75 100644 (file)
@@ -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 (file)
index 0000000..5cdae79
--- /dev/null
@@ -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
index d3cd86c462a7d8f22933ab2b8a0da41673a0ce25..3cff2e04cd5264aefab4510679d4abf80bca5f59 100644 (file)
@@ -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<Goal> &&g) { bg_task = std::move(g); }
+       Goal &BackgroundTask() { return *bg_task; }
+
        void AddNeed(std::unique_ptr<Need> &&n) { needs.emplace_back(std::move(n)); }
        const std::vector<std::unique_ptr<Need>> &Needs() const noexcept { return needs; }
 
@@ -135,6 +141,7 @@ private:
 
        Memory memory;
 
+       std::unique_ptr<Goal> bg_task;
        std::vector<std::unique_ptr<Need>> needs;
        std::vector<std::unique_ptr<Goal>> goals;
 
index 57c1f53f720ca6804647fdf42fa4a1bea4423602..74d5751bce5f9f413a9f111cbdd17e8a42862807 100644 (file)
@@ -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<Goal> &&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<Goal>(new BlobBackgroundTask(c)));
        c.AddGoal(std::unique_ptr<Goal>(new IdleGoal(c)));
 }
 
index daf8f901d7989b780cb067712eb65e4b5e14cd3c..9d3e1254c870670e15db2f38eb28d08358af57e6 100644 (file)
@@ -1,3 +1,4 @@
+#include "BlobBackgroundTask.hpp"
 #include "Goal.hpp"
 #include "IdleGoal.hpp"
 #include "LocateResourceGoal.hpp"
 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());
-               }
-       }
 }
 
 
index 7f444f80b6065e703751d1912e9feea33462798e..6ef9ecea1ab3619633f45b704ba5f453de892289 100644 (file)
@@ -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; }
 
index 4ce278f92b0fb56b0b34d3eaaf7d89975bbbe13c..d380e248405a2efb1ae9b65308d3b05b48e09e18 100644 (file)
@@ -60,7 +60,7 @@ public:
        }
 
        double UNorm() noexcept {
-               return double(Next<std::uint64_t>()) / double(std::numeric_limits<std::uint64_t>::max());
+               return double(Next<std::uint64_t>()) * (1.0 / double(std::numeric_limits<std::uint64_t>::max()));
        }
 
        template<class Container>