The Bibites: Digital Life

The Bibites: Digital Life

Not enough ratings
How I Programmed my first ever Bibite brain
By dogcatcowpig
In this guide, I will walk you through the process of creating a Bibite brain, and show you some ways you can use hidden nodes to create complex behaviors.
   
Award
Favorite
Favorited
Unfavorite
Introduction
Alright so I have been following the development of the Bibites for a while now, but with the release of the Steam version, this was my first time trying my hand at creating some artificial Bibites. I made some minor alterations to Luscus xhybridu, which is a Bibite that came with the game, in order to beat the like rabbits challenge, but then I decided to create my own Bibite brain from scratch for the apocalypse challenge. I am by no means an expert, although I'm not sure if there are any expert Bibet creators, but since there are very few guides about Bibets so far I decided to show my work in the hopes that it will help someone create their own Bibites.

The apocalypse challenge starts you off with a smattering of plant pellets and 50 adult Bibites of your champion species. The goal is to have at least one of your Bibites survive for as long as possible without any extra food or energy being generated.

In this guide, I will walk you through my process of creating a Bibite, which survived the apocalypse challenge for 25 hours. I will show you what behaviors I wanted my Bibites to have and how I coded them to do it using the neural network of the Bibite brain. Before we begin I would like to recommend the first guide I read on Bibite brains written by When the murderer is sus, here. This gave me a starting point to work from, and it should help you to understand what I am about to show you as I delve into some practical applications of these nodes and synapses.
Version 1
For the first version of my apocalypse survivor Bibite, my plan was that when the game started all of my champions would kill each other until only one Bibite remained, that Bibite would slowly eat its way through all the food, starting with the meat since meat decays and plants do not, and hopefully live for as long as possible. I started with the template for Squalus nova, since it is a predator that can go for a while without meals. I left most of its genes the same but I completely removed its brain and started coding my own. let's start with the easier half of their brain.
This image contains two basic functions, the one on the bottom controls the speed. the green node in the middle bottom of the image is a ReLu node. It adds up all the incoming activations and outputs the result, but if the output would be negative it instead outputs zero. I used this node because I never wanted my Bibite to go backward, since that takes extra energy, so I never want a negative activation going into my accelerate node. I set the default activation of this ReLu node to 1 so that if there are no negative activations coming in the Bibite will go forwards at full speed. Then I connected the plant-closeness, meat-closeness, energy-ratio, and fullness input nodes to the ReLu node with negative synapses. This means that the higher each of these input nodes activates, the slower the Bibite will go. I had to tinker with the weights of each of these synapses because, with my first version, the Bibites ended up completely stopping whenever they saw both meat and plants at the same time.

The top function in this image paralyzes the Bibite if it is ever attacked, this prevents the last Bibite standing from being hurt. I have the attacked-damage input connected with a very strong weight to the latch node. this means that even if the Bibite is attacked just a little bit, it will always send an activation of at least 1 to the latch. That latch is attached with a very strong negative connection to the want-to-eat, and want-to-attack nodes, as well as the speed controller ReLu node. This means that once the Bibite is attacked it will activate the latch node which will inhibit all of the Bibite's movement effectively paralyzing it while it waits to die.

Now let's move on to the second half of its brain. This part of the brain controls the steering of the Bibite. The plan for this part is that it will only steer towards one type of thing at a time. so if it sees another Bibite, it will ignore all plants and meat. If it sees meat it will ignore the plants. If it sees plants but no meat or Bibites, it will steer towards the plants. Let's take a look at this part of the brain.
Now I know this looks a bit complicated with all the crossing wires but it's actually made up of several copies of the same smaller circuit, so let's break it down and look at just one of them.
This circuit here controls whether or not the Bibite will steer toward plants. The plant-angle input is connected to the multiplication node, which I am using as an AND gate. If the multiplication node receives an activation of 1 from the latch node it will multiply the signal from plant-angle by 1 and allow it to go through to the rotation node, but if it gets a signal of 0 from the latch the multiplication node will output 0 and the Bibite will ignore plants. I have the meat-angle node connected to an absolute value node, which turns a negative activation into a positive activation of equal size. I then connected the absolute value node to the latch with a very strong negative weight. This means that if the meat-angle input node shows anything other than 0, positive or negative, it will send a negative activation to the latch so that it sends 0 to the multiplication node. By default I want the latch to be set to 1 unless the Bibite sees meat, so I used the life-ratio input to send 1 to the latch. I was thinking that since the Bibite would become paralyzed if it ever got attacked, all the active Bibites would always have a full life ratio. This turned out to be an oversight as we will see later, but there are lots of ways you could get that signal of 1 for the latch.

Now if you look back at the image of the larger brain you may be able to pick out the copies of this circuit. There is one for plants and one for meat. The Bibite-angle doesn't need one of these circuits since it should always steer towards other Bibites, so it is connected directly to the rotation output. I also have a circuit that will allow the fullness input to affect steering if the Bibite doesn't see anything. This makes it so that the Bibite will try to turn and look for more food if it just finished eating a pellet, but it doesn't see any more food.

The one part of the brain I haven't explained so far is the "hibernation" function. The idea behind this was that if the Bibite had eaten all of the food in the simulation it should stop moving and just burn off its fat stores to get a little bit of extra time. I attached the minute input with a weak negative weight to the speed controller node so that the longer it had been since the clock had been reset the slower it would go. I then attached the absolute value nodes from the steering controller to the clock-reset node so that whenever the Bibite saw food it would reset the clock. This hibernation function caused more problems than it solved because I never managed to get the Bibite to eat all of the food, so if it got unlucky and didn't see food for a while it would stop moving when it should have kept searching for more food. I eventually removed the hibernation function in a later version.

This first version didn't work because the weights telling it to slow down were too high, so they all just sat there staring at each other until they starved to death. So, it's time to start fixing bugs and making modifications.
Version 2-7
I made several small adjustments to the Bibites diet, metabolism, and brain weights until at version 7 it started to work mostly as intended. The Bibites would kill each other, leaving one Bibite to slowly eat the food.
When I simulated the challenge with this champion the first time, it died after about 3 or 4 hours because it stopped finding food. However, when I simulated it again to get pictures for this guide, I got a lucky run and it managed to eat all the food and survive for almost 6 hours.
I noticed that near the beginning of the simulation, the Bibite would often eat much more food than it needed and so it would be wasting energy by digesting food while it had a full energy meter and full fat storage.
This means that it uses food faster than it needs to, leaving less food around for the later parts of the challenge. This is what I will start to fix in the next version.
Version 8-14
I decided to fix the issue of eating too much food using this circuit here.
I attached the energy-ratio node to a latch with a weight of 1 so that if the energy bar ever got completely filled it would activate the latch. This latch was attached with a negative weight to the want-to-eat and speed controller nodes so that the Bibite would stop moving and eating if it had full energy. I also needed a way to deactivate that latch node when the energy level dropped down again, so I attached the tick node to it. I thought that this would send a pulse every second to the latch, deactivating it. However that is not how the tick node works, it toggles back and forth between 1 and 0 for one second each. So in the next version, I placed a differential node in between the tick node and the latch.
The differential node remembers what activation it received the last tick, and outputs the difference between the last tick's activation and the current tick's activation. My thought was that it would only send a pulse to deactivate the latch node once every second instead of spending half of its time trying to deactivate it like the previous version. This didn't work because it also sent the opposite activation to turn on the latch. when the tick node changed from 0 to 1 the differential node would give an activation of 1, which after going through the negative weight would turn off the latch. However, when the tick node changed from 1 to 0 the differential node would send an activation of -1 which would then turn on the latch. the result of this was that the Bibites would constantly switch between being active and inactive even if they didn't have a full energy bar. In the next version, I fixed the problem by putting an absolute node between the differential node and the latch.
I also noticed that the energy-ratio node never seemed to output a 1, it was always just a little bit less. I am guessing that this is because the energy gained from digestion is added before the energy from the metabolism is removed every tick, so it never quite has a full bar of energy when the brain is processed by the program. So, I increased the weight of the connection between the energy node and the latch so that it would activate when the energy bar was almost full. This finally gave me the desired behavior. When the energy bar was mostly full it would freeze the Bibite, and then the tick node would send a pulse every second to deactivate the latch and basically check if the energy had fallen enough that the Bibite should start moving again. I also connected the latch to the digestion output node so that when the Bibite had full energy it would stop digesting the food it already had in its stomach and keep it until it was needed.

This whole circuit with the tick node was probably over-engineered and there was likely a better way to do it but I still wanted to share it in case it proves useful to someone else.

After these changes to the brain and a few other edits along the way, including removing the problematic hibernation feature, we arrive at version 14 of my Bibite. This version was more efficient than version 7 and didn't waste food. Here you can see a Bibite with no stomach acid because it already has enough energy.
Version 14 managed to survive for 6.5 hours when I re-simulated it for pictures despite not managing to eat all of the food, which was about what I experienced the first time around.
Version 15-17
At this point I felt that I was getting diminishing returns as I developed this Bibite, and while I probably could have gotten it to my 10 hour goal, I decided to go for a more cheesy stratagy. I lowered the brood time gene to 1 second. This made it so that a baby of this species would be much larger, which means that the adult version would have to be much larger in order to lay such a large egg. Here is the result at the start of the simulation.
The new Bibites are so large that they overlap each other at the start and damage each other because of the collisions. However, this damage is not caused by being directly attacked/bitten, and so they do not become paralyzed. They will still attack each other like usual after this so they will eventually die and leave behind one living Bibite and a massive pile of meat.
Now at this point, it is important to understand how meat decays. Meat in The Bibites decays at a linear rate. Each piece of meat loses 0.02u^2 of mass every second, no matter how large it is.
This means that a 1-gram piece of meat will decay 1000 times faster than a 1-kilogram piece of meat. Because the meat left behind when one of these giant Bibites dies is about 18000u^2, it will take about 250 hours to completely disappear.
Because meat is the only meaningful food source left at this point I made the Bibites completely carnivorous.

You might remember that I said using the life-ratio node in my steering controller was a bit of an oversight, and this is when it becomes a problem. Because of the Bibites overlapping at the beginning, all of them end up getting damaged, even the last survivor. This means that the life-ratio node no longer outputs 1 so it can't turn the latches back on. This means that once a Bibite sees another Bibite it will start ignoring meat, and will continue to ignore meat even when it stops seeing Bibites. It will simply move straight ahead all the time. I fixed this issue in version 18, but despite this problem, the Bibite managed to survive for just under 11 hours when I re-simulated it for pictures. There is simply so much meat around that it stumbles into enough food to keep it alive thanks to the void-no-mo'.
Version 18-25
This large Bibite was able to live for a long time, but I wanted to take more advantage of the fact that the pieces of meat were so large. So, I decided to have the adult lay an egg so the baby would be able to eat the pile of meat at a slower pace. I wanted the adult to lay an egg after 90 minutes had passed since there was usually only one Bibite left at that time, and then become paralyzed as if it had been attacked. lets look at my first try.
I attached the minute node with a weight of 0.011 to a latch. After 90 minutes had passed that latch would activate and paralyze the Bibite and activate the want-to-lay node. There were two problems with this circuit. The first was that the baby Bibite would also become paralyzed after 90 minutes even though it could not lay an egg. The second problem was that because the egg-production node became negatively activated at the same time as the want-to-lay node was activated, the Bibite would start to reabsorb its egg before actually laying it. However, sometimes a Bibite would get killed while carrying an egg and so the baby version would be born early.
While this baby is smaller than its parent, it is still quite a bit larger than a normal Bibite. I solved the first problem with the egg-laying circuit here.
The maturity node is supposed to output 1 when the Bibite is able to lay eggs and a lower number before that, however, that was not what I was getting with this Bibite. The adult Bibite was given a maturity value of about 380 while the baby was given an output of about 50. This could be caused by the extreme size of the Bibite but I'm not sure. I attached the maturity node to a ReLu node with a default activation of -300 so that the adult would get an output from the ReLu of more than 1 and the baby would get an output of 0. I then attached this to a latch to normalize the output to 1 before attaching that to the multiply node. The adult Bibite will have the minute nodes output multiplied by 1 and eventually lay an egg, while the baby will have it multiplied by 0 and thus never become paralyzed. I solved the problem of reabsorbing the egg in the next circuit.
In this circuit, I separated the latch that inhibits egg-production from the latch that activates want-to-lay. The top connection of the minute node works the same way as before, and it will make the Bibite lay an egg after 90 minutes if it is an adult. the other connection from the minute node goes into a linear node with a default activation of -5 before going on to the paralyzing node. This means that the Bibite will lay its egg after 90 minutes, and will start being paralyzed and try to reabsorb its egg 5 minutes later at the 95-minute mark. This worked as intended so that each adult Bibite would lay exactly one egg after 90 minutes.

At this point, we are finally caught up to version 25 of my Bibite, which is my most recent version. It is finally working as intended, and after a while, we end up with one baby Bibite with a nice big pile of meat to eat.
This version was able to live for a very long time. When I was building it originally, this was the first version that lasted for 10 hours or more. When I re-simulated version 25 for pictures, it survived for 17 hours. However, as you can see from my high score, my best run lasted for 25 hours.
if you are curious, this is what the final brain looks like in all of its glory. it looks complicated at a glance, but hopefully I've explained it well enough that you can pick out what each part does now.
Conclusion
There you have it. That is how I programmed a Bibite brain from start to finish. I didn't include every tiny change I made, but I think I showed most of the important ones. There is definitely still a lot of room for improvement, for instance, I could shrink the egg organ to make the baby even smaller compared to the adult, but I already doubled the 3-star time requirement so I think this is a good enough stopping point.

This might have been more of a documentary than a guide, but I hope that this will help some newer players get into engineering their own Bibites. The neural network that makes up the brain of a Bibite is basically just another programming language, albeit written in a very different way than Java and Python and those sorts of languages. It may seem confusing at first, but once you start to understand how these nodes and synapses work, you can program any behavior you want. There are still several hidden node types that I have not even touched, but you don't need to understand all of them to start creating some cool Bibites of your own.

I hope this guide was useful to you. If you have any questions about this design in particular or about Bibite brains in general I will do my best to answer them in the comments.
1 Comments
thomas.cortens 10 Sep @ 12:53pm 
That's soooo cool also the first proper bibite engineering guide