Index Here are the tutorial's sections: 1) Dna and robots overview 2) How the robots work 3) The DNA language 4) The inverse polish notation 5) Writing DNAs: the funny part 6) Let's do something more: turning 7) A hunter robot 8) The ref.. variables 9) Movements 10) Centralizing the decision on behaviour 11) Following a prey 12) Messing up other robots 13) Other input cells 14) Other instructions 15) Have fun 1) DNA and robots overview The central parts in DarwinBots are the DNAs. An individual it's his own DNA, which decides his whole behaviour. A friend of mine, watching at the program, objected that the robots could not evolve, since they are all square. Well, DNA can't change their shape. But can give'em a different behaviour. It's different behaviours that are mutated and selected by evolution, not shape. So, a DNA = a behaviour. A robot's behaviour must be such that he can hunt for food, eat it, and reproduce. If he's not able to do such simple things, he will die without any sons, which means that his DNA will disappear. As far as I know, it works this way also for human beings. There's a lot of artificial life programs around in which the individual's DNA just specifies how much a pre-defined behaviour will be expressed in the individual. DarwinBots don't work this way, since a DNA is a program written in a language which has the same power of the most common programming languages. So you'll wave a complete control over a robot's behaviour, within the limits of the simulated universe physics. To understand how to create a whole new DNA, you should know first how a robot works. Well, it's easy enough. Every robot has two parts which are really fundamental, and these are the DNA and the memory, which is made by an array of one thousand cells. The DNA is the robot's program, and like every program does, he works on the datas stored in the memory. So, you may ask, how can a robot move and interact with the universe's reality? Easy: some of the memory's cells are directly connected to the robot's "muscles" and other outputs, while other are connected to the eyes or other input cells. So, you can make a robot move writing a value in one of those cells, or process his sight input reading values from the sight cells. 3) The DNA language If you've ever wrote some program, you will be probably used to a language wich works this way: BEGIN variable declaration WHILE condition1 DO ...... WHILE condition2 DO ..... END WHILE ...... END WHILE END For my robots, I have chosen a different approach. The problem is, that in a program like this shown, a random mutation in one of the outer points - say, on the external 'while' condition- can have disastrous effects over the inner cycles. Furthermore, althought such a program can specify a behaviour, it's really difficult to divide it in discrete components - like the Mendel's peases characters, for instance. So, the structure of the DNA-programs is: BEGIN IF condition1 AND condition2 .... AND conditionN THEN START BLOCK .... (no conditions inside) END BLOCK IF condition1 AND condition3 .... AND conditionM THEN START BLOCK .... (no conditions inside) END BLOCK ................... END Every time the execution cycle restarts, which is, for any simulation cycle, every one of these programs it's re-executed completely from start. So it's like if the whole program is included in an infinite loop. At a first look, it may seem that this language has not the same power of the one shown above. But this is not true. For example, you can translate a common FOR-THEN cycle in this new language this way: IF variable<max THEN START BLOCK increase variable END BLOCK IF variable<max THEN START BLOCK put here the inner code END BLOCK This cycle could be initialized from every point of the program: this is a further advantage of this code, since it is much more flexible than a normal code in respect of the position of its parts. 4) The polish inverse notation Last thing to know before going to the funny part: the inverse polish notation. Maybe you know it already, it was used on old Texas Instruments calculators, as far as I remember. The basic principle is that everything is done passing throug a last-in first-out stack. It's like a stack of dishes: you can take or put a dish only from the top of the stack, all other are unaccessible. The language's instructions work on the dish / data which are on top of the stack, removing them and putting the results at their place. For example, to sum two numbers, you should put them in the stack, and then invoke the sum instruction. It will remove the two numbers, calculate the sum, and put the result on top of the stack. It may seem complicated, but's not. For instance, where you usually write a=b+c now you should write b c add a store Where the 'store' instruction removes the sum's results and the 'a' address from the stack, and puts the first inside the second. It's all that simple. 5) Writing DNAs: the funny part Now, we can finally start with the fun part, that is writing codes which will invariantly bring our robots to tragic deaths :)) Let's try to create a "vegetable", that is one of those robots which don't need to hunt for food, since they are fed by the program itself. In fact, they are there just to form the basis of the food chain. All he has to do, is just reproduce himself when he feels it's time. But he don't have to manage to copy his own DNA: he will just ask the program to do it for him. To do so, he'll just put in a particular cell of his memory a value which represents the percentage of his own energy to pass to his son. The instruction to insert a value in a memory cell is 'store'. So, the code will be: 50 300 store where '50' means an equal subdivision of energy between parent and child, and 300 is the number of the cell which controls reproduction. However, you will not need to recall the cells number: to each one of the system cells of the memory is assignd a mnemonic code. Our code therefore is: 50 .repro store But this isn't still a gene. A gene is a complete block with his activation condition and start and stop markers. So let's state that our vegetable will reproduce whenever his energy reaches the value of 6000. The complete gene will be: cond *.nrg 6000 > start 50 .repro store stop Ok, this is a complete gene. The block between 'start' and 'stop' markers is executed whenever the condition expressed between the 'cond' and 'start' markers turns to true. The star symbol '*' in '*.nrg' means that is to be considered not the value of the .nrg address itself (which is always 310, the address of the memory cells that stores the robot's energy value) but the value _contained_ in it. Finally, if we want to create an organism made from this unique gene, we have to insert an 'end' marker after the last stop. So there's our complete organism: cond *.nrg 6000 > start 50 .repro store stop end Now you can just save it to text file and load it within the program, to see it live and evolve. 6) Something more: turning There's something wrong with our vegetable: he's incapable of reproducing more than one time. The reason is, that the second time he tries to dupicate himself, the program won't do it, because the position in which the new child would appear, it's already occupied by the first child (same will happen for the child, as it points directly towards his parent). What we have to do then, is to tell our robot to turn a little each time he wants to duplicate himself. Here's the code: cond *.nrg 6000 > start 50 .repro store 10 .aimdx store stop end The .aimdx cell (and the other, .aimsx) control the movement of the robot's aim. Obviously, each movement is relative to the current angle, so that a robot simply cannot point, say, horizontally to the left or right, because he wan't know where they are. Each point in an .aimdx or .aimsx cell represents 1/200 of a radiant, so that a 360 degrees turn (6.28 radiants) is made insering a value of 1256. Anyway, now our vegetable will work fine. 7) A hunter robot Now let's try to write down the code of a robot capable of hunting for food. To this purpose, it is fundamental the cell 7, named .shoot. By inserting a -1 value in this cell, our robot will shoot forward a jet of particles. if these particles will eventually reach another robot, this will be forced to respond with another jet, carrying tokens of his own energy. But, a robot who shots continuously in hope to hit some unseen opponent, will rapidly wear off all of his energy, dying ignominously. We need to know whether there is an opponent in front of us, and maybe also how much is it far, since our jet is much shorter than our sight. We'll use for this purpose the sight sense. This sense is composed by a group of nine cells, named .eye1, .eye2 ... , .eye9, each one carrying information on a different viewing angle, which gives our robot a little but useful view field. The value stored in a sight cell it's 0 if no opponent is in our field - or it's too far; then gets increasing as an opponent comes closer. The value in fact is calculated by the formula: (robot size/opponent distance)*100. Since robot size is a constant, you should not worry about that. Just remember that, when this value is 100 or more, the robots are touching; when it's around 50, are separated by a the distance of a robot side, and so on. Of the nine sight cell, .eye5 it's the most important: oviously, since it carries information about what is directly in front of us. Let's write down a gene, then: cond *.eye5 0 > start -1 .shoot store stop With this gene, our robot will shoot everything will be in front of him. Now maybe you'll see what makes such way of coding useful: you can take this gene AS IS and put it anywhere in the DNA of another robot (yes, even in the vegetable we wrote above, althought it's not fair!) and it will work without problems. But... what happens if what we have in front of us is a wall, or maybe a 'friend' robot? 8) The ref... variables We should have a way to determine something more object we're staring at. And there is one. Each time a robot (or a wall, which is made someway of bodys of dead robots) is created, the program creates a list of the occurrences of a certain number of variables in his DNA. This way, we can tell whether a robot belongs to a certain species or another ( but we can also be fooled by an acquired mimetism). For instance, for the one-gened vegetable DNA we wrote above, we have only one occurrence of the variable .aimdx, used for making the robot turn. We can use the ref.. variables to know this values for the current opponent - the object which is in the .eye5 field. Let's see an example of this, here's a gene which prescribes to attack only those vegetables: cond *.eye5 0 > *.refaimdx 1 = start -1 .shoot store stop A robot which has this gene for attacking will shoot only those robots who have only one occurrence of the .aimdx variable in their DNA. Let's make another example now. Suppose that we want to attack only the robots which have more than 4000 points of energy: cond *.eye5 0 > *.refnrg 4000 > start -1 .shoot store stop And here is a list of all the ref.. variables: .refup How many instructions the opponent has in his DNA for moving forward? .refdn How many... backwards? .refsx How many for the left? .refdx How many for the right? .refaimdx How many for turning right? .refaimsx How many for turning left? .refshoot how many to shoot? .refeye How many to look (from .eye1 to .eye9)? .refnrg How many points of energy it has? 9) Movements It's useful that a robot could come closer to his preys, so there are four cells that control movements: .up, .dn, .sx (for the left) , .dx (for the right). So let's write a gene to make our robot get closer to his prey: cond *.eye5 0 > start 10 .up store stop And now, something to make him escape from a fellow: cond *.eye5 0 > *.refup 0 > start 10 .dn store stop Warning! All movements are expressed in respect of the current robot position and aiming: so .up makes the robot going forward, not upwards! 10) Using different variables: There are a lot of cells which are'nt used by the robot's system variables. You can use every one of these cells to store useful values for your robot. Here is an example, using the free cell 40, of a few genes interacting with each other through the use of a free cell. cond *.eye5 0 > *.refaimdx 1 = start 1 40 store stop cond *.eye5 0 = start 0 40 store stop cond *40 1 = start -1 .shoot store stop cond *40 1 = start 10 .up store stop It may seem long, but they are only for genes. The first and second genes set the value for the cell 40: the first assigns it the value 1 if something 'interesting' is in the aim; the second one deletes this value if nothing is seen. The third and fourth genes use the value of the cell 40 to decide whether to attack or not. In this way, any mutation on the first two genes will take effect over the whole attacking behaviour. 11) Following a prey Now let's have a rapid glance on a possible use of the other sight cells: let's write some genes for following a prey when it moves left or right: cond *.eye4 0 > start 10 .aimsx store stop cond *.eye6 0 > start 10 .aimsx store stop .... and so on. 12) Messing up the other robots. Until now we have seen only an use of the particles jet, but others are possible. For example, by inserting a -2 value in the .shoot variable, a robot can shoot a token of his energy. Pretty unuseful, anyway, unless you want your robot to suicide (anyway, there's a lot of interest around the suicide behaviour of cells, called apoptosis). More useful it's this: cond *.eye5 0 > start .aimsx .shoot store 200 .shootval store stop The sequence ".aimsx .shoot store" is no error. In fact, it puts the .aimsx address into the robot's shot, combined with the value 200, which is put in .shootval. This means that our robot will shoot a particle that, when received by an opponent, will force him to turn left by the value 200. This could be used to mess up the other robots, as well to exchanege information with them, using some free cell. If a robot uses the group of genes seen before for deciding which object is to attack, messing up the value of his cell 40 could be a good strategy to prevent him from attacking. 13) Other input cells Let's see all other input cells: .vel : the robot's speed, in absolute value .pain : positive if the energy acquired is less than the lost .pleas : the opposite, obviously .hitup : collision with another robot, in the direction of the aim .hitdn : from the back (d'oh!) .hitdx, .hitsx : same as above, left and right .shup, .shdn, .shdx, .shsx : a shot coming from the respective dkirections: the value is that put in the .shoot cell by the opponent .tie: this creates a stable tie between your robot and the one facing it: it has been thought for the creation of multicellular bodies - a task which I found near impossible. By the way, if anybody would succed in this task, please!, let me know. You'll find a non-working example of a multicellular little worm in the robots dir. 14) Some other instructions Other, self explaining, instructions: add, sub, mult, div 15) Have fun! As in subject. Don't forget to email me your best robots. Bye, Carlo Comis comis@libero.it |
DNA TUTORIAL |