What we have so far:
Having a good definition of fitness is going to be crucial to our success with Alphabet Soup, and any of our games for that matter. So far we have only one fitness factor, a rather rudimentary "meatiness" goal: the more 1s, the better.
Aiming for the maximum fitness of 1, we define an ideally fit chromosome of 16 binary "alleles" as 16/16 =1, or:
chromosome = 1111111111111111 =
1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 = 16/16 = 1 = 100% fit.
Anything less than ideal is given a fitness value such as 13/16 = 0.81, or:
chromosome = 1111110111011101 =
1+1+1+1+1+1+0+1+1+1+0+1+1+1+0+1 = 13/16 = 0.81 = 81% fit.
This is all very simple. Too simple. But it's a start. The question is, where do we go from here?
In progress:
The next step will be to include the schemata for the letters. Fitness will be a combined value of the "meatiness" and the "likeness" defined by a comparator function. Here is how it will all work:
First we will have the letter genomes in the Binary Letter Library broken down and defined into the final schemata:
charLine[0] = 0*****0000000000
...
lines 1 thru 14
...
charLine[15]=0******0000***00
Where there is a "0", the value is always zero--in any letter in our population. Why calculate that if it is never going to change? The remaining values then, represented by asterisks, will be either 1s or 0s, depending on the letter. The results of the GA generations will be run through the schemata, with the remaining asterisked positions matched up against the letters in the library. Matching to the nearest letter will be easy. Say there are 125 asterisked positions. After the first generation of GA takes place, the fittest-so-far (meatiest individual) is passed through the schemata. All zero-only spots (such as charLine[0][0], charLine[0][6] are dropped immediately. All asterisk "either-or" positions are evaluated. If charLine[0][1] is a '1', it is matched to all letters with a value of '1', and so on. The genome will then take the shape of the letter with the most matching values....
An important technical aspect of this that we have agreed on is to have the comparator only change the way the letters are displayed, while leaving their array intact--aside from the schemata. In other words, the original GA-defined chromosome/genome is maintained, while a copy of itself is stripped to be matched against the schemata. This allows it to maintain its evolutionary integrity with a level of abstraction so more fitness functions can be performed. I will deal more with this later.
So how do we define the new fitness value, with both the schemata (likeness) and meatiness in mind? Here is a 5-step process that should do the job:
1. Take value of current generation individual. Let's use for genInd[5], say: 0000101011101110
2. Pass through schemata. Let's use generic letter line 5, which might be 00*****0******00, making genInd[5] now equal 00001010111011
00
(the only bit that changes is the second-to-last one, because based on the schema that bit always equals 0).
3. Define "likeness value." For simplicity's sake let's use charAline[5] which equals 0000010001000000. For all bits of genInd[5] that match charAline[5], add a 1:
So, comparing
0000101
01
11
011
00 (genInd[5]) to
0000010
00
10
000
00 (charAline[5]), and disregarding schemata characters that are always 0
(blue), we find only 4 bits that match
(red), giving genInd[5] the "likeness" value of 4 as compared to charAline[5].
4. Define the "meatiness value." To incorporate the "meatiness" factor, let's add an additional +1 to each value of matching letter that is, actually, "1" (meat). When we add up all the matching value of 1s between genInd[5] and charAline[5], we only get +1: 000010101
1101100 compared to 000001000
1000000. So, for this particular example, the meatiness value = 1.
5. Add "likeness value" and "meatiness value".To get the total fitness value, add the likeness value (4) to the meatiness value (1) for a total value of 5.
Note: since this schemata line has 5 characters that are always equal to 0 (shown here: 00*****0******00), they are subtracted from the maximum fitness amount. So, the maximum fitness of this line is 16-5 = 11 possible values that match ("likeness" value), plus the possibility that all of those values are 1s ("meatiness" value), making the total maximum fitness of this line equal to:
11 (max "likeness") + 11 (max "meatiness") = 22. So in our example,
4 (likeness) + 1 (meatiness) = 5 was not all that great (5/22 = 23%). Other letters in the alphabet will much likely have higher fitness on this line.
I think this will be a good way to determine total fitness--at least in early versions of Alphabet Soup.
Future awesomeness:
All technicalities aside, this is where Alphabet Soup can get really interesting. This will probably be around... version 3.0 or so. Right now, these are just vague ideas.
Fitness based on letter shape was the original goal of Alphabet Soup
all along:
"Hark! Here comes a second generation character, ‘i’, who has lost the vestigial tittle (the dot). Most other letters are unchanged or changed in a negative or neutral way. The lower mass of the ‘i’ makes it faster and take in less calories. Alas, it’s lower weight makes it do less damage and is losing ground to the dastardly ‘T’s and their hearty top most shield. Will the character genes be favorable enough to carry on or will they be lost and another random variation will make itself dominant. At the front of ‘i’s’ and ‘T’s’ war, a fork occurs with the ‘w’s. The ‘w’s strike fast coming down but their double point distributes the impacts, lessoning the effect on harder shelled letters like the ‘T'."
With this, things like food, environment and the ability to reproduce/fight/defend are all important.
Another idea is this: fitness is dynamic, determined by the players. They change the landscape--by adding obstacles, giving new goals (such as winning a race, building a tower, et cetera). Different letters will be more suited to different tasks, so fitness will vary from task to task. This might keep it more interesting than if fitness was just based on one thing (like meatiness or shape). Also, on the note of shape mattering--maybe shape won't matter as much as far as fitness value is concerned, however shape may be important for movement in Farseer if we can get the physics of it right. So... if the goal is to get over a mountain or something, the shape and physics will be important to the letter's success, indirectly having an effect on the fitness anyway.
A good comparison is to think of how to keep a Sim alive: by balancing a variety of values that are important to the character's success at staying alive, such as social value, food, health, activity, recreation, knowledge, and so on. Any of these kinds of ideas could be incorporated into the fitness value to make it more interesting and keep the player more involved in what is happening in the Soup. One important key to this is to allow the Evolutionary Computation to do its thing without interferring. If we can hone that delicate balance between the EC and the player-letter interaction, Alphabet Soup could be great.
The future awesomeness of Alphabet Soup depends on our ability to come up with more fitness ideas, and to make them actually work.
Other considerations:
We have talked a lot about including sensing organs for letters to be able to interact with their environment on a biological level. Also in discussion are color values which may or may not be related to fitness, sensing ability, or overall health of a letter. We will have to deal more with these ideas and see what we can agree on.
One thing we have reached consensus on is the level of abstraction that will be present in our final product. Overall, we are going to let the GA and GP do their things in a very precise way, keeping the Evolutionary Computation aspect as pure as possible--but this will all be going on behind the scenes. The precision in the background will be modified and "rounded" (such as with the schemata) before reaching the eyes of the player. This will allow the letters to maintain their forms, allow the Physics Engine to operate on fixed shapes, and so on. However there will likely be a more abstract level of EC going on as well, such as with the shapes present in the physics engine and how they react to one another. The more levels of EC operating within the game, the more rich the environment and the more capable it will be of surprising us.
But we don't want the abstraction to completely cover up what is going on behind the scenes.
One way to be able to unite the abstraction with the player's awareness of what is going on is through keeping a detailed history of each genome in the population. We should somehow tie the chromosomes to their respective genome so that the genome holds its identity and evolutionary lifespan throughout its own history. Maybe stamp each chromosome with some sort of hidden i.d. assigning it to its current genome. These generational histories will provide the owner of the letter with information showing how old the letter is (how many generations it has survived) and each detailed transformation it has undergone during its evolution to its current state. This could be useful for farming, trading or even--who knows--combat? Dog-fighting is illegal, but how about pitting our letters against each other? There are all kinds of scenarios and places we could go with Alphabet Soup. And as the
creators of Dwarf Fortress believe, the more ideas we integrate, the better the game might become.