Banner

Hunting Bugs or Bug Hunting

 

 

By Michael Chungkun Chen

 

CS263c – Dyer

12/12/2002

Hypothesis:

I.                    We can evolve hunting an evading behavior based on pheromones with an artificial neural network.

II.                 Animats can learn how to use chemical signals in a new and exciting way.

III.               A more realistic environment is a better environment to evolve these tasks in.

IV.              Speed is very important in simulating a large amount of animats, so making the code efficient and using integer and bit-wise operations will help in this project.

 

Motivation:

I.                    I wanted to build something that used a neural net because neural nets have always fascinated me.  From the time I first learned about neurons from Psych 15 in my sophomore year, I just had to try and make a neuronal model.  My first attempt that year failed because I did not realize all the aspects involved in using neural nets.

II.                 I thought it would be cool if I could create some animats that would work together, and maybe create controllers for something more complex like nano-scaled robots.  So this project is a good starting off point.

III.               I wanted to try to design a very fast and efficient neural net implementation.  See I can get my computer to simulate enough neurons maybe to accomplish some semi-complicated task.

IV.              I wanted to learn techniques that maybe applied in other animat/neural net tasks, which would make my code faster and more efficient.

V.                 It would be fun to play with these animats after I program them.

VI.              This would be a good opportunity to learn how to program with the Windows API.

VII.            I also wanted to use this programming opportunity to brush up on my class inheritance.

 

Architecture:

I.                    Input and output of the Neural Network

a.      Sensors

                                                              i.      Health points (positive number)

                                                            ii.      Energy Level (positive number)

                                                          iii.      X and Y Positions (bounded by constant screen width)

                                                           iv.      Current heading of the bug (In degrees multiplied by 1000000)

                                                             v.      Smell vectors of three smell regions around bug

1.      Smell vectors contain a signal level for each smell type

a.      Food and corpses emit different levels of the same smell

b.      Each bug type has a different smell

c.      Variable number of Signals allowed.  Currently it is set to 6.

2.      Totaling 10 smell signals for each region.

3.      Initial trials had smell regions depend on heading of bug, but changed to the three regions fixed at upper left, upper right, and below bug.  To prevent errors in choosing regions.

                                                           vi.      Later experiments involved a direction of friendly bug nearby

b.      Motors

                                                              i.      Left turn amount (30 degree max)

                                                            ii.      Right turn amount (30 degree max)

                                                          iii.      Forward movement (0 to 4 spaces)

                                                           iv.      Backwards movement (0 to 1 spaces)

                                                             v.      Mating activation (On/Off)

                                                           vi.      Eating activation (On/Off)

                                                         vii.      Attacking activation (On/Off)

                                                       viii.      Signal Emission activation (Signal Strength)

II.                 Environment and physics of the world

a.      World

                                                              i.      1024 X 768 pixels

                                                            ii.      Initial trials allowed bugs to move past one edge to appear on the other side of the screen

                                                          iii.      Later trials forced bugs to get stuck at the edge until they move away

                                                           iv.      Initially population was based on the action of the bugs and energy available as food

                                                             v.      Due to population explosion/collapse, population controls were introduced

                                                           vi.      During the middle phase before using the Neighborhood list, population was capped at 500 for each bug type

                                                         vii.      With the Neighborhood list, it was much faster and population cap was increased to 1000 for each bug type

b.      Food

                                                              i.      Is stationary in the world

                                                            ii.      Food have initial mass which can be changed through menus,

                                                          iii.      When eaten, food mass is decreased by that amount.

                                                           iv.      Food also decays and starts with a user modifiable lifetime.

                                                             v.      When food decays or is completely eaten, it is gone and deleted from the world.

                                                           vi.      When auto-feed feature is on, amount of food is checked every cycle, and more food is added when quota is not reached.

c.      Smells

                                                              i.      Each food has the same smell with a strong magnitude

                                                            ii.      Corpses have the same smell but with a very weak magnitude

                                                          iii.      Each type of bug has it’s own smell

                                                           iv.      Gender also has a smell, only males generate this smell

                                                             v.      I started with one signal for bugs to use, but increased signal number to 5

                                                           vi.      Smells are emitted at a location and dissipates

                                                         vii.      When displayed, smells are coded into colors and drawn in a miniature size maps

1.      Green is for food

2.      Blue is for bugs, any type of bugs

3.      Red is for signals the bugs might emit

d.      Bugs

                                                              i.      Types

1.      Type 1 (Weak)

a.      Less health

b.      Less maturity time

c.      Very little attack power

d.      Energy cost to eat, mate, attack, and move is less

2.      Type 2 (Balanced)

a.      Reasonable health

b.      Reasonable attack power

c.      Maturity time is longer

d.      Energy cost to eat, mate, attack and move is moderate

3.      Type 3 (Strong)

a.      Health is high

b.      Attack power is high

c.      Maturity time is longest

d.      Energy cost to eat, mate, attack and move is highest

                                                            ii.      Moving

1.      The bugs can either turn clockwise or counterclockwise by 30 degrees

2.      Then the bug can move forward by 0 to 4 steps or backwards by 1 step

3.      The bugs can not be on top of the same pixel as another bug

4.      In earlier trials once bugs reached the end of the world, they would appear at the other side

5.      In later trials once bugs reached the edges or corners of the world they would get stuck there unless they turn around

                                                          iii.      Mating

1.      Each bug may only mate with bugs of the same type and opposite gender

2.      They can only mate with bugs that are geographically near

3.      In the beginning when they activated mating, they mated with every compatible candidate around

4.      In later trials, they would only mate with one of the candidates

5.      Fitness was indirectly applied through the environment in beginning trials, while in later ones a discrete fitness variable was added

6.      Mating takes 1 cycle and off-springs are produced immediately

7.      Attempting to mate costs energy

                                                           iv.      Eating

1.      The bugs can only eat what was nearby

2.      In the beginning they would take a bite out of each clump of food that was nearby

3.      In later trails they can only take one bite out of one clump of food

4.      Either they ate a specific amount proportional to their attack points, or they ate what is left of the food

5.      They do not have to face their food

6.      Eating takes only 1 cycle

7.      Attempting to eat costs energy

                                                             v.      Attacking

1.      Bugs can attack only bugs that are close by

2.      They do not have to face the bug they are attacking

3.      They can only attack one bug at a time

4.      Attempting to attack costs energy

5.      Attacked bugs gets to counterstrike bug is much weaker than a full strength attack

                                                           vi.      Emitting smells

1.      Any bug can emit any of the extra 5 smell signals in the world.

2.      Smells released are directly proportional to the activation level of the resulting neuron

3.      Original trials used only 5 signals, and smells signals had a parallel distributed encoding.

4.      Later trials each signal was extracted out of the initial bug and food smells and given individual signals.

                                                         vii.      Dying

1.      When a bug reaches 0 or less health it was killed

2.      When a bug reaches 0 or less energy it starved to death

3.      When a bug’s time left reaches 0 it died of old age

4.      It leaves a corpse which is converted to food

III.               Algorithms used

a.      Smell Region Mapping

                                                              i.      Initial trials used a link list of smells which was very inefficient and slow

                                                            ii.      Then I tried to store smells at each pixel in a smell map of the world, but there were too many pixels and it took more than a second to cycle just the smell itself on my computer

                                                          iii.      Finally I decide to regionalize the smell map, and divided the static world size of 1024 X 768 by 16, and arrived at 64 X 48 smell regions.  This made cycle times much faster

                                                           iv.      Smells are only propagated to its adjacent cells, left, right, up and down.

                                                             v.      Initial world had neighbor cells receive 1/8 the signal strength and the original cell receive ½ the strength.  Smells were dissipating a little too fast still

                                                           vi.      The current implementation involves the neighbor cells receiving 1/16th of the signal strength and the original cell to receive ¾ of the strength.

                                                         vii.      Equations used only had simple shifting

1.      Neighbor+=(Original>>4);

2.      NewSignal=(Original>>1)+(Original>>2);

b.      Neighborhood list

                                                              i.      Original trials did not use the Neighborhood list and every bug had to check through the whole world to determine which objects were nearby.  This gives us a whole factor of N more processing for every bug

                                                            ii.      A Neighborhood list was added which would allow any thing to check an area for objects by checking the region in a spatial manner, bypassing the need to check through the whole world list

                                                          iii.      Each bug on movement would delete itself from the neighbor list at it’s old position and add itself to the neighbor list at the new position

                                                           iv.      When the Thing base class is destructed, the object is removed from the neighbor list

                                                             v.      This feature allowed my computer to process from 1500 bugs to an order of 100000 bugs within a few seconds

c.      Genetic Evolution

                                                              i.      Instead of discrete generations, I decided to implement a more continuous propagation of genes.

1.      Each bug has a lifetime

2.      Each bug mates while alive and generates offspring

3.      Bugs that can find mates and produce offspring are more fit and will pass their genes off to their children

4.      The more children they have, the better chance their genes have for survival

                                                            ii.      Genes

1.      The genes involved in the bugs are basically the neuronal weights used.

2.      When an offspring is created, the genes are directly copied from both parents.

                                                          iii.      Mutation

1.      Mutations occur during birth

2.      It can happen anywhere in the gene with a rate of MU_Rate which is set to 0.30 throughout the trials

3.      An exponential distribution is used to generate a number based on the mutation rate.  And we would skip this amount of non-mutated genes.  Then we change the weight that mutated to a random number.  And we continue until all weights are passed.

                                                           iv.      Crossover

1.      Crossovers occur during birth

2.      It occurs at a rate of CR_Rate which is set to 0.30 throughout the trials

3.      Again an exponential distribution is used, however instead of skipping the weights all the time, we copy the weights from the other parents every other time we encounter a crossover point

                                                             v.      Exponential Distribution

1.      Equation for Exponential Distribution

a.      result = - (1/MU_Rate) * log(random());

b.      the random number is between 0 and 1

2.      This is more efficient than generating a random number for every weight, and checking that against the rate, to decide if we have a mutation or crossover point.

d.      Threshold functions

                                                              i.      None

1.      I started out by not using a threshold function because it was extra processing I didn’t want to give up

2.      I used zero as my natural threshold

3.      Negative number naturally result in a negative number when multiplied to a positive one which would inhibit

4.      Positive numbers would result in a positive number when multiplied resulting in activation

5.      When compared with the Sigmoid function, except for adjusting values because the range is different, they both worked similarly

                                                            ii.      Sign Function

1.      I tried the sign function because it was the least processing of the three threshold functions in the CS161 book.

2.      The results were very discrete, I had trouble implementing turning because it required different levels of activation

3.      All results were now either positive one, or negative one.

4.      This threshold function was insufficient

5.      Equation

a.      if (data[i]>=0) data[i]=BaseOne; else if (data[i]<0) data[i]=-BaseOne;

                                                          iii.      Sigmoid function

1.      I decided to try this function out because it was the fanciest

2.      Results were nice and smooth compared to the sign function

3.      Varying degrees of turns, movements, and signal emission was allowed

4.      Took a lot of processing to calculate the exponential function slowed down by a factor of two

5.      Equation

a.      data[i]=(BaseOne/(1+exp(-(data[i]/BaseOne)))+0.5);

                                                           iv.      Approximated Sigmoid function

1.      I decided to combine the approximate shape of the sigmoid function and maintain the speed of linear ones

2.      The approximated sigmoid function has three segments

a.      Zero segment

b.      Linear rise

c.      One segment

3.      It worked better than the Sign function

4.      It was faster than the sigmoid function

5.      Equation

a.      if (data[i]<-5000) data[i]=0;

else if (data[i]>5000) data[i]=BaseOne;

else data[i]=(data[i]+5000)*BaseOne/10000;

 

Experiments:

I.                     Initial testing of the physics of the environment

a.      Initial testing involved getting the bugs to move and making sure that they would genetically evolve.

b.      Movement seemed jerky and in continual circles

                                                              i.      The angle of turn was multiplied by too great of a factor

                                                            ii.      And jerky movement caused by direct forward and backwards movement, no transformation through mass and acceleration.

                                                          iii.      Reduced the angle of turn factor, movement seemed more natural

c.      Population either exploded or collapsed

                                                              i.      Too easy to reproduce, or too hard to.  Can’t get evolution with population collapse, and population explosion caused system to slow down to much to evolve in a reasonable time.

                                                            ii.      Attempts to tweak this the physics of mating and reproduction failed.

1.      Population equilibrium is a delicate balance that is hard to achieve

2.      Tried to manually adjust the amount of food available

a.      Was not responsive enough, by the time food adjusted, population had already exploded.

b.      Residual energy from things eaten in the past

3.      Decided to just cap population at set sizes

a.      Worked well

b.      A bit god like to be realistic

d.      Smells either spread and stayed too long, or dissipated before it was detected

                                                              i.      Smells would increase to infinite and linger forever

                                                            ii.      Smells would reach 0 before it had a chance to spread at all

                                                          iii.      Introduced the idea of Smell Conservation

1.      Allowed smells to behave more realistic

II.                   Trials to improve speed of the simulation

a.      System was only allowing a few hundred bugs to be simulated

b.      Tried to time execution time of each segment of code

c.      Determined it was a algorithmic representation of cycling through smells and determining nearby objects that slowed everything down

d.      Introduced smell regions to speed up cycle times

e.      Introduced neighbor lists to further speed up cycle times and to reduce the order of the program by a factor of the number of objects in the world

III.                  Trials to evolve coordinated group activities

a.      Tried to obtain coordinated defense and attack

b.      Bugs were allowed to modify the five chemical signals to communicate

c.      No coordinated behavior other than herding evolved

                                                              i.      Herding evolved due to mating being geographically bound, groups of bugs had a easier time mating than bugs who wander off

                                                            ii.      Bugs not as easily killed in groups did come into play but had a relatively small effect

                                                          iii.      Very likely that bugs were just confused by the parallel smells because bugs only had 9 neurons in the hidden layer at this stage

IV.               Trials after Separated smells

a.      Smells were separated into discrete signals for each bug type, food, and gender along with possible chemical signals the bugs can emit

b.      Smells were a lot nicer to visualize

c.      Easier to see when the bugs emit smells but still hard to determine what the bugs were doing with smells

d.      No still no more advance behavior than simple herding behavior

V.                 Making the world Flat

a.      Bugs tended to move in the same direction all the time to the lower right.

b.      Removed wrapping so bugs get stuck at the corners to determine if it was a visual effect or if bugs really moved in that direction

c.      Many more bugs got stuck in the lower right corner, and bugs in the upper left migrates towards the lower right

d.      Determined that problem lay in calculating new position, 0.5 was added before converting to an integer in order to round.  This was gradually pushing all the bugs to the lower right corner.

VI.               Trials after including a heading of nearby friendly bug into sensors

a.      When a bug detects Signal 6, it would include the heading of a nearby friendly bug as part of its input to the neural net

b.      Complicated attacking or defending behavior still haven’t appeared

c.      Interesting things such as bugs of the same type meeting and changing directions occurred

                                                              i.      Almost appears as though bugs were avoiding each other

VII.              Trials after including a fitness selector into system

a.      Fitness determined the probability of mating whenever mating occurred before.

b.      Probability from 0 to 1

c.      All the bugs started dying off

d.      Fitness was lost too fast had to adjust fitness indicators

e.      Ran out of time

Evaluation/Conclusions:

I.                    I was not able to evolve hunting or other higher coordinated behavior other than simple herding, and reaction from nearby friendly type bugs with just pheromones.

a.      Group activities such as hunting turns out to be quite complicated and a simple pheromone signal is not enough to use to coordinate with.  Especially since the signal is shared between all the bugs types.

b.      Even being able to see the heading of a friendly bug is not enough to coordinate hunting with.

II.                 Maybe I was beginning to see the animats evolving collision avoidance with pheromones, but I did not have enough time to continue further in this venue

a.      Animats would be heading towards each other and one would start going in circles, or veer away.

b.      Sometimes they would veer towards each other.

c.      I believe this was just random or they were veering towards other bugs that I wasn’t watching because I had no selectional pressure for the bugs to avoid friendly types.  I did have very high selectional pressure for the bugs to mate, so I can understand how veering towards each other would be beneficial.

III.               A more realistic environment turned out to be worse to evolve animats in because it was just too complicated and the focus becomes designing the environment than evolving neural nets.

a.      When comparing to the results that my roommate got, his animats were all doing something interesting compared to mine, and he used much fewer animats.

                                                              i.      He had two hundred animats at most, while I at times had thousands.  And the fewest I’ve had was like 500.

                                                            ii.      His model is a generational one, with mating based on fitness only and was guaranteed.  With elite ants passing into the next generation.

                                                          iii.      My model was too dependent on stabilizing population

                                                           iv.      Death was impossible in his simulations so that allowed him to evolve using very few animats.

b.      I could not tell what generation an animat was because it’s hard to figure out what generation the child of a first generation animat and a seventh generation animat would be.

c.      Because animats could die, it was very possible that animats that would have done really well would have died off before it had a chance to mate.

                                                              i.      In fact, if an animat that can hunt really well and can’t mate, nothing would come of it.  Mating is so necessary and vital that hunting probably isn’t even evolved at all.

IV.              Speed is very important; once I was able to simulate animats at a more reasonable speed I was able to observe more behaviors.

a.      It does make a large difference if the world is written efficiently even in this day and age when computers are very fast.

b.      Once again comparing the speed of my simulations versus my roommate’s

                                                              i.      My simulation was able to run ten times more animats and still be a reasonable speed.

                                                            ii.      My simulation included smells, mating, fighting, eating, and moving, and had a layer of 16 hidden neurons in the end.

                                                          iii.      I believe my roommates had only eating and moving and when he added smells he always claimed it slowed down the system greatly.

c.      I was able to do much more theoretical work after I increased the speed of my simulations.

                                                              i.      Two thirds of the time I was attempting to speed up the simulation and test the physics of the world

                                                            ii.      Though during that time I was also trying to get coordinated hunting, the last Third of the time after I got my simulations to be fast enough was I finally able to progress in any sense with testing my main hypothesis

V.                 All results are analyzed through visual inspection statistical generation limited

 

Status:

I.                    Windows Graphical Interface

a.      Done

II.                 World where animats can interact in

a.      Done

III.               Smell World for pheromone propagation

a.      Done

IV.              Basic animats structure and neural matrix

a.      Done

V.                 Attempting to get animats to perform some kind of behavior

a.      Mating - Done

b.      Eating - Done

c.      Attacking - Done

d.      Using Chemical signal - Attempted but results inconclusive

VI.              Attempting to get animats to perform group coordinated behavior

a.      Attempted but failed

VII.            Making simulation efficient

a.      Done

VIII.         Process separate worlds on other computers and interfacing them through the network

a.      Not attempted but dreamed of

IX.              Statistical Generation

a.      Limited to population and count of food

X.                 Logfiles

a.      Done


Appendix:

 

References:

theForger’s Win32 API Tutorial

http://www.winprog.org/tutorial/

 

Michael Chiu’s project used in comparison studies

 

Sample Log File:

Moved 1 distance to 330.773000

We see the other bug of type 65 and we are type 65

Moved 3 distance to -19.716000

Moved 5 distance to 322.120000

Moved 3 distance to 507.927000

Moved -2 distance to -6.79000

We see the other bug of type 66 and we are type 65

Fitness for mating 4946

Type: 65 - Mates with Type:66

Moved 5 distance to 459.552000

Moved -2 distance to -23.705000

Moved -2 distance to 222.516000

Type: 65 - Eats

Moved 5 distance to -67.31000

Type: 65 - Eats

Moved 5 distance to -19.343000

Moved 3 distance to 28.950000

Moved 3 distance to 323.0

Moved 3 distance to 177.0

Moved 3 distance to 434.0

Moved -2 distance to 23.21000

Moved 5 distance to 177.387000

Moved 3 distance to -5.31000

Moved 3 distance to 319.678000

Moved -2 distance to 129.714000

Moved -2 distance to 210.0

Moved 5 distance to 597.0

Moved 3 distance to 352.613000

Moved 5 distance to 295.447000

Moved 5 distance to -33.371000

Moved -2 distance to 141.502000

Moved 5 distance to 145.192000

Moved -2 distance to 237.788000

Moved 3 distance to 340.0

We see the other bug of type 65 and we are type 66

Moved 5 distance to -144.179000

Moved 3 distance to 225.0

We see the other bug of type 65 and we are type 65

Moved 3 distance to 1.373000

Moved 3 distance to 478.0

Moved 0 distance to 240.861000

Moved 5 distance to 5.0

Moved 3 distance to 182.919000

Moved 3 distance to 39.646000

We see the other bug of type 65 and we are type 65

Moved 5 distance to 95.162000

Moved 3 distance to 367.0

Moved 3 distance to 426.275000

Moved 2 distance to 155.812000

Moved 5 distance to 146.0

Moved 3 distance to 336.0

Moved 0 distance to 15.0

Moved 3 distance to -12.0

Moved 3 distance to 137.287000

Moved 5 distance to 209.136000

Moved 3 distance to 211.0

Moved 3 distance to 148.0

Moved -2 distance to 296.642000

Moved 3 distance to 43.229000

Moved 4 distance to 310.63000

Moved 2 distance to 292.0

Moved -2 distance to 198.0

Moved 4 distance to 241.354000

We see the other bug of type 66 and we are type 66

Moved 5 distance to 293.29000

Moved 5 distance to 94.704000

Moved 5 distance to 26.712000

Moved 3 distance to -123.0

Type: 66 - Eats

Moved 5 distance to 336.0

Moved -2 distance to 4.0

Moved 3 distance to 141.0

Moved 0 distance to 47.119000

Moved -2 distance to 197.16000

Moved 3 distance to -20.612000

Moved 0 distance to 60.613000

Moved 5 distance to 192.0

Moved 3 distance to 423.0

Moved 3 distance to 316.530000

Moved 0 distance to 170.0

Moved 4 distance to 178.149000

Moved 3 distance to 395.31000

Type: 34 - Eats

Moved 0 distance to 276.493000

Moved 3 distance to -134.0

Moved 3 distance to 309.294000

We see the other bug of type 34 and we are type 34

Moved 3 distance to 255.0

Moved 3 distance to 451.928000

Moved 3 distance to 341.721000

Moved 5 distance to 401.732000

Moved 3 distance to 33.981000

Moved 5 distance to 358.511000

Moved 0 distance to 223.124000

Moved 0 distance to 517.0

We see the other bug of type 34 and we are type 33

Fitness for mating 4967

Type: 33 - Mates with Type:34

Moved 0 distance to 177.556000

Moved 3 distance to 23.720000

Moved 3 distance to 207.0

Moved -2 distance to 109.893000

Moved 5 distance to 431.805000

We see the other bug of type 34 and we are type 34

Moved 3 distance to 296.0

Moved 3 distance to 230.111000

We see the other bug of type 33 and we are type 33

Moved 3 distance to -234.0

We see the other bug of type 34 and we are type 34

Moved 5 distance to 425.0

Moved 0 distance to 202.858000

 

This data was basically used to determine what actions were performed and how the bugs were moving, and certain messages were included and taken out depending on the goal of the experiment, all trials tended to generate >10MB files, I will not include all of them.


Screen Shots:

Very early screen shot of initial setup and tests.  Group 1 bugs are seen clumping together in huge amounts.  This was near the initial testing and setup of the world.

 

The circled portions are type 1 bugs, which have learned to reproduce easily by clumping together.  Notice how type 1 bugs has a populations of 503 while type 2 bugs have 57, and type 3 bugs only have 14.  This run was done early in the experiment when the population was capped at 500.  Before I perfected the smells and before I initiated the neighborhood map.

 

Type 3 bugs are clumping together at the type, then type one bugs in the middle, and type 2 bugs on the bottom.  It’s interesting because the starting points of the bugs were, type 2-upper left, type 1-upper right, type 3-lower right.  This was also run before the smell map was perfected and the population cap was still 500.

 

Latest screenshots, there are indicators above each bugs’s head to show which activators are working.  The smell world was tweaked some more giving a nice puffy type look.  Picture looks much better in color.

 

 

/*Mainwin.cpp*/

 

#define STRICT

#define GUIMode

 

#include "memleak.h"

#include <stdlib.h>

#include <fstream.h>

#include <windows.h>

#include <time.h>

#include <string>

 

#include "constants.h"

#include "Neighbor.h"

 

class Things *World=NULL;

class Things *Deadlist=NULL;

class Smells *smellmap=NULL;

struct Neighbor *nearlist=NULL;

 

//Setup the default values for numbers that can be modified during runtime.

int tvalue=50;                                  //Delay between each cycle in milliseconds

int num3Bugs=100;                        //Number of type 3 bugs to add

int num2Bugs=200;                        //Number of type 2 bugs to add

int num1Bugs=400;                        //Number of type 1 bugs to add

int numFood=700;                         //Number of food to add

int worldtime=0;                         //World starts at time 0

int totalEnergy=0;                //Energy of world is 0

int num1Left=0;                                 //Counting variable for type 1 bug

int num2Left=0;                                 //Counting variable for type 2 bug

int num3Left=0;                                 //Counting variable for type 3 bug

int foodLeft=0;                                 //Counting variable for food

int DecayTime=500;                //Duration food lasts

int DefaultMass=10000;  //How much energy each piece of food gives

bool autoFeed=true;               //Autofeed mode is on

bool randomFood=true;             //Randomize food location is on

bool DRAWON=true;                        //Drawing bugs is on

bool ShowSig=true;                //Show the bugs activator signals is on

int foodLev=500;                         //The number of food to maintain in auto feed mode

int foodXpos=maxX>>1;             //XPosition of food is center of screen

int foodYpos=maxY>>1;             //YPosition of food is center of screen

int foodRadius=maxX>>1;    //Radius of food zone is half the largest dimension

int foodDiam=maxX;                //Diameter of food zone is largest dimension

int group1x=700;                         //X and Y pos of the Center of

int group1y=150;                         //Type 1 Bug group

int group2x=150;                         //X and Y pos of the Center of

int group2y=150;                         //Type 2 Bug group

int group3x=900;                         //X and Y pos of the Center of

int group3y=600;                         //Type 3 Bug group

 

//Files for output

ofstream logfile;                        //Logfile of activities and statistics

ofstream timefile;                //Time file to determine bottle necks

int PrgExit=0;                                  //Exit variable false

unsigned int globtime=0;//Global time is 0

 

#include "resource.h"

//#include "NeuralNet.h"

#include "Smells.h"

#include "World.h"

#include "Thing.h"

#include "Bugs.h"

#include "Food.h"

#include "Obstacle.h"

 

 

using namespace std;

// My procedures

 

//Windows GUI stuff will not be commented.

// Options Dialog box procedure

BOOL CALLBACK DProc

       (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

       HWND ShowSignal = GetDlgItem(hwnd, IDC_ShowSignal);

       HWND DrawBug = GetDlgItem(hwnd, IDC_DrawBug);

       HWND AutoFeed = GetDlgItem(hwnd, IDC_AutoFeed);

       HWND RandomFood = GetDlgItem(hwnd, IDC_RandomFood);

       HWND FoodLev = GetDlgItem(hwnd, IDC_FoodLev);

       HWND FoodGenXpos = GetDlgItem(hwnd, IDC_FoodGenXpos);

       HWND FoodGenYpos = GetDlgItem(hwnd, IDC_FoodGenYpos);

       HWND FoodRadius = GetDlgItem(hwnd, IDC_FoodRadius);

       HWND FoodMass = GetDlgItem(hwnd, IDC_FoodMass);

       HWND FoodDur = GetDlgItem(hwnd, IDC_FoodDur);

       HWND G1X = GetDlgItem(hwnd, IDC_G1X);

       HWND G1Y = GetDlgItem(hwnd, IDC_G1Y);

       HWND G2X = GetDlgItem(hwnd, IDC_G2X);

       HWND G2Y = GetDlgItem(hwnd, IDC_G2Y);

       HWND G3X = GetDlgItem(hwnd, IDC_G3X);

       HWND G3Y = GetDlgItem(hwnd, IDC_G3Y);

 

       char a[50];

       int           Length = 0;

 

 

  switch(message)

  {

       case WM_INITDIALOG :

              itoa(group1x,a,10);

              SetWindowText(G1X, TEXT(a));

              itoa(group1y,a,10);

              SetWindowText(G1Y, TEXT(a));

              itoa(group2x,a,10);

              SetWindowText(G2X, TEXT(a));

              itoa(group2y,a,10);

              SetWindowText(G2Y, TEXT(a));

              itoa(group3x,a,10);

              SetWindowText(G3X, TEXT(a));

              itoa(group3y,a,10);

              SetWindowText(G3Y, TEXT(a));

              itoa(foodLev,a,10);

              SetWindowText(FoodLev, TEXT(a));

              itoa(foodXpos,a,10);

              SetWindowText(FoodGenXpos, TEXT(a));

              itoa(foodYpos,a,10);

              SetWindowText(FoodGenYpos, TEXT(a));

              itoa(foodRadius,a,10);

              SetWindowText(FoodRadius, TEXT(a));

              itoa(DefaultMass,a,10);

              SetWindowText(FoodMass, TEXT(a));

              itoa(DecayTime,a,10);

              SetWindowText(FoodDur, TEXT(a));

              if (autoFeed) {

                     SendMessage(AutoFeed,BM_SETCHECK,BST_CHECKED,0);

              }

              else {

                     SendMessage(AutoFeed,BM_SETCHECK,BST_UNCHECKED,0);

              }

              if (DRAWON) {

                     SendMessage(DrawBug,BM_SETCHECK,BST_CHECKED,0);

              }

              else {

                     SendMessage(DrawBug,BM_SETCHECK,BST_UNCHECKED,0);

              }

              if (ShowSig) {

                     SendMessage(ShowSignal,BM_SETCHECK,BST_CHECKED,0);

              }

              else {

                     SendMessage(ShowSignal,BM_SETCHECK,BST_UNCHECKED,0);

              }

              if (randomFood) {

                     SendMessage(RandomFood, BM_SETCHECK,BST_CHECKED,0);

              }

              else {

                     SendMessage(RandomFood, BM_SETCHECK,BST_UNCHECKED,0);

              }

 

              return TRUE ;

             

       case WM_COMMAND :

              switch (LOWORD (wParam))

              {

              case IDOK :

                     Length = GetWindowTextLength(G1X);

                     GetWindowText(G1X, a, Length+1);

                     group1x = (int)atoi(a);

                     Length = GetWindowTextLength(G1Y);

                     GetWindowText(G1Y, a, Length+1);

                     group1y = (int)atoi(a);

                     Length = GetWindowTextLength(G2X);

                     GetWindowText(G2X, a, Length+1);

                     group2x = (int)atoi(a);

                     Length = GetWindowTextLength(G2Y);

                     GetWindowText(G2Y, a, Length+1);

                     group2y = (int)atoi(a);

                     Length = GetWindowTextLength(G3X);

                     GetWindowText(G3X, a, Length+1);

                     group3x = (int)atoi(a);

                     Length = GetWindowTextLength(G3Y);

                     GetWindowText(G3Y, a, Length+1);

                     group3y = (int)atoi(a);

                     Length = GetWindowTextLength(FoodLev);

                     GetWindowText(FoodLev, a, Length+1);

                     foodLev = (int)atoi(a);

                     Length = GetWindowTextLength(FoodGenXpos);

                     GetWindowText(FoodGenXpos, a, Length+1);

                     foodXpos = (int)atoi(a);

                     Length = GetWindowTextLength(FoodGenYpos);

                     GetWindowText(FoodGenYpos, a, Length+1);

                     foodYpos = (int)atoi(a);

                     Length = GetWindowTextLength(FoodRadius);

                     GetWindowText(FoodRadius, a, Length+1);

                     foodRadius = (int)atoi(a);

                     foodDiam=foodRadius<<1;

                     Length = GetWindowTextLength(FoodMass);

                     GetWindowText(FoodMass, a, Length+1);

                     DefaultMass = (int)atoi(a);

                     Length = GetWindowTextLength(FoodDur);

                     GetWindowText(FoodDur, a, Length+1);

                     DecayTime = (int)atoi(a);

 

                     if (SendMessage(AutoFeed,BM_GETCHECK,0,0)==BST_CHECKED) {

                           autoFeed=true;

                     }

                     else {

                           autoFeed=false;

                     }

                     if (SendMessage(ShowSignal,BM_GETCHECK,0,0)==BST_CHECKED) {

                           ShowSig=true;

                     }

                     else {

                           ShowSig=false;

                     }

                     if (SendMessage(DrawBug,BM_GETCHECK,0,0)==BST_CHECKED) {

                           DRAWON=true;

                     }

                     else {

                           DRAWON=false;

                     }

                     if (SendMessage(RandomFood,BM_GETCHECK,0,0)==BST_CHECKED) {

                           randomFood=true;

                     }

                     else {

                           randomFood=false;

                     }

 

 

                     EndDialog (hwnd, 0) ;

                     return TRUE ;

              case IDCANCEL :

                     EndDialog (hwnd, 1) ;

                     return TRUE ;

              }

              break ;

       }

       return FALSE ;

}

 

BOOL CALLBACK D2Proc

       (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

 

       char a[50];

       HWND speedset = GetDlgItem(hwnd, IDC_EDIT2);

       int           Length = 0;

       int           grabbed_data;

 

    switch(message)

    {

       case WM_INITDIALOG :

              itoa(tvalue,a,10);

              SetWindowText(speedset, TEXT(a));

              return TRUE ;

             

       case WM_COMMAND :

              switch (LOWORD (wParam))

              {

              case IDOK :

 

                     Length = GetWindowTextLength(speedset);

                     GetWindowText(speedset, a, Length+1);

 

                     grabbed_data = (int)atoi(a);

                          

                     EndDialog (hwnd, grabbed_data) ;

                     return TRUE ;

              case IDCANCEL :

                     EndDialog (hwnd, tvalue) ;

                     return TRUE ;

              }

              break ;

       }

       return FALSE ;

}

 

BOOL CALLBACK D3Proc

       (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

 

       char a[50];

       HWND Bug1Num = GetDlgItem(hwnd, IDC_Bug1);

       HWND Bug2Num = GetDlgItem(hwnd, IDC_Bug2);

       HWND Bug3Num = GetDlgItem(hwnd, IDC_Bug3);

       HWND FoodNum = GetDlgItem(hwnd, IDC_Food);

       int           Length = 0;

       int           grabbed_data;

 

    switch(message)

    {

       case WM_INITDIALOG :

              itoa(num1Bugs,a,10);

              SetWindowText(Bug1Num, TEXT(a));

              itoa(num2Bugs,a,10);

              SetWindowText(Bug2Num, TEXT(a));

              itoa(num3Bugs,a,10);

              SetWindowText(Bug3Num, TEXT(a));

              itoa(numFood,a,10);

              SetWindowText(FoodNum, TEXT(a));

              return TRUE ;

             

       case WM_COMMAND :

              switch (LOWORD (wParam))

              {

              case IDAdd :

 

                     Length = GetWindowTextLength(Bug1Num);

                     GetWindowText(Bug1Num, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     num1Bugs=grabbed_data;

 

                     Length = GetWindowTextLength(Bug2Num);

                     GetWindowText(Bug2Num, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     num2Bugs=grabbed_data;

 

                     Length = GetWindowTextLength(Bug3Num);

                     GetWindowText(Bug3Num, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     num3Bugs=grabbed_data;

 

                     Length = GetWindowTextLength(FoodNum);

                     GetWindowText(FoodNum, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     numFood=grabbed_data;

 

                     EndDialog (hwnd, 1) ;

                     return TRUE;

              case IDSave :

 

                     Length = GetWindowTextLength(Bug1Num);

                     GetWindowText(Bug1Num, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     num1Bugs=grabbed_data;

 

                     Length = GetWindowTextLength(Bug2Num);

                     GetWindowText(Bug2Num, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     num2Bugs=grabbed_data;

 

                     Length = GetWindowTextLength(Bug3Num);

                     GetWindowText(Bug3Num, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     num3Bugs=grabbed_data;

 

                     Length = GetWindowTextLength(FoodNum);

                     GetWindowText(FoodNum, a, Length+1);

                     grabbed_data = (int)atoi(a);

                     numFood=grabbed_data;

 

                     EndDialog (hwnd, 0) ;

                     return TRUE ;

              }

              break ;

       }

       return FALSE ;

}

 

// Window Procedure called by Windows

 

LRESULT CALLBACK WindowProcedure

    (HWND hwnd, unsigned int message, WPARAM wParam, LPARAM lParam)

{

       static HINSTANCE hInstance;

       static HBITMAP h_bug1F = NULL;

       static HBITMAP h_bug1M = NULL;

       static HBITMAP h_bug2F = NULL;

       static HBITMAP h_bug2M = NULL;

       static HBITMAP h_bug3F = NULL;

       static HBITMAP h_bug3M = NULL;

       static HBITMAP h_food = NULL;

       RECT a={0,0,maxX,maxY};

 

       OPENFILENAME lpofn;

  PAINTSTRUCT ps;

       HBITMAP bmp;

       HDC hdcBug1M,hdcBug1F, hdcBug2M, hdcBug2F, hdcBug3M, hdcBug3F, hdcFood;

       HDC hdc;

       int ret;

       char maskstring[]="Bug World Type Files (*.BUG)\0*.BUG\0All Files (*.*)\0*.*\0";

       char filename[500]="";

 

       ZeroMemory(&lpofn, sizeof(lpofn));

       filename[0]=0;

       lpofn.lStructSize=sizeof(OPENFILENAME);

       lpofn.hwndOwner=hwnd;

       lpofn.lpstrFilter=maskstring;

       lpofn.lpstrCustomFilter=NULL;

       lpofn.lpstrFile=filename;

       lpofn.nMaxFile=500;

       lpofn.Flags=OFN_ENABLESIZING|OFN_OVERWRITEPROMPT|OFN_EXPLORER;

       lpofn.lpstrInitialDir=".\\";

       lpofn.lpstrDefExt = "BUG";

 

       switch (message)

       {

       case WM_CREATE:

              srand((unsigned)time( NULL ));

 

              smellmap=new Smells[(maxx+1)*(maxy+1)];

             

              ret = SetTimer(hwnd, ID_TIMER, tvalue, NULL);

              if(ret == 0)

                     MessageBox(hwnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION);

 

 

        h_bug1M = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_Bug1M));

        if(h_bug1M == NULL)

            MessageBox(hwnd, "Could not load BUG!", "Error", MB_OK | MB_ICONEXCLAMATION);

        h_bug1F = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_Bug1F));

        if(h_bug1F == NULL)

            MessageBox(hwnd, "Could not load BUG!", "Error", MB_OK | MB_ICONEXCLAMATION);

        h_bug2M = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_Bug2M));

        if(h_bug2M == NULL)

            MessageBox(hwnd, "Could not load BUG!", "Error", MB_OK | MB_ICONEXCLAMATION);

        h_bug2F = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_Bug2F));

        if(h_bug2F == NULL)

            MessageBox(hwnd, "Could not load BUG!", "Error", MB_OK | MB_ICONEXCLAMATION);

        h_bug3M = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_Bug3M));

        if(h_bug3M == NULL)

            MessageBox(hwnd, "Could not load BUG!", "Error", MB_OK | MB_ICONEXCLAMATION);

        h_bug3F = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_Bug3F));

        if(h_bug3F == NULL)

            MessageBox(hwnd, "Could not load BUG!", "Error", MB_OK | MB_ICONEXCLAMATION);

        h_food = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_FOOD));

        if(h_food == NULL)

            MessageBox(hwnd, "Could not load Food!", "Error", MB_OK | MB_ICONEXCLAMATION);

 

              hInstance = ((LPCREATESTRUCT) lParam)->hInstance;

 

    hdc = BeginPaint(hwnd, &ps);

              FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

 

              a.left=maxX+50;

              a.right=maxX+200;

              a.top=50;

              a.bottom=maxY;

              FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

    EndPaint(hwnd, &ps);

 

              break;

    case WM_DESTROY:

        DeleteObject(h_bug1M);

        DeleteObject(h_bug1F);

        DeleteObject(h_bug2M);

        DeleteObject(h_bug2F);

        DeleteObject(h_bug3M);

        DeleteObject(h_bug3F);

        DeleteObject(h_food);

 

              KillTimer(hwnd, ID_TIMER);

              DoMyExit();

        PostQuitMessage (0);

        return 0;

              //case WM_NCPAINT:

                           //Clears the memory screen

                           //FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

                           //break;

       case WM_TIMER:

              CycleSmell();

              Cycle();

 

              InvalidateRect(hwnd,NULL,FALSE);

              break;

       case WM_PAINT:

        BITMAP s_bug1M, s_bug1F, s_bug2M, s_bug2F, s_bug3M, s_bug3F, s_Food;

        hdc = BeginPaint(hwnd, &ps);

 

                           ShowStats(hdc);

                           ShowSmellMap(hdc);

 

                           if (DRAWON) {

                                  hdcBug1M = CreateCompatibleDC(hdc);

                                  bmp = (HBITMAP)SelectObject(hdcBug1M,h_bug1M);

                                  GetObject(h_bug1M, sizeof(s_bug1M), &s_bug1M);

                                  hdcBug1F = CreateCompatibleDC(hdc);

                                  bmp = (HBITMAP)SelectObject(hdcBug1F,h_bug1F);

                                  GetObject(h_bug1F, sizeof(s_bug1F), &s_bug1F);

                                  hdcBug2M = CreateCompatibleDC(hdc);

                                  bmp = (HBITMAP)SelectObject(hdcBug2M,h_bug2M);

                                  GetObject(h_bug2M, sizeof(s_bug2M), &s_bug2M);

                                  hdcBug2F = CreateCompatibleDC(hdc);

                                  bmp = (HBITMAP)SelectObject(hdcBug2F,h_bug2F);

                                  GetObject(h_bug2F, sizeof(s_bug2F), &s_bug2F);

                                  hdcBug3M = CreateCompatibleDC(hdc);

                                  bmp = (HBITMAP)SelectObject(hdcBug3M,h_bug3M);

                                  GetObject(h_bug3M, sizeof(s_bug3M), &s_bug3M);

                                  hdcBug3F = CreateCompatibleDC(hdc);

                                  bmp = (HBITMAP)SelectObject(hdcBug3F,h_bug3F);

                                  GetObject(h_bug3F, sizeof(s_bug3F), &s_bug3F);

                                  hdcFood = CreateCompatibleDC(hdc);

                                  bmp = (HBITMAP)SelectObject(hdcFood,h_food);

                                  GetObject(h_food, sizeof(s_Food), &s_Food);

 

                                  //Cycles through objects and draws objects on screen

                                  Draw(hdc, s_bug1M, s_bug1F, s_bug2M, s_bug2F, s_bug3M, s_bug3F, s_Food,

                                         hdcBug1M, hdcBug1F, hdcBug2M, hdcBug2F, hdcBug3M, hdcBug3F, hdcFood);

                                 

                                  //*/

                                  DeleteDC(hdcFood);

                                  DeleteDC(hdcBug1F);

                                  DeleteDC(hdcBug1M);

                                  DeleteDC(hdcBug2F);

                                  DeleteDC(hdcBug2M);

                                  DeleteDC(hdcBug3F);

                                  DeleteDC(hdcBug3M);

                           }

 

        EndPaint(hwnd, &ps);

                           //DrawScreen(hwnd);

              break;

       case WM_COMMAND: //Menu handler labels

              switch(LOWORD(wParam))

              {

              case IDCLOSE:

                     DoMyExit();

                     PostQuitMessage (0);

                     return 0;

              case IDHELP:

                     return 0;

              case IDStart:

                     Begin(hwnd);

                     return 0;

              case ID_Save:

                     lpofn.lpstrTitle="Save Bugs";

                     ret=GetSaveFileName(&lpofn);

                     if (ret) SaveWorld(filename);

                     return 0;

              case ID_Load:

                     lpofn.lpstrTitle="Load Bugs";

                     ret=GetOpenFileName(&lpofn);

                     if (ret) LoadWorld(filename);

                     return 0;

              case IDSettings:

                     ret=DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DProc);

                     if (ret==0) {

                     } else if (ret==1) {

                     }

                     return 0;

              case IDAdd:

                     ret=DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG3), hwnd, D3Proc);

                     if (ret==0) {

                     } else if (ret==1) {

                           Begin(hwnd);

                     }

                     return 0;

              case IDSpeed:

                     tvalue=DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG2), hwnd, D2Proc);

                     KillTimer(hwnd, ID_TIMER);

                     ret = SetTimer(hwnd, ID_TIMER, tvalue, NULL);

                     if(ret == 0)

                           MessageBox(hwnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION);

                     return 0;

              case IDClear:

                     ClearWorld();

      hdc = BeginPaint(hwnd, &ps);

                     FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

      EndPaint(hwnd, &ps);

                     InvalidateRect(hwnd,&a,TRUE);

                     return 0;

              }

 

              return 0;

 

    }

    return DefWindowProc (hwnd, message, wParam, lParam );

}

 

int WINAPI WinMain (HINSTANCE hinst, HINSTANCE previnst, LPSTR cmd, int ncmd)

{

       HWND mwnd;

       MSG msg;

       WNDCLASS wndclass;

       int pix;

 

       //Initialize the log files

       logfile.open("log.dat");

       timefile.open("time.txt");

 

       //Create and clear the Neighborhood list.

       pix=(maxX+1)*(maxY+1);

       nearlist=new struct Neighbor[pix];

  memset(nearlist,0,sizeof(struct Neighbor)*pix);

 

  wndclass.style = 0;

  wndclass.lpfnWndProc = WindowProcedure; // window procedure: mandatory

  wndclass.cbClsExtra = 0;

  wndclass.cbWndExtra = 0;

  wndclass.hInstance = hinst;         // owner of the class: mandatory

  wndclass.hIcon = 0;

  wndclass.hCursor = ::LoadCursor (0, IDC_ARROW); // optional

  wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); // optional

  wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); //Setup the menu system, 0 if none

  wndclass.lpszClassName = "MainWndClass"; // mandatory

 

      

       RegisterClass(&wndclass);

 

       mwnd=CreateWindow("MainWndClass","NeuralBugs",WS_OVERLAPPEDWINDOW,

              0,0,maxX+256,maxY+256,

              (HWND) NULL, (HMENU) NULL, hinst, (LPVOID) NULL);

 

       ShowWindow(mwnd,ncmd);

       UpdateWindow(mwnd);

 

 

  while (GetMessage(&msg, (HWND) NULL, 0, 0))

  {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

  }

 

       return 0;

}

 

/********************************************************************************************

Constant declaration, and global variable declarations

********************************************************************************************/

#ifndef constants_h

#define constants_h

#include <stdio.h>

#include <fstream.h>

 

const int ID_TIMER = 1;

extern int tvalue;                       //Time between each cycle in milliseconds

extern int worldtime;                    //Age in cycles of the world

extern int num3Bugs;              //Number of type 3 bugs to initialize

extern int num2Bugs;              //Number of type 2 bugs to initialize

extern int num1Bugs;              //Number of type 1 bugs to initialize

extern int numFood;                      //Number of food to initialize

extern int totalEnergy;           //Total energy in the world (yet unused)

extern int num1Left;              //Number of type 1 bugs currently

extern int num2Left;              //Number of type 2 bugs currently

extern int num3Left;              //Number of type 3 bugs currently

extern int foodLeft;              //Number of food left in world

 

extern bool ShowSig;              //Show signal flag (draws the bugs activators on screen above bugs)

extern bool DRAWON;                      //Drawon flag (Turns on and off drawing of bugs)

extern bool autoFeed;                    //Autofeed flag (Enables the program to automatically feed bugs)

extern bool randomFood;           //Random food flag (Randomly places food in a range round food center)

 

extern int foodLev;                      //Level to keep food above for autofeed

extern int foodXpos;              //X position of the food center

extern int foodYpos;              //Y position of the food center

extern int foodRadius;            //Radius of the food region

extern int foodDiam;              //Diameter of the food region

extern int DefaultMass;           //Mass of new food

extern int DecayTime;                    //Decay time of new food

extern int group1x;                      //X and Y pos of the Center of

extern int group1y;                      //Type 1 Bug group

extern int group2x;                      //X and Y pos of the Center of

extern int group2y;                      //Type 2 Bug group

extern int group3x;                      //X and Y pos of the Center of

extern int group3y;                      //Type 3 Bug group

 

 

//Screen size boundaries

const int maxX=1024;

const int maxY=768;

const int maxy=48;

const int maxx=64;

const int maxall=maxy*maxx;

 

//Smell constants

const int SmellMAX=0x00ffffff; //Smell signal strength cap

const int SigNum=10;                            //Number of signals for smells

 

const int EnergyLoss=200;                //Energy loss when becomming corpse

 

const int B1LifeTime=400;                //Lifetime of bug

const int B1TimeLeft=380;                //Time left in world before you can have offspring

const int B1InfantEnergy=6000;//Energy at birth

const int B1EnergyNeed=3000;      //Energy Needed to have offspring.

const int B1CorpseMass=300;       //Energy left in corpse

const int B1HP=14;                                     //Hit points

const int B1AP=2;                                             //Action/Attack points

 

const int B2LifeTime=600;                //Lifetime of bug

const int B2TimeLeft=540;                //Time left in world before you can have offspring

const int B2InfantEnergy=8000;//Energy at birth

const int B2EnergyNeed=4000;      //Energy Needed to have offspring.

const int B2CorpseMass=500;       //Energy left in corpse

const int B2HP=35;                                     //Hit points

const int B2AP=5;                                             //Action/Attack points

 

const int B3LifeTime=500;                       //Lifetime of bug

const int B3TimeLeft=420;                       //Time left in world before you can have offspring

const int B3InfantEnergy=10000;   //Energy at birth

const int B3EnergyNeed=5000;             //Energy Needed to have offspring.

const int B3CorpseMass=3500;             //Energy left in corpse

const int B3HP=41;                                            //Hit points

const int B3AP=10;                                            //Action/Attack points

 

//Unused constants or constants used for generic objects not used

const int newenergy=10000;

const int Lifespan=500;

const int initialMass=5000;       //Not used

 

//Mutation rate of 30%

#define MU_Rate                          0.30

//Cross over rate of 30%

#define CR_Rate                          0.30

 

/*************************

ID TAGS

*************************/

#define ID_Obstacle        0x08

#define ID_Food                          0x04

#define ID_Bug1M                  0x11

#define ID_Bug1F                  0x12

#define ID_Bug2M                  0x21

#define ID_Bug2F                  0x22

#define ID_Bug3M                  0x41

#define ID_Bug3F                  0x42

#define ID_Bug1                          0x10

#define ID_Bug2                          0x20

#define ID_Bug3                          0x40

#define ID_Bug                           0x73

 

 

/******************************

Smell Gradient Conversion

******************************/

const int SCTnum = 20;                   //Number of signal levels

 

//Smell bounds

const int SmellConvBound[]= {0x000004,0x000008,0x000010,0x000020,

                                                                                                0x000040,0x000080,0x000100,0x000200,

                                                                                                0x000400,0x000800,0x001000,0x002000,

                                                                                                0x004000,0x008000,0x010000,0x020000,

                                                                                                0x040000,0x080000,0x100000,0x200000};

 

//Color levels

const int SmellConvVal[]=         {0x002,0x004,0x008,0x00C,

                                                                                                0x00F,0x01F,0x02F,0x03F,

                                                                                                0x04F,0x05F,0x06F,0x07F,

                                                                                                0x08F,0x09F,0x0AF,0x0BF,

                                                                                                0x0CF,0x0DF,0x0EF,0x0FF};

 

/***************************************************

Smells

***************************************************/

//Originally parrallel distributed smells.

//const int Smell1M[] = {0x00000100,0x00000F00,0x00000D00,0x00000100,0x00000300};

//const int Smell1F[] = {0x00000000,0x00000E00,0x00000F00,0x00000100,0x00000200};

//const int Smell2M[] = {0x00000F00,0x00000000,0x00000400,0x00000100,0x00000100};

//const int Smell2F[] = {0x00000F00,0x00000100,0x00000100,0x00000100,0x00000000};

//const int Smell3M[] = {0x00000200,0x00000100,0x00000100,0x00000E00,0x00000F00};

//const int Smell3F[] = {0x00000100,0x00000000,0x00000200,0x00000F00,0x00000400};

//const int SmellFood[]={0x00000F00,0x00000F00,0x00000F00,0x00000F00,0x00000F00};

//const int SmellDead[]={0x00000100,0x00000200,0x00000200,0x00000300,0x00000300};

const int Smell1=0x000000FF;

const int Smell2=0x000000FF;

const int Smell3=0x000000FF;

const int SmellM=0x000000FF;

const int SmellF=0x00000000;

const int SmellFood=0x000000FF;

const int SmellDead=0x00000000;

 

/***************

Global World objects

***************/

//World list (all object in world),

//and dead list (dead objects that should be erased off screen)

extern class Things *World, *Deadlist;

 

//Smell map for all the smells

extern class Smells *smellmap;

 

//Neighbor list, for finding nearby objects faster

extern struct Neighbor *nearlist;

 

//Output files

extern ofstream logfile;

extern ofstream timefile;

#endif

 

 

/*Bugs.h*/

#ifndef bugs_h

#define bugs_h

#include "NeuralNet.h"

#include "Thing.h"

 

class Bug:public Things {

public:

       Bug();

       Bug(Bug &copy);

       ~Bug();

       void Cycle();

       bool gone();

       bool moveon();

       int GetEnergy();

       int GetAction(int i);

       void Emmit();

       void Smell();

       int Near(Things *&lst);

       void ExternalSense(int A1Sig[], int A2Sig[], int A3Sig[], bool Front, bool Back);

       void operator+(class Bug &rhs);          //+ is the mating operator

       void operator-(class Bug &rhs);          //- is the attacking operator

       void operator+=(class Food &meal);//+= is the eating operator

       friend ostream & operator<<(ostream &out, Bug &B);

       friend istream & operator>>(istream &in, Bug &B);

 

protected:

       int HP,                                  //Hitpoints, 0=dead

                     AP,                                //Attack points, amount to decrease other hp by.

                     Energy,                    //Energy level, 0=starvation

                     TimeLeft,            //Time left alive in cycles, 0=died of old age

                     heading,             //heading of bug in degree*1000000

                     Fitness;             //Fitness of bug from 0 to 100

 

       neuralnet brain;

       /*

       ********Basic on off

       Mate > 1

       Eat > 1

       Attack > 1

 

       ********Discretized continuous numbers

       TurnLeft * 100

       TurnRight * 100

       MoveForward / BASEONE

       MoveBack / BASEONE

       EmmitSmell[]

       */

       neuralvec actions;

       /*

       A1Sig[], A2Sig[], A3Sig[]  : chemcal strength at left antenna, right, and back

       HP, Energy, posx, posy, heading : It can know certain values of its own state.

       */

       neuralvec senses;

};

 

class Bug1:public Bug {

public:

       Bug1();

       ~Bug1();

       void operator+(class Bug1 &rhs);         //+ is the mating operator

private:

};

 

class Bug2:public Bug {

public:

       Bug2();

       ~Bug2();

       void operator+(class Bug2 &rhs);         //+ is the mating operator

private:

};

 

class Bug3:public Bug {

public:

       Bug3();

       ~Bug3();

       void operator+(class Bug3 &rhs);         //+ is the mating operator

private:

};

 

#endif

 

/*********************************************************

Bugs class

Specifies 3 types of bugs

Each of the 3 type of bugs are derived from the bug

base class, and the bug base class is derived from the

Things base class.

*********************************************************/

#include "memleak.h"

#include <stdlib.h>

#include <math.h>

#include <iostream.h>

#include "Constants.h"

#include "Obstacle.h"

#include "Neighbor.h"

#include "Smells.h"

#include "Bugs.h"

#include "Food.h"

#include "Thing.h"

 

/*********************************************************

Class functions

*********************************************************/

Bug::Bug() {

       ID=ID_Bug;                 //Setup the ID tag, will be overwritten

       HP=100;                                  //Setup initial Health, will be overwritten

       AP=0;                                    //Setup attack strength will be overwritten

       mass=100;                         //Setup mass of bug will be overwritten

       Energy=100;                //Setup the energy left will be overwritten

       TimeLeft=100;        //Setup time bug has left to live will be overwritten

       Fitness=5000;        //Give initial fitness (was added in later trials)

       heading=(rand()%360)*1000000;  //Random initial heading

 

       brain.setinputs(10+3*SigNum);//Setup the input size

       brain.setoutputs(3+SigNum);  //8+SigNum-5  Setup output size

       brain.addlayer(16);                             //Add a hidden layer with 16 neurons

       brain.randomize();                              //Randomize neural weights

       actions.setsize(3+SigNum);   //8+SigNum-5  ..Resize the actions vector

       senses.setsize(10+3*SigNum); //Resize the senses vector

       senses[0]=BaseOne;                              //The 0 sense is always BaseOne which

                                                                                                        //maps to 1,  This allows weights to

                                                                                                        //determine the threshold.

       next=NULL;                                                           //Clear next field used by link list.

}

 

Bug::Bug(Bug & copy) {

       //Copy constructor

       ID=copy.ID;                //Copy the Type ID

       HP=copy.HP;                //Copy the health

       AP=copy.AP;                //Copy the Attach strength

       mass=copy.mass; //Copy the mass

       Energy=copy.Energy;    //Copy energy level

       TimeLeft=copy.TimeLeft;//Copy lifetime left

       heading=copy.heading;  //Copy heading

       brain=copy.brain;      //Copy the brain neural net

       actions=copy.actions;  //Copy resulting actions

       senses=copy.senses;    //Copy the sense input

       next=copy.next;        //Copy the next pointer

}

 

Bug1::Bug1() {

       //Instantiate type 1 bug

       if (rand()%2==0) { //Randomize the assignemnt of male/female

              //Male

              SetSmell(2,Smell1);

              SetSmell(0,SmellM);

              ID=ID_Bug1M;

       }

       else {

              //Female

              SetSmell(2,Smell1);

              SetSmell(0,SmellF);

              ID=ID_Bug1F;

       }

 

       //Randomize the starting position of this bug to be close to

       //the starting point of this group.

       posx=group1x+rand()%200-100;

       posy=group1y+rand()%200-100;

 

       //If position is off the screen, readjust to be on the edge

       //I don't want to send these bugs to the other side of the screen

       if (posx<0) posx=0;

       if (posx>maxX) posx=maxX;

       if (posy<0) posy=0;

       if (posy>maxY) posy=maxY;

 

       //Setup the variables to equal the amounts setup in the constants file.

       HP=B1HP;

       AP=B1AP;

       mass=B1CorpseMass;

       Energy=B1InfantEnergy;

       TimeLeft=B1LifeTime;

}

 

Bug2::Bug2() {

       //Instantiate type 2 bug

       if (rand()%2==0) {   //Randomize the assignment of male/female

              //Male

              SetSmell(3,Smell2);

              SetSmell(0,SmellM);

              ID=ID_Bug2M;

       }

       else {

              //Female

              SetSmell(3,Smell2);

              SetSmell(0,SmellF);

              ID=ID_Bug2F;

       }

 

       //Randomize the starting position of this bug to be close to

       //the starting point of this group.

       posx=group2x+rand()%200-100;

       posy=group2y+rand()%200-100;

 

       //If position is off the screen, readjust to be on the edge

       //I don't want to send these bugs to the other side of the screen   

       if (posx<0) posx=0;

       if (posx>maxX) posx=maxX;

       if (posy<0) posy=0;

       if (posy>maxY) posy=maxY;

 

       //Setup the variables to equal the amounts setup in the constants file.   

       HP=B2HP;

       AP=B2AP;

       mass=B2CorpseMass;

       Energy=B2InfantEnergy;

       TimeLeft=B2LifeTime;

}

 

Bug3::Bug3() {

       //Instantiate type 3 bug

       if (rand()%2==0) { //Randomize the assignment of male/female

              //Male

              SetSmell(4,Smell3);

              SetSmell(0,SmellM);

              ID=ID_Bug3M;

       }

       else {

              //Female

              SetSmell(4,Smell3);

              SetSmell(0,SmellF);

              ID=ID_Bug3F;

       }

 

       //Randomize the starting position of this bug to be close to

       //the starting point of this group.

       posx=group3x+rand()%200-100;

       posy=group3y+rand()%200-100;

 

       //If position is off the screen, readjust to be on the edge

       //I don't want to send these bugs to the other side of the screen

       if (posx<0) posx=0;

       if (posx>maxX) posx=maxX;

       if (posy<0) posy=0;

       if (posy>maxY) posy=maxY;

 

       //Setup the variables to equal the amounts setup in the constants file.

       HP=B3HP;

       AP=B3AP;

       mass=B3CorpseMass;

       Energy=B3InfantEnergy;

       TimeLeft=B3LifeTime;

}

 

//Empty destructors

Bug::~Bug() {

}

Bug1::~Bug1() {

}

Bug2::~Bug2() {

}

Bug3::~Bug3() {

}

 

void div(int a[],int b, int c[]) {

       //Helper function to divide each smell in a by b and store in c

       //Not used anymore, was used in an earlier version

       int i;

       for (i=0;i<SigNum;i++) {

              c[i]=a[i]/b;

       }

}

 

void Bug::Emmit() {

       //Emmits smell of bug, common for all bugs.

       int x,y;

      

       //Map position onto the position for the smell map

       x=posx>>4;

       y=posy>>4;

 

       //Sets smell on the smell map to include smell emitted by bug

       smellmap[maxx*(y)+(x)].SetSmell(Signal);

}

 

void Bug::Smell() {

       //Bugs sampling the smell map at three spots

       int s1[SigNum];

       int s2[SigNum];

       int s3[SigNum];

       int x,y, tmp;

 

//The following commented out code used to calculate the three spots dynamically

//But was too slow, so I tried to use a static mapping.

//     int y1,y2,x1,x2, x3, y3, tmpr;

//  int piover4;

//     bool fblock, bblock;

//     double adjhead;

 

//Heading are in degrees * 1000000, so adjhead would be in radians.

//     adjhead=(heading/180000000)*3.14159265358979323846264338327950288;

 

//     piover4=(3.14159265358979323846264338327950288419 / 4);

//     y1=(int)(sin(adjhead+piover4)+0.5);

//     x1=(int)(cos(adjhead+piover4)+0.5);

//     y2=(int)(sin(adjhead-piover4)+0.5);

//     x2=(int)(cos(adjhead-piover4)+0.5);

//     y3=-(int)(sin(adjhead)+0.5);

//     x3=-(int)(cos(adjhead)+0.5);

 

       //Calculate smell map position

       x=posx>>4;

       y=posy>>4;

 

       //Static spot below bug

       tmp=maxx*(y+1)+x;

       if (tmp>=0 && tmp <maxall) smellmap[tmp].GetSmell(s3);

 

       //Static spot above and to right of bug

       tmp=maxx*(y-1)+x+1;

       if (tmp>=0 && tmp <maxall) smellmap[tmp].GetSmell(s1);

      

       //Static spot above and to left of bug

       tmp=maxx*(y-1)+x-1;

       if (tmp>=0 && tmp <maxall) smellmap[tmp].GetSmell(s2);

 

       //Store smell samples into sensors on bug.

       ExternalSense(s1,s2,s3,0,0);

}

 

void Bug::ExternalSense(int A1Sig[], int A2Sig[], int A3Sig[], bool Front, bool Back) {

       //Commit smell samples to bug sensors, Front and Back was used but is ignored now

       int i, Sig1;

 

       //For each signal, store it in the senses after signal 7, and SigNum spaces apart.

       //Allows us to loop through SigNum only once, and store all three values semi-parallel

       for(i=0;i<SigNum;i++) {

              senses[8+i]=A1Sig[i];

              senses[8+SigNum+i]=A2Sig[i];

              senses[8+SigNum+SigNum+i]=A3Sig[i];

       }

 

       Sig1=A1Sig[5]+A2Sig[5]+A3Sig[5];  //Signal 5 will be to tell other bugs to go to head where I'm heading

       senses[6]=Sig1;                                                                   //Temporarily store in location 6 of sense vector

}

 

void Bug::operator+(Bug &rhs) {

       //+ is the mating operator

       Bug *child;

 

       //Create a new bug

       child=new Bug;

       //Set heading to 0

       child->heading=0;

       //Copy initiating parent's neural matrix

       child->brain=brain;

 

       //Do a crossover with passive parent with CR_Rate specified in constants

       child->brain.cross(rhs.brain, CR_Rate);

       //Mutate the weights with a rate MU_Rate specified in constants

       child->brain.mutate(MU_Rate);

      

       //Insert the Child into world

       child->next=World;

       World=child;

 

       //Decrease the energy of the parents

       rhs.Energy-=AP*5;

       Energy-=AP*5;

}

 

void Bug1::operator+(Bug1 &rhs) {

       //+ is the mating operator

       Bug1 *child;

 

       //Make sure that both parents have enough energy and are old enough

       if (rhs.Energy>=B1EnergyNeed && Energy>=B1EnergyNeed

                     && rhs.TimeLeft<B1TimeLeft && TimeLeft<B1TimeLeft)     {

              //Create new bug

              child=new Bug1;

              //Randomize heading

              child->heading=rand()%360000000;

 

              //Setup position of child to be between parents

              child->Setx((rhs.posx+posx)>>1);

              child->Sety((rhs.posy+posy)>>1);

 

              //Copy the brain of active parent

              child->brain=brain;

              //Crossover with teh brain of passive parent

              child->brain.cross(rhs.brain, CR_Rate);

              //Mutate the brain

              child->brain.mutate(MU_Rate);

 

              //Insert the child into the beginning of the World link list

              child->next=World;

              World=child;

 

              //Decrease the energy of the parents

              rhs.Energy-=B1EnergyNeed;

              Energy-=B1EnergyNeed;

//            logfile << "Mate Success!" << endl;

       }

}

 

void Bug2::operator+(Bug2 &rhs) {

       //+ is the mating operator

       Bug2 *child;

 

       //Make sure both parents have enough energy and are old enough

       if (rhs.Energy>=B2EnergyNeed && Energy>=B2EnergyNeed

                     && rhs.TimeLeft<B2TimeLeft && TimeLeft<B2TimeLeft)     {

              //Create a new bug

              child=new Bug2;

              //Randomize heading

              child->heading=rand()%360000000;

 

              //Setup position of child to be between parents

              child->Setx((rhs.posx+posx)>>1);

              child->Sety((rhs.posy+posy)>>1);

 

              //Copy the brain of active parent

              child->brain=brain;

              //Crossover with teh brain of passive parent

              child->brain.cross(rhs.brain, CR_Rate);

              //Mutate the brain

              child->brain.mutate(MU_Rate);

 

              //Insert the child into the beginning of the World link list

              child->next=World;

              World=child;

 

              //Decrease the energy of the parents

              rhs.Energy-=B2EnergyNeed;

              Energy-=B2EnergyNeed;

//            logfile << "Mate Success!" << endl;

       }

}

 

void Bug3::operator+(Bug3 &rhs) {

       //+ is the mating operator

       Bug3 *child;

 

       //Make sure both parents have enough energy and are old enough

       if (rhs.Energy>=B3EnergyNeed && Energy>=B3EnergyNeed

                     && rhs.TimeLeft<B3TimeLeft && TimeLeft<B3TimeLeft)     {

              //Create a new bug

              child=new Bug3;

              //Randomize heading

              child->heading=rand()%360000000;

 

              //Setup position of child to be between parents

              child->Setx((rhs.posx+posx)>>1);

              child->Sety((rhs.posy+posy)>>1);

 

              //Copy the brain of active parent

              child->brain=brain;

              //Crossover with teh brain of passive parent

              child->brain.cross(rhs.brain, CR_Rate);

              //Mutate the brain

              child->brain.mutate(MU_Rate);

 

              //Insert the child into the beginning of the World link list

              child->next=World;

              World=child;

 

              //Decrease the energy of the parents

              rhs.Energy-=B3EnergyNeed;

              Energy-=B3EnergyNeed;

//            logfile << "Mate Success!" << endl;

       }

}

 

 

void Bug::operator-(Bug &rhs) {

       //- is the attacking operator

 

       //The bug attacked looses health based on the attack power of this bug

       rhs.HP-=AP;

 

       //In a desparate attempt to protect itself, the other bug injures this bug

       //But only does damage of the other bug's attack power / 8

       HP-=rhs.AP>>3;

 

       //This bug is tired from attacking, looses energy proportional to attack power

       Energy-=AP;

}

 

void Bug::operator+=(Food &meal) {

       int i;

 

       //+= is the eating operator

       //One mouthfull has 200*AP energy in it.

       //Determine if the food has enough for one mouthfull

       if ((i=meal.GetMass())>AP*200) {

              //Take one mouthfull

              meal.Taken(AP*200);

              Energy+=AP*200;

       }

       else {

              //Take what's left

              meal.Taken(i);

              Energy+=i;

       }

}

 

void Bug::Cycle() {

       //When the world cycles through one instant, this is done for all bugs.

       Things *lst, *idx;

       int i;

       int typ,match, dist;

 

       //Decrease lifetime by one

       TimeLeft--;

       //Decrease energy by 1

       Energy-=1;

 

       //Copy current value to sensors

       senses[1]=HP;

       senses[2]=Energy;

       senses[3]=posx;

       senses[4]=posy;

       senses[5]=heading;

       senses[7]=TimeLeft;

       //Smell the world to copy rest of values

       Smell();

 

       //Input senses into neural net

       brain.input(senses);

       //Propagate the values

       brain.propagate();

       //Retrieve output

       actions=brain.output();

//     logfile << actions << endl;

 

       //Determine nearby items.

       typ=Near(lst);

 

       //We are sensing some other bug's signal, pay attention to same type headings

       match=(0xF0&ID);

       if (senses[6]>50) {

              if ((typ&0xF0)==match) {

                     //Reset sense 6 to 0

                     senses[6]=0;

                     //Go through all the object in world

                     for(idx=lst;idx!=NULL; idx=idx->lstnext) {

                           //If it matches a bug of the same type

                           if ((idx->ID&0xF0)==match) {

                                  //Randomly or if this is the first one

                                  if (senses[6]==0 || rand()%2) {

                                         //Set sense 6 to be heading of other bug

                                         //Bugs can see where one of their friends is heading

                                         senses[6]=((Bug *)idx)->heading;

                                         logfile << "We see the other bug of type " << idx->ID << " and we are type " << ID << endl;

                                  }

                           }

                     }

              }

       }

       else //Sense 6 is 0 otherwise

              senses[6]=0;

 

       //Mate > 1  Initiator neuron

       //always receptive to mating

 

  //Type ID of bugs with the same type but of the other gender

       match=(0xF0&ID) | ((0x03&ID)^0x03);

 

       //If mating activator on, and a compatible bug is nearby

       if (actions[0]>1 && ((typ&ID_Bug)==match)) {

             

              //For each nearby object

              for(idx=lst; idx!=NULL; idx=idx->lstnext) {

                     //Check compatibility

                     if (idx->ID==match) {

                           //Compatible

                           logfile << "Fitness for mating " << Fitness << endl;

                           Fitness+=100;

 

                           //Bugs more likely to be successful if fitness is higher

                           if (rand()%5000<Fitness) {

//                         logfile << "Type: " << ID << " - ";

//                         logfile << "Mates with Type:" << idx->ID << endl;

 

                                  //Use to correct mating operator for the type of bug

                                  if ((ID&ID_Bug1)!=0)

                                         *(Bug1 *)this+*(Bug1 *)idx;

                                  if ((ID&ID_Bug2)!=0)

                                         *(Bug2 *)this+*(Bug2 *)idx;

                                  if ((ID&ID_Bug3)!=0)

                                         *(Bug3 *)this + *(Bug3 *)idx;

 

                                  //Only one successful mate per cycle per bug

                                  break;

                           }

                     }

              }

       }

 

//Eat > 1

       if (actions[1]>1 && ((typ&ID_Food)==ID_Food) ) {

              //Go through near list

              for(idx=lst; idx!=NULL; idx=idx->lstnext) {

                     //If food

                     if (idx->ID==ID_Food) {

                           //Increase Fitness

                           Fitness+=5;

//                         logfile << "Type: " << ID << " - ";

//                         logfile << "Eats" << endl;

                           //Eat some food

                           *this+=*(Food *)idx;

 

                           //Eat only one mouthfull per cycle

                           break;

                     }

              }

       }

 

       //Attack > 1

       //Bugs not of the same type

       match=((ID & 0xF0) ^ (ID_Bug1|ID_Bug2|ID_Bug3));

      

       if (actions[2]>1 && ((typ&match)!=0) ) {

              //For all the nearby things

              for(idx=lst; idx!=NULL; idx=idx->lstnext) {

                     //If we have a bug of a different type

                     if ((idx->ID&match)!=0) {

                           Fitness+=25;

//                         logfile << "Type: " << ID << " - ";

//                         logfile << "Attacks Type " << idx->ID << endl;

                           //Attack them

                           *this-*(Bug *)idx;

 

                           //Only one attack per cycle

                           break;

                     }

              }

       }

//*/

 

       //We want to make the bug tired for trying to mate, eat or attack

       //And we lower their fitness if they try

       if (actions[0]>1) {

              Energy-=10;

              Fitness-=1;

       }

       if (actions[1]>1) {

              Energy-=2;

              Fitness-=2;

       }

       if (actions[2]>1) {

              Energy-=5;

              Fitness-=3;

       }

 

       //TurnLeft

       heading-=actions[3]*300;

 

       //TurnRight

       heading+=actions[4]*300;

 

       //MoveForward / BASEONE

       dist=actions[5]*5/BaseOne;

      

       //MoveBack / BASEONE

       dist-=actions[6]*2/BaseOne;

       logfile << "Action1 " << actions[3] << "." << actions[3] << endl;

       logfile << "Action2 " << actions[4] << "." << actions[4] << endl;

       logfile << "Moved " << dist << " distance to " << heading/1000000 << "." << abs(heading %1000000) << endl; 

 

       //The further a bug moved, the more energy is lost

       Energy-=abs(dist);

 

       //Move the bug

       Move(heading, dist);

      

       //Sets the output smells, to the actions of the smell activators on the bug

       for(i=0;i<SigNum-5;i++)

              SetSmell(5+i,actions[i+7]);

 

}

 

int Bug::GetEnergy() {

       //Return energy left of bug

       return Energy;

}

 

bool Bug::gone() {

       //Bug is gone if it dies

       //It can die because it has negative energy

       if (Energy<0)

              logfile << ID << "Type Died from Exhaustion" << endl;

       //It can also die because it has no health

       if (HP<0)

              logfile << ID << "Type Died from Murder" << endl;

       //It can also die of old age

       if (TimeLeft<=0)

              logfile << ID << "Type Died from Old Age" << endl;

 

       //If the bug is gone, return true

       if (Energy<0 || HP<0 || TimeLeft<=0) {

              return true;

       }

 

       //The bug is still alive

       return false;

}

 

bool Bug::moveon() {

       //We are not able to move ontop of another bugs exact pixel location

       return false;

}

 

int Bug::Near(Things *&obj) {

       //Determines the objects near the bug

       Neighbor *idx;

       Things *lst;

       int typ;

       int pos, i,j;

       //Using a square with a radius of 3 as a approximation to

       //Speed up cycle time

       const int radius=3;

 

       //Initialize return type, and list

       typ=0;

       lst=NULL;

      

       //Determine starting position (x-radius, y-radius)

       pos=(posy-radius)*maxX+posx-radius;

 

       //If it is off the beginning corner or end corner, then readjust

       //So no exceptions occur

       if (pos<0) pos=0;

       else if (posy>=(maxY-2*radius)) pos=(maxY-2*radius)*maxX-radius;

 

       //Searches for a square of radius for objects

       for (i=0;i<2*radius;i++, pos+=maxX) {

              for (j=0;j<2*radius;j++,pos++) {

                     //Copies everything in the linked list of the nearlist into the returning list of objects

                     for(idx=nearlist[pos].next;idx!=NULL;idx=idx->next) {

                           //Don't copy itself

                           if (idx->obj==this) continue;

 

                           //Or the Bits of the Type ID of this object into the return type

                           typ=typ|idx->obj->ID;

                          

                           //Add the object into the near list

                           idx->obj->lstnext=lst;

                           lst=idx->obj;

                     }

              }

       }

 

/* This was the old code which scanned through the world and determined if it was

within a certain distance of this bug, it increased our order by a factor of N.

 

       for(idx=World;idx!=NULL;idx=idx->next) {

              if (idx!=this && Distance(*idx)<10) {

                     typ=typ|idx->ID;

                     if (lst==NULL) {

                           lst=idx;

                           lst->lstnext=NULL;

                     }

                     else {

                           idx->lstnext=lst;

                           lst=idx;

                     }

              }

       }

*/

 

       //Return the list and the type

       obj=lst;

       return typ;

}

 

int Bug::GetAction(int i) {

       //Return the action vector of bug

       return actions[i];  

}

 

 

ostream & operator<<(ostream &out, Bug &B) {

       //Stream output operator just outputs all information of bug

       //Used for saving the bugs into a file

       int i;

 

       out << B.ID << endl;

       out << B.posx << endl;

       out << B.posy << endl;

       out << B.mass << endl;

       for (i=0;i<SigNum;i++) {

              out << B.Signal[i] << endl;

       }

       out << B.HP << endl;

       out << B.AP << endl;

       out << B.Energy << endl;

       out << B.TimeLeft << endl;

       out << B.heading << endl;

       out << B.brain;

       out << B.actions;

       out << B.senses;

       return out;

}

 

istream & operator>>(istream &in, Bug &B) {

       //Stream input operator sets bug information based on input

       //Used to load a bug that was saved with the << operator.

       int i;

 

       in >> B.ID;

       in >> B.posx;

       in >> B.posy;

       in >> B.mass;

       for (i=0;i<SigNum;i++) {

              in >> B.Signal[i];

       }

 

       in >> B.HP;

       in >> B.AP;

       in >> B.Energy;

       in >> B.TimeLeft;

       in >> B.heading;

       in >> B.brain;

       in >> B.actions;

       in >> B.senses;

       return in;

}

 

/*Expongen.c*/

#include <math.h>

#include <stdlib.h>

#include "expongen.h"

 

double rande(void)          /*Functions*/

{                           /*This function remaps the random*/

                            /*function to the range of 0-1*/

    return (float)(rand())/(float)RAND_MAX;

}

 

double EXP(double mean)

{ /* RETURNS EXPONENTIALLY DISTR RV */

   double result;

   if (mean <0.0) { /*Can't use negative values for mean*/

       exit(1);

       }

    result = - (mean) * log(rande()); /*Make it exponential*/

   return(result);  /*Return the result*/

}

 

/******************************************************************

Food class

Derived from base class of thing

******************************************************************/

#include "memleak.h"

#include "Thing.h"

#include "Food.h"

#include "Bugs.h"

#include "Smells.h"

#include "Constants.h"

#include <stdlib.h>

 

Food::Food() {

       //Set the Food ID

       ID=ID_Food;

       //Set the Mass of the food

       mass=DefaultMass;

       //Set the time left before decay of food

       decay=DecayTime<<3;

       //Set signal 1 of smell to food smell

       SetSmell(1,SmellFood);

 

       //If randomFood flag set, randomize location based on center and radius

       if (randomFood) {

              posx=foodXpos-foodRadius+rand()%(foodDiam);

              posy=foodYpos-foodRadius+rand()%(foodDiam);

             

              //If off screen readjust position to be on screen again

              if (posx<0) posx+=foodRadius;

              if (posy<0) posy+=foodRadius;

              if (posy>=maxY) posy=posy>>1;

              if (posx>=maxX) posx=posx>>1;

       }

       else {

              //Otherwise just place at center location

              posx=foodXpos;

              posy=foodYpos;

       }

       //Place item on neighbor list.

       Move(0,0);

}

 

Food::Food(Bug &corpse) {

       //Convert a dead bug into a peice of food

       ID=ID_Food;

       SetSmell(1,SmellDead);

       //The mass of the food equals the nergy of the bug - some loss of energy

       mass=corpse.GetEnergy()-EnergyLoss;

 

       //Set position equal to corpse position

       posx=corpse.Getx();

       posy=corpse.Gety();

      

       //Set Decay

       decay=DecayTime;

 

       //Place item on neighbor list

       Move(0,0);

}

 

Food::~Food() {

}

 

bool Food::gone() {

       //Food is gone if eaten or decayed

       if (decay==0 || mass<=0) return true;

       return false;

}

 

void Food::Taken(int amount) {

       //Amount is eaten from this food clump

       mass-=amount;

}

 

void Food::Emmit() {

       //Food emits a smell

       int smell[SigNum];

       GetSmell(smell);

       smellmap[maxx*(Gety()>>4)+(Getx()>>4)].SetSmell(Signal);

}

 

void Food::Cycle() {

       //Decay the food by 1

       decay--;

}

 

bool Food::moveon() {

       //You can move on the food, it is a small clump, a bug can walk on.

       return true;

}

 

int Food::GetAction(int i) {

       //Food doesn't have actions.

       return 0;

}

 

 

/*NerualMatrix.cpp*/

#ifndef GUIMode

#include <iostream.h>

#endif

 

#include "memleak.h"

#include <stdlib.h>

#include <memory.h>

#include "NeuralNet.h"

#include "expongen.h"

 

/***********************************

Neural Matrix class

***********************************/

neuralmatrix::neuralmatrix(int r, int c) {

//Constructor to create matrix of size r X c

       row=r;

       col=c;

       rowcol=r*c;

       recval.setsize(col);

       if (rowcol==0) data=NULL;

       else data=new int[rowcol+1];

       recmat=NULL;

       next=NULL;

}

 

neuralmatrix::neuralmatrix(const neuralmatrix & n) {

//Copy constructor

       row=n.row;

       col=n.col;

       rowcol=n.rowcol;

       recmat=new neuralmatrix();

       if (n.recmat!=NULL)

              *recmat=*n.recmat;

       recval=n.recval;

       if (rowcol==0) data=NULL;

       else data=new int[rowcol+1];

       memcpy(data,n.data,rowcol*sizeof(int));

       next=NULL;

}

 

neuralmatrix::~neuralmatrix() {

//Destructor, frees memory.

       if (data!=NULL) delete [] data;

       if (recmat!=NULL) delete recmat;

       data=NULL;

       recmat=NULL;

 

}

 

void neuralmatrix::recurrent(bool flag) {

//Sets the recurrent mode

       if (flag) {

              if (recmat!=NULL) {

                     delete recmat;

              }

              recmat=new neuralmatrix(col,col);

              recmat->randomize();

       }

       else {

              if (recmat!=NULL) {

                     delete recmat;

              }

       }

}

 

void neuralmatrix::setsize(int r, int c) {

//Resizes the neural matrix

//Deletes and redeclares matrix space

       if (data!=NULL) {

              delete [] data;

              data=NULL;

       }

       if (recmat!=NULL) delete recmat;

       recmat=NULL;

       row=r;

       col=c;

       rowcol=r*c;

       recval.setsize(c);

       data=new int[rowcol+1];

}

 

void neuralmatrix::reset() {

//Zero out the neural matrix

       if (data!=NULL) {

              memset(data,0,rowcol*sizeof(int));

       }

       if (recmat!=NULL) {

              recmat->reset();

       }

       recval.reset();

}

 

void neuralmatrix::randomize() {

//Randomize the neural matrix.

       int v;

       if (data!=NULL) {

              for(int i=0;i<rowcol;i++) {

                     v=rand()%BaseOne;

                     memcpy(&data[i],&v,sizeof(int));

              }

       }

       recval.reset();

}

 

int neuralmatrix::get(int x, int y) {

//Retrieve a specific value from the neuralmatrix

       if (x<row && y<col) {

              return data[x*col+y];

       }

       return 0;

}

 

void neuralmatrix::setval(int r, int c, int value) {

//Set the value of a specific row and column to value.

       if (r<row && c<col) {

              data[r*col+c]=value;

       }

}

 

//The overloaded = operator

neuralmatrix & neuralmatrix::operator=(const neuralmatrix & copy) {

       //Delete data already in matrix

       if (data!=NULL) {

              delete [] data;

              data=NULL;

       }

       if (recmat!=NULL) {

              delete recmat;

              recmat=NULL;

       }

 

       //Reset row and column size

       row=copy.row;

       col=copy.col;

       rowcol=copy.rowcol;

 

       //copy the recurrency matrix if not null.

       if (copy.recmat!=NULL) {

              recmat=new neuralmatrix;

              *recmat=*copy.recmat;

       }

       else

              recmat=NULL;

      

       recval=copy.recval;

       //Declare new space if necessary

       if (rowcol==0) data=NULL;

       else data=new int[rowcol+1];

 

       //Copy the weights

       memcpy(data,copy.data,rowcol*sizeof(int));

       return *this;

}

 

 

/* Index access overloaded operators */

//To write

int & neuralmatrix::operator[ ](int Index ) {

    if(Index<0 || Index > rowcol) {

                     exit(1);

              }

    return data[Index];

}

 

//To read

int neuralmatrix::operator[ ]( int Index ) const {

    if(Index<0 || Index > rowcol) {

                     exit(1);

              }

    return data[Index];

}

 

//Function to return row size

int neuralmatrix::rsize() {

       return row;

}

 

//Function to return column size

int neuralmatrix::csize() {

       return col;

}

 

void neuralmatrix::cross(const neuralmatrix &p2, double rate) {

//Rate has floating point values from 0 to 1

//Crossover function, will cross this neural matrix with p2, with the rate rate.

       double median;

       unsigned long int midx, ncount, at;

       int which;

 

       //Calculate the rate and

       median=1.0/rate;

       ncount=col*row;

       at=0;

       which=0;

 

       //While we haven't proecessed the whole weight matrix

       while (at<ncount) {

              //Find next crossover point

              midx=(unsigned long int)(EXP(median))+1;

              if (which==1) {

                     which=0;

                     if (midx+at>ncount)

                           midx=ncount-at;

                     //Copy from other matrix

                     memcpy(&data[at],&(p2.data[at]),midx*sizeof(int));

              }

              else {

                     //Keep values from this matrix

                     which=1;

              }

              at+=midx;

       }

}

 

 

/***********************************************************

Applying matrix transforms with different methods of learning

 

************************************************************/

 

void neuralmatrix::transform(neuralvec &from, neuralvec &to, double reinforce, bool recur) {

  int r, c, speedup, speedup2;

  long int result;

  int reinf;

       neuralvec inter(col);

      

       //If recurrency is on, and there is no recurrent information, then setup recurrent info.

       if (recur && recmat==NULL)

              recurrent(recur);

 

  reinf=(int)(reinforce*BaseOne+0.5);

 

       //If recurrency mode, then increase the intermediate value by the result of the recurrent values

       if (recur) {

              recmat->transform(recval,inter,reinforce);

              inter+=from;

       }

 

       //Error check.

  if (row!=from.getsize()) {

    cerr << "Inconsistent vector size for matrix" << endl;

    exit(-1);

  }

 

       //Initialize output vector

  to.setsize(col);

  to.reset();

 

       //Loop to transform

  for (r=0,speedup=0;r<row; r++) {

    for (c=0;c<col; c++, speedup++) {

      speedup2=data[speedup];

                     //multiply

      result=(from[r]*speedup2)/BaseOne;

                     //Add to activation vector

      to[c]+=result;

                    

                     //Memory degradation rate

                     //Active Neuron connection reinforcement phase

                     data[speedup]=speedup2+(result*reinf-1)/BaseOne;

 

    }

  }

 

       //Add recurrent values and Store output for reccurent calculation in next cycle

       if (recur) {

              to+=inter;

              recval=to;

       }

 

}

 

void neuralmatrix::transform(neuralvec &from, neuralvec &to, double reinforce) {

       //Transforms the input from to the output to,

  int r, c, speedup, speedup2;

  long int result;

  int reinf;

 

       //Calculate reinforcement factor

  reinf=(int)(reinforce*BaseOne+0.5);

 

       //Error check.

  if (row!=from.getsize()) {

    cerr << "Inconsistent vector size for matrix" << endl;

    exit(-1);

  }

 

       //Setup the output vector

  to.setsize(col);

  to.reset();

 

       //Loop through to calculate the transformation

  for (r=0,speedup=0;r<row; r++) {

    for (c=0;c<col; c++, speedup++) {

      speedup2=data[speedup];

      result=(from[r]*speedup2)/BaseOne;

      to[c]+=result;

        

                     //Memory degradation rate and

                     //Active Neuron connection reinforcement phase

                     data[speedup]=speedup2+(result*reinf-1)/BaseOne;

 

    }

  }

}

 

/********* No learning on propagate ***********/

void neuralmatrix::transform(neuralvec &from, neuralvec &to) {

       //Transforms the input from to the output to.

  int r, c, speedup;

 

       //Error check

  if (row!=from.getsize()) {

    cerr << "Inconsistent vector size for matrix" << endl;

    exit(-1);

  }

 

       //Setup destination

  to.setsize(col);

  to.reset();

 

       //Efficient loop to multiply using integers

  for (r=0,speedup=0;r<row; r++) {

    for (c=0;c<col; c++, speedup++) {

      to[c]+=(from[r]*data[speedup])/BaseOne;

    }

  }

}

/***********************************************************

End of Transforms section

***********************************************************/

 

ostream & operator<<(ostream & out, neuralmatrix & m) {

  //Output to stream, allows saving to file

       int i;

       out << m.row << endl;

       out << m.col << endl;

 

       for (i=0; i< m.col*m.row; i++) {

              out << m[i] << endl;

       }

       return out;

}

 

istream & operator>>(istream & in, neuralmatrix & m) {

       //Input from stream, allows loading from file.

       int i,r,c;

       in >> r;

       in >> c;

       if (r<0 || c<0) return in;

       m.setsize(r,c);

       for (i=0; i< m.col*m.row; i++) {

              in >> m[i];

       }

       return in;

}

 

/*NeuralNet.cpp*/

#include "memleak.h"

#include <stdlib.h>

#include <memory.h>

#include <fstream.h>

#include <iostream.h>

#include <string.h>

#include "NeuralNet.h"

#include "expongen.h"

 

/****************************************

Neural Net Class

****************************************/

neuralnet::neuralnet(int insize, int outsize) {

//Constructor for the main neural net

//Setup the input storage, and output storage, and

//Setup the neural matrix.

       inputhold.setsize(insize);

       inputnodes=insize;

       outputnodes=outsize;

       outputhold.setsize(outsize);

       network=new neuralmatrix(insize,outsize);

       network->next=NULL;

       neurons=insize*outsize;

}

 

neuralnet::neuralnet(const neuralnet & copy) {

//Copy constructor copies everything

       inputhold=copy.inputhold;

       inputnodes=copy.inputnodes;

       outputnodes=copy.outputnodes;

       outputhold=copy.outputhold;

       neuralmatrix * idx=copy.network;

       neurons=copy.neurons;

       if (idx!=NULL) {

              network=new neuralmatrix(*copy.network);

              neuralmatrix * idx2=network;

              idx=idx->next;

 

              //While we have other hidden layers copy them

              while (idx!=NULL) {

                     idx2->next=new neuralmatrix(*idx);

                     idx=idx->next;

                     idx2=idx2->next;

              }

              idx2->next=NULL;

       }

}

 

neuralnet::~neuralnet() {

//Free up the memory used by the neural net.

       neuralmatrix *idx=network;

       neuralmatrix *idx2=idx;

       idx=idx->next;

       //Goes through all the hidden layers

       while(idx!=NULL) {

              delete idx2;

              idx2=idx;

              idx=idx->next;

       }

       delete idx2;

       network=NULL;

}

 

void neuralnet::reset() {

//Resets all the weights in the neural net

       neuralmatrix *idx=network;

       while (idx!=NULL) {

              idx->reset();

              idx=idx->next;

       }

}

 

void neuralnet::randomize() {

//Randomizes all the weights in the neural net

       neuralmatrix *idx=network;

       while (idx!=NULL) {

              idx->randomize();

              idx=idx->next;

       }

}

 

ostream & operator<<(ostream &out, neuralnet & n) {

//outputs all the information of a neural net into a stream

       neuralmatrix *idx;

       int i;

       out << "NeuralNet" << endl;

       out << n.inputnodes << endl;

       out << n.outputnodes << endl;

       for(idx=n.network, i=0;idx!=NULL;idx=idx->next,i++);

       out << i << endl;

 

       for(idx=n.network;idx!=NULL;idx=idx->next) {

              out << *idx << endl;

       }

       return out;

}

 

istream & operator>>(istream &in, neuralnet & n) {

//Retrieves all information from the stream back into neural net

       neuralmatrix *idx=n.network;

       neuralmatrix *idx2=idx;

       neuralmatrix tmp;

       char cmp[50];

       int i;

 

       in >> cmp;

       if (strcmp(cmp,"NeuralNet")!=0) {

              cerr << "Error loading NueralNet file wrong type." << endl;

       }

       in >> n.inputnodes;

       in >> n.outputnodes;

       in >> i;

 

       idx=idx->next;

       while(idx!=NULL) {

              delete idx2;

              idx2=idx;

              idx=idx->next;

       }

       delete idx2;

       idx=NULL;

       n.network=NULL;

 

       idx2=NULL;

       while (i>0) {

              in >> tmp;

              idx=new neuralmatrix(tmp);

              idx->next=NULL;

              if (idx2==NULL) {

                     n.network=idx;

                     idx2=idx;

              }

              else {

                     idx2->next=idx;

              }

              i--;

       }

       return in;

}

 

void neuralnet::save(const char *st) {

//Saves to a file with name specified in st

       neuralmatrix *idx;

       ofstream savefile(st,ios::out);

       savefile << "NeuralNet" << endl;

       savefile << inputnodes << endl;

       savefile << outputnodes << endl;

      

       for(idx=network;idx!=NULL;idx=idx->next) {

              savefile << *idx << endl;

       }

}

 

 

void neuralnet::load(const char *st) {

//Loads from a file with name specified in st

       neuralmatrix *idx=network;

       neuralmatrix *idx2=idx;

       neuralmatrix tmp;

       char cmp[50];

       ifstream loadfile(st,ios::in);

       loadfile >> cmp;

       if (strcmp(cmp,"NeuralNet")!=0) {

              cerr << "Error loading NueralNet file wrong type." << endl;

       }

       loadfile >> inputnodes;

       loadfile >> outputnodes;

      

       idx=idx->next;

       while(idx!=NULL) {

              delete idx2;

              idx2=idx;

              idx=idx->next;

       }

       delete idx2;

       idx=NULL;

 

       while (!loadfile.eof()) {

              loadfile >> tmp;

              if (idx==NULL) {

                     network=new neuralmatrix(tmp);

                     idx=network;

              }

              else {

                     idx->next=new neuralmatrix(tmp);

                     idx=idx->next;

              }

              idx->next=NULL;

       }

}

 

 

 

void neuralnet::mutate(double rate) {

//Rate has floating point values from 0 to 1

       double median;

       unsigned long int midx, ncount, at;

       bool done;

       neuralmatrix *idx;

 

       median=1.0/rate;

       done=false;

       idx=network;

       ncount=idx->csize()*idx->rsize();

       at=0;

 

       while (!done) {

              midx=(unsigned long int)(EXP(median))+1;

 

              while (midx>0 && !done) {

                     if (midx>ncount) {

                           midx-=ncount;

                           ncount=0;

                           if (idx!=NULL) {

                                  idx=idx->next;

                                  at=0;

                           }

                           if (idx!=NULL) {

                                  ncount=idx->csize()*idx->rsize();

                           }

                           else {

                                  done=true;

                           }

                     }

                     else {

                           (*idx)[at+midx-1]=rand()%BaseOne;

                           ncount-=midx;

                           at+=midx;

                           midx=0;

                     }

              }

             

       }

}

 

void neuralnet::addlayer(int size) {

//Add layer of size to neural net

       neuralmatrix *idx=network;

       bool flag;

       int rcount, ccount;

       neuralmatrix *old, *new1, *new2;

 

       flag=true;

 

       while (idx!=NULL && idx->next!=NULL && idx->next->next!=NULL) {

              idx=idx->next;

       }

       if (idx->next==NULL) {

              old=idx;

              flag=false;

       }

       else

              old=idx->next;

       rcount=old->rsize();

       ccount=old->csize();

       neurons=neurons-rcount*ccount+rcount*size+ccount*size;

       new1=new neuralmatrix(rcount,size);

       new2=new neuralmatrix(size,ccount);

       delete old;

       new2->next=NULL;

       new1->next=new2;

       if (flag) idx->next=new1;

       else network=new1;

}

 

void neuralnet::setinputs(int size) {

//Set the input size

       neuralmatrix *idx;

       inputnodes=size;

       inputhold.setsize(size);

       neurons=neurons-(inputnodes-size)*network->csize();

       idx=new neuralmatrix(size,network->csize());

       idx->next=network->next;

       delete network;

       network=idx;

}

 

void neuralnet::setoutputs(int size) {

//Set the output size

       neuralmatrix *idx, *idx2, *oidx;

       bool flag=true;

       //Goes to the end of the layer.

       for (idx=network, oidx=NULL;idx->next!=NULL; oidx=idx, idx=idx->next) flag=false;

       outputnodes=size;

       outputhold.setsize(size);

       neurons=neurons-(outputnodes-size)*idx->rsize();

       idx2=new neuralmatrix(idx->rsize(),size);

       idx2->next=NULL;

       if (flag) {

         delete network;

         network=idx2;

       }

       else {

         delete idx;

         oidx->next=idx2;

       }

}

 

void neuralnet::input(const neuralvec & nv) {

//Set the input vector

       inputhold=nv;

}

 

neuralvec & neuralnet::output() {

//Return the output vector

       return outputhold;

}

 

void neuralnet::adjust(int layer, int row, int col, int value) {

//Adjust the weight at a specific layer

       neuralmatrix *idx=network;

       while (idx!=NULL && layer>0) {

              layer--;

              idx=idx->next;

       }

       idx->setval(row,col,value);

}

 

neuralnet & neuralnet::operator=(const neuralnet & copy) {

//Overloaded equals operator

       inputhold=copy.inputhold;

       inputnodes=copy.inputnodes;

       outputnodes=copy.outputnodes;

       outputhold=copy.outputhold;

       neuralmatrix * idx=copy.network;

       neurons=copy.neurons;

       if (idx!=NULL) {

              network=new neuralmatrix(*copy.network);

              neuralmatrix * idx2=network;

              idx=idx->next;

 

              //Copies all the layers

              while (idx!=NULL) {

                     idx2->next=new neuralmatrix(*idx);

                     idx=idx->next;

                     idx2=idx2->next;

              }

              idx2->next=NULL;

       }

       return *this;

}

 

int neuralnet::get(int row, int col) {

//Get a specific row and colum from the first layer

       return network->get(row,col);

}

 

neuralmatrix & neuralnet::getnet(int l) {

//Return the nueral matrix at the specified layer l.

       neuralmatrix * idx;

       for(idx=network;l>1 && idx!=NULL;l--,idx=idx->next);

       return *idx;

}

 

void neuralnet::cross(const neuralnet &p2, double rate) {

//Rate has floating point values from 0 to 1

//Cross the current matrix with the other matrix

       neuralmatrix *idx;

       neuralmatrix *idx2;

 

       idx=network;

       idx2=p2.network;

 

       //Go through the weights in each layer

       while (idx!=NULL) {

              //Cross them with the corresponding layer in the other matrix

              idx->cross(*idx2,rate);

              idx=idx->next;

              idx2=idx2->next;

       }

}     

 

void neuralnet::propagate(double reinforcement) {

//Propagate the input activation pattern through the neural

//network and store the result in the outputhold vector

  neuralvec a, b;

  int state;

  outputhold.reset();

  neuralmatrix *idx;

  b=inputhold;

  state=0;

 

  for(idx=network; idx!=NULL; idx=idx->next) {

              //Alternate between staes to save time from copying

              //Source and destination vectors

    if (state==0) {

                     if (reinforcement==0) idx->transform(b,a);

                     else idx->transform(b,a,reinforcement);

                     a.ApproxSigmoidThresh();

      state=1;

    }

    else {

                     if (reinforcement==0) idx->transform(a,b);

                     else idx->transform(a,b,reinforcement);

                     b.ApproxSigmoidThresh();

      state=0;

    }

  }

  if (state==1)

    outputhold=a;

  else

    outputhold=b;

}

 

void neuralnet::rpropagate(double reinforcement) {

//Propagate the input activation pattern through the neural

//network and store the result in the outputhold vector

  neuralvec a, b;

  int state;

  outputhold.reset();

  neuralmatrix *idx;

  b=inputhold;

  state=0;

 

  for(idx=network; idx!=NULL; idx=idx->next) {

              //Alternate between staes to save time from copying

              //Source and destination vectors

    if (state==0) {

                     if (reinforcement==0) idx->transform(b,a,0,true);

                     else idx->transform(b,a,reinforcement,true);

                     a.ApproxSigmoidThresh();

      state=1;

    }

    else {

                     if (reinforcement==0) idx->transform(a,b,0,true);

                     else idx->transform(a,b,reinforcement,true);

                     b.ApproxSigmoidThresh();

      state=0;

    }

  }

  if (state==1)

    outputhold=a;

  else

    outputhold=b;

}

 

 

/*NeuralVec.cpp*/

#include "memleak.h"

#include <stdlib.h>

#include <memory.h>

#include "NeuralNet.h"

#include <math.h>

 

/***********************************

Neural vector class

***********************************/

neuralvec::neuralvec(int s) {

       size=s;

       if (s==0) data=NULL;

       else data=new int[s+1];

}

 

neuralvec::neuralvec(const neuralvec & n) {

       size=n.size;

       if (size==0) data=NULL;

       else data=new int[size+1];

       memcpy(data,n.data,size*sizeof(int));

}

 

neuralvec::~neuralvec() {

       if (data!=NULL) delete [] data;

  data=NULL;

}

 

void neuralvec::setsize(int s) {

       if (data!=NULL) delete [] data;

       size=s;

       data=new int[s+1];

}

 

int neuralvec::getsize() {

  return size;

}

 

void neuralvec::reset() {

       if (data!=NULL) {

              memset(data,0,size*sizeof(int));

       }

}

 

neuralvec & neuralvec::operator=(const neuralvec & copy) {

       if (data!=NULL) delete [] data;

       size=copy.size;

       if (size==0) data=NULL;

       else data=new int[size+1];

       memcpy(data,copy.data,size*sizeof(int));

       return *this;

}

 

 

/* Index access overloaded operators */

int & neuralvec::operator[ ]( int Index ) {

    if(Index<0 || Index > size) {

                     exit(1);

              }

    return data[Index];

}

 

int neuralvec::operator[ ]( int Index ) const {

    if(Index<0 || Index > size) {

                     exit(1);

              }

    return data[Index];

}

 

void neuralvec::operator+=(const neuralvec &rhs) {

       int i;

       if (size==rhs.size) {

              for(i=0;i<size;i++)

                     data[i]+=rhs[i];

       }

}

 

/************************************************

Thresholding functions for activation

************************************************/

 

void neuralvec::SignThresh() {

//Uses a signthreshold.

       int i;

       for(i=0;i<size;i++) {

              if (data[i]>=0) data[i]=BaseOne;

              else if (data[i]<0) data[i]=-BaseOne;

       }

}

 

void neuralvec::SigmoidThresh() {

//Implements the Sigmoid Threshold

       int i;

       for(i=0;i<size;i++) {

              data[i]=(int)(BaseOne/(1+exp(-(data[i]/(double)BaseOne)))+0.5);

       }

}

 

void neuralvec::ApproxSigmoidThresh() {

//Approximates the Sigmoid Threshold

       int i;

       for(i=0;i<size;i++) {

              if (data[i]<-5000) data[i]=0;

              else if (data[i]>5000) data[i]=BaseOne;

              else data[i]=(data[i]+5000)*BaseOne/10000;

       }

}

 

void neuralvec::StepThresh() {

//Uses A step threshhold

       int i;

       for(i=0;i<size;i++) {

              if (data[i]>=500) data[i]=BaseOne;

              else if (data[i]<500) data[i]=0;

       }

}

/*************************************************/

 

ostream & operator << (ostream &out,const neuralvec &obj) {

       //Stream output for saving

       int i;

       out << obj.size << endl;

       for(i=0;i<obj.size;i++) {

              out << (obj.data[i]) << endl;

       }

       return out;

}

 

istream & operator >> (istream &in,neuralvec &obj) {

       //Stream input for loading

       int i;

       in >> i;

       obj.setsize(i);

       for(i=0;i<obj.size;i++) {

              in >> obj.data[i];

       }

       return in;

}

 

/*Obstacle.cpp*/

#include "memleak.h"

#include "Obstacle.h"

#include "Thing.h"

 

Obstacle::Obstacle() {

       ID=ID_Obstacle;

}

 

void Obstacle::Cycle() {

}

 

bool Obstacle::gone() {

       return false;

}

 

void Obstacle::Emmit() {

}

 

bool Obstacle::moveon() {

       return false;

}

 

int Obstacle::GetAction(int i) {

       return 0;

}

 

/*Smells.cpp*/

#include "memleak.h"

#include "Constants.h"

#include "Smells.h"

 

Smells::Smells() {

       for (int i=0; i<SigNum; i++) {

              Signal[i]=0;

              Osignal[i]=0;

       }

}

 

Smells::~Smells() {

}

 

void Smells::Cycle(Smells &a,Smells & b,Smells & c, Smells & d) {

       int i;

       for (i=0;i<SigNum;i++) {

              //Direct neighbors get 1/8 of the smell

              a.Signal[i]+=(Osignal[i]>>4);

              b.Signal[i]+=(Osignal[i]>>4);

              c.Signal[i]+=(Osignal[i]>>4);

              d.Signal[i]+=(Osignal[i]>>4);

              //Cap the maximum

              if ((unsigned)Signal[i]>(unsigned)0x0FFFFFFF) Signal[i]=0x0FFFFFFF;

              Osignal[i]=(Signal[i]>>1)+(Signal[i]>>2);

              //if (Osignal[i]>=0x000F) Osignal[i]-=0x000F;

              Signal[i]=Osignal[i];

       }

}

 

void Smells::SetSmell(int smellnum, int strength) {

//Increases the smell in the region by amount specified by strength

       if (Signal[smellnum]<SmellMAX)

              Signal[smellnum]+=strength;

       if (Signal[smellnum]<0) Signal[smellnum]=0;

}

 

void Smells::SetSmell(const int smell[]) {

//Increases the smell int the region by a smell vector

       for (int i=0;i<SigNum;i++) {

              if (Signal[i]<SmellMAX) {

                     Signal[i]+=smell[i];

                     if (Signal[i]<0) Signal[i]=0;

              }

       }

}

 

int Smells::GetSmell(int smellnum) {

//Gets a specific smell

       return Osignal[smellnum];

}

 

void Smells::GetSmell(int smellnum[]) {

//Gets a smell array

       int i;

       for (i=0; i<SigNum; i++) {

              smellnum[i]=Osignal[i];

       }

}

 

bool Smells::GetBlock() {

       return blocked;

}

 

 

/*Things.cpp*/

#include "memleak.h"

#include <stdlib.h>

#include <math.h>

#include "Constants.h"

#include "Neighbor.h"

#include "Smells.h"

#include "Thing.h"

#include "Obstacle.h"

 

Things::Things() {

       posx=rand()%maxX;

       posy=rand()%maxY;

       oldx=0;

       oldy=0;

       next=NULL;

       mass=0;

       for (int i=0; i<SigNum; i++) {

              Signal[i]=0;

       }

}

 

Things::~Things() {

       int ref;

       Neighbor *idx,*oidx;

       Things *cpy;

 

       //Add it to the dead list so the draw function can erase it from the screen

       if (DRAWON) {

              cpy=new Obstacle;

              cpy->oldx=cpy->posx=oldx;

              cpy->oldy=cpy->posy=oldy;

              cpy->ID=ID;

              cpy->next=Deadlist;

              Deadlist=cpy;

       }

 

       //Delete it from the neighborhood list also

       ref=posx+posy*maxX;

       for(idx=nearlist[ref].next, oidx=NULL;idx!=NULL && idx->obj!=this; oidx=idx, idx=idx->next);

       if (idx!=NULL) {

              if (oidx!=NULL) {

                     oidx->next=idx->next;

                     delete idx;

              }

              else {

                     nearlist[ref].next=idx->next;

                     delete idx;

              }

       }

 

}

 

int Things::Getx() {

       return posx;

}

 

int Things::Gety() {

       return posy;

}

 

int Things::Getox() {

       return oldx;

}

 

int Things::Getoy() {

       return oldy;

}

 

void Things::UpdatePos() {

       oldx=posx;

       oldy=posy;

}

 

int Things::GetMass() {

       return mass;

}

 

void Things::SetSmell(int smellnum, int strength) {

       Signal[smellnum]=strength;

}

 

void Things::SetSmell(const int smell[]) {

       for (int i=0;i<SigNum;i++) {

              Signal[i]=smell[i];

       }

}

 

int Things::GetSmell(int smellnum) {

       return Signal[smellnum];

}

 

void Things::GetSmell(int smell[]) {

       int i;

       for (i=0;i<SigNum;i++) {

              smell[i]=Signal[i];

       }

}

 

void Things::clean() {

}

 

void Things::SetMass(int m) {

       mass=m;

}

 

void Things::Setx(int x) {

       posx=x;

}

 

void Things::Sety(int y) {

       posy=y;

}

 

void Things::Move(int dir, int dist) {

       double tmp;

       Neighbor *idx, *oidx;

       int ref;

 

       tmp=dir/(double)180000000*3.1415926535897932384626433832795028841971693993751058;

 

       ref=posx+posy*maxX;

       //Remobes the object from the current neighborhood map

       for(idx=nearlist[ref].next, oidx=NULL;idx!=NULL && idx->obj!=this; oidx=idx, idx=idx->next);

       if (idx!=NULL) {

              if (oidx!=NULL) {

                     oidx->next=idx->next;

              }

              else {

                     nearlist[ref].next=idx->next;

              }

       }

 

       posy+=(int)(dist*sin(tmp));

       posx+=(int)(dist*cos(tmp));

 

/* Add / at beginning of this line to use wrap, take off to use Stop

       //Wrap around bounds

       if (posx>maxX) posx-=maxX;

       if (posx<0) posx+=maxX;

       if (posy>maxY) posy-=maxY;

       if (posy<0) posy+=maxY;

/*/

       //Stop at edge

       if (posx>maxX) posx=maxX;

       if (posx<0) posx=0;

       if (posy>maxY) posy=maxY;

       if (posy<0) posy=0;

//*/

 

       ref=posx+posy*maxX;

 

       //Place object at the new location on the neighborhood map

       if (idx==NULL) idx=new struct Neighbor;

       idx->next=nearlist[ref].next;

       idx->obj=this;

       nearlist[ref].next=idx;

}

 

int Things::Distance(class Things &obj) {

       //Estimation of the distance

       return abs(obj.posx-posx)+abs(obj.posy-posy);

}

 

bool Things::InTheWay(int dir, int dist, class Things &obj) {

       //Determine if some object is in the way and can't move ontop of it.

       int ny, nx;

       double tmp;

       tmp=dir/(double)180000000*3.1415926535897932384626433832795028841971693993751058;

 

       ny=posy+(int)(dist*sin(tmp));

       nx=posx+(int)(dist*cos(tmp));

       if (ny==obj.posy && nx==obj.posx && !obj.moveon()) return true;

       return false;

}

 

/*World.cpp*/

#include "memleak.h"

#include <time.h>

#include <sys/timeb.h>

#include <sys/types.h>

#include <fstream.h>

#include "World.h"

#include "Constants.h"

#include "Smells.h"

#include "Obstacle.h"

#include "Bugs.h"

#include "Food.h"

#include "Thing.h"

#include "Neighbor.h"

 

//Timer function for efficiency checking

void timefunc(char *message) {

static int go=0;

struct timeb timeptr;

static unsigned int timestart;

unsigned int timestop;

if (go==0) {

       ftime(&timeptr);

       timestart=timeptr.millitm+1000*timeptr.time;

       go=1;

}

else {

       ftime(&timeptr);

       timestop=timeptr.millitm+1000*timeptr.time;

       go=0;

       timefile << message << " took " << timestop-timestart << " seconds at " << timestart << endl;

}

 

}

 

//Displays the statistics of population size

void ShowStats(HDC hdc) {

       RECT a={maxX+50,50,maxX+200,maxY};

       char num[50];

 

       TextOut(hdc,maxX+55, 50,"Type 1 Population:",17);

       TextOut(hdc,maxX+55, 100,"Type 2 Population:",17);

       TextOut(hdc,maxX+55, 150,"Type 3 Population:",17);

       TextOut(hdc,maxX+60, 200,"Food Available:",15);

       a.top=70;

       a.bottom=100;

       itoa(num1Left,num,10);

       FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

       TextOut(hdc,maxX+55, 70,num,strlen(num));

       a.top=120;

       a.bottom=150;

       FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

       itoa(num2Left,num,10);

       TextOut(hdc,maxX+55, 120,num,strlen(num));

       a.top=170;

       a.bottom=200;

       FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

       itoa(num3Left,num,10);

       TextOut(hdc,maxX+55, 170,num,strlen(num));

       a.top=220;

       a.bottom=250;

       FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

       itoa(foodLeft,num,10);

       TextOut(hdc,maxX+60, 220,num,strlen(num));

}

 

//Displays the smell map after converting it into a colormap

void ShowSmellMap(HDC hdc) {

       int x, y, idx,i;

       int a1, a2, a3;

       int smell[SigNum], bugsmell, signal;

       HBRUSH B;

       COLORREF C;

 

       RECT a={maxX+32,maxY-200,maxX+224,maxY+256};

//     FillRect(hdc, &a, (HBRUSH)GetStockObject(WHITE_BRUSH));

       /*xdiff=3 pix per region

              ydiff=5 pix per region

       */

 

       //For each of the regions

       for(y=0, idx=0;y<48;y++) {

              for (x=0;x<64; x++, idx++) {

 

                     //Setup the map block

                     a.left=maxX+32+3*x;

                     a.top=maxY-200+5*y;

                     a.right=maxX+32+3*x+3;

                     a.bottom=maxY-195+5*y;

 

                     //Retrieve smell

                     smellmap[idx].GetSmell(smell);

                     //Compile color for bugs

                     bugsmell=smell[2]+smell[3]+smell[4];

                    

                     //Compile color for signals

                     signal=0;

                     for(i=0;i<SigNum-5;i++) {

                           signal+=smell[5+i];

                     }

 

                     //Food is it's own color

 

                     //Make sure we don't have any negative smells

                     if (bugsmell<0) bugsmell=0;

                     if (smell[1]<0) smell[1]=0;

                     if (signal<0) signal=0;

 

                     a1=0;

                     a2=0;

                     a3=0;

 

                     //Use a table to convert signal strength to color

                     for(i=0;i<SCTnum;i++) {

                           if (bugsmell>=SmellConvBound[i]) a1=SmellConvVal[i];

                           if (smell[1]>=SmellConvBound[i]) a2=SmellConvVal[i]<<8;

                           if (signal>=SmellConvBound[i]) a3=SmellConvVal[i]<<16;

                          

                           /* Old smell code which used least significant byte as color

                           if (smell[0]>0x00FF) a1=0x00FF0000;

                           else a1=(smell[0]<<16)&0x00FF0000;

                           if (smell[1]>0x00FF) a2=0x00FF00;

                           else a2=(smell[1]<<8)&0x00FF00;

                           if (smell[2]>0x00FF) a3=0x00FF;

                           else a3=(smell[2])&0x00FF;

                           */

                     }

 

                     //Mix the colors together

                     C=(a1 | a2 | a3);

                     //Create a brush with that color

                     B=CreateSolidBrush(C);

                     //Draw the rectangle

                     FillRect(hdc, &a, B);

                     //Erase the color

                     DeleteObject(B);

              }

       }

 

}

 

void ClearWorld() {

       //Clear the world of all things.

       Things *idx, *tmp;

       for(idx=World, World=NULL;idx!=NULL;tmp=idx, idx=idx->next, delete tmp);

}

 

void prune(int type1, int type2, int type3) {

//Prune the number of bugs, for population control

//parameters specify the number of bugs of each type to prune

//If 0 or less, none of that type is pruned.

       Things *idx, *pidx;

       int t1,t2,t3;

       t1=0;

       t2=0;

       t3=0;

 

       //Loop through world

       for(idx=World, pidx=NULL;idx!=NULL;pidx=idx, idx=idx->next) {

 

              //If object is type 1 and we haven't met our prune quota

              if (t1<type1 && (idx->ID&ID_Bug1)) {

                     if (rand()%5) {  //20% Chance of being killed

                           if (pidx!=NULL) {

                                  pidx->next=idx->next;

                                  delete idx;

                                  idx=pidx;

                                  t1++;

                           }

                     }

                     continue;

              }

 

              //If object is type 2 and we haven't met our prune quota

              if (t2<type2 && (idx->ID&ID_Bug2)) {

                     if (rand()%5) {  //20% Chance of being killed

                           if (pidx!=NULL) {

                                  pidx->next=idx->next;

                                  delete idx;

                                  idx=pidx;

                                  t2++;

                           }

                     }

                     continue;

              }

 

              //If object is type 3 and we haven't met our prune quota

              if (t3<type3 && (idx->ID&ID_Bug3)) {

                     if (rand()%5) {  //20% Chance of being killed

                           if (pidx!=NULL) {

                                  pidx->next=idx->next;

                                  delete idx;

                                  idx=pidx;

                                  t3++;

                           }

                     }

                     continue;

              }

 

       }

}

 

void CycleSmell() {

       //Every cycle, we cycle the smell.

       int i;

       Smells tmp;

 

       //For each region Cycle the smellregion with the four adjacent neighbors as it's input.

       //If it is on a edge or corner, use a dummy region as input.

       for (i=0; i<(maxx*maxy); i++) {

              if (i==0)                                                            //upper left

                     smellmap[i].Cycle(smellmap[i+1],tmp,smellmap[i+maxx],tmp);

              else if (i==maxx-1)                      //upper right

                     smellmap[i].Cycle(tmp,smellmap[i-1],smellmap[i+maxx],tmp);

              else if (i==maxy*maxx-1)   //lower right

                     smellmap[i].Cycle(tmp,smellmap[i-1],tmp,smellmap[i-maxx]);

              else if (i==(maxy-1)*maxx)//lower left

                     smellmap[i].Cycle(smellmap[i+1],tmp,tmp,smellmap[i-maxx]);

              else if ((i)%maxx==0)                    //left

                     smellmap[i].Cycle(smellmap[i+1],tmp,smellmap[i+maxx],smellmap[i-maxx]);

              else if ((i+1)%maxx==0)           //right

                     smellmap[i].Cycle(tmp,smellmap[i-1],smellmap[i+maxx],smellmap[i-maxx]);

              else if (i<maxx)                                //upper

                     smellmap[i].Cycle(smellmap[i+1],smellmap[i-1],smellmap[i+maxx],tmp);

              else if (i>(maxy-1)*maxx)  //lower

                     smellmap[i].Cycle(tmp,smellmap[i-1],tmp,smellmap[i-maxx]);

              else

                     smellmap[i].Cycle(smellmap[i+1],smellmap[i-1],smellmap[i+maxx],smellmap[i-maxx]);

       }

}

 

void Cycle() {

//Cycle through the whole world

       Things *idx, *pidx;

       bool notdead=false;

       int i;

 

//World time is increased.

       worldtime++;

 

//Auto feeder enabled and not enough food left

       if (autoFeed && foodLeft<foodLev) {

              i=(foodLev-foodLeft);

              //Generate Some Food

              while (i>0) {

                     idx=new Food();

                     idx->next=World;

                     World=idx;

                     i--;

              }

       }

 

       num1Left=0;

       num2Left=0;

       num3Left=0;

       foodLeft=0;

      

       //Cycle through the world

       for (idx=World,pidx=NULL;idx!=NULL;pidx=idx, idx!=NULL?idx=idx->next:idx=NULL)

       {            

              //Delete dead objects

              if (idx->gone()) {//IF gone

                     //If corpse, replace bug with food

                     if ((idx->ID&ID_Bug)!=0) {//If is bug

                           if (pidx!=NULL) {//If a

                                  idx->clean();

                                  pidx->next=new Food((*(class Bug *)idx));

                                  pidx->next->next=idx->next;

                                  delete idx;

                                  idx=pidx->next;

                           }

                           else {

                                  idx->clean();

                                  pidx=new Food((*(class Bug *)idx));

                                  pidx->next=idx->next;

                                  World=pidx;

                                  delete idx;

                                  idx=pidx->next;

                                  pidx=NULL;

                           }//end If a

                     }

                     //Delete gone object

                     else {//else not bug

                           if (pidx!=NULL) {//If not on first object

                                  pidx->next=idx->next;

                                  idx->clean();

                                  delete idx;

                                  idx=pidx->next;

                           }

                           else {

                                  World=idx->next;

                                  idx->clean();

                                  delete idx;

                                  idx=World;

                                  pidx=NULL;

                                  break;

                           }//End not on first object

                     }//End else not bug

              }//Else of gone

              else {

                     //Cycles and moves

                     idx->Cycle();

 

                     //emmits smells

                     idx->Emmit();

 

                     //Counts objects

                     switch (idx->ID) {

                     case ID_Food:

                           foodLeft++;

                           break;

                     case ID_Bug1M:

                           num1Left++;

                           break;

                     case ID_Bug1F:

                           num1Left++;

                           break;

                     case ID_Bug2M:

                           num2Left++;

                           break;

                     case ID_Bug2F:

                           num2Left++;

                           break;

                     case ID_Bug3M:

                           num3Left++;

                           break;

                     case ID_Bug3F:

                           num3Left++;

                           break;

                     }//End switch

              }//End else gone

       }//End for loop

 

       if (!notdead) {

              //logfile << "The Simulation of the bug world has ended at " << worldtime << " cycles." << endl;

              //ClearWorld();

              worldtime=0;

       }

 

       //Prunes world

       prune(num1Left-1000,num2Left-1000,num3Left-1000);

 

}

 

void Draw(HDC hdc, BITMAP s_bug1M, BITMAP s_bug1F, BITMAP s_bug2M, BITMAP s_bug2F,

                                   BITMAP s_bug3M, BITMAP s_bug3F, BITMAP s_Food, HDC hdcBug1M, HDC hdcBug1F,

                                   HDC hdcBug2M, HDC hdcBug2F, HDC hdcBug3M, HDC hdcBug3F, HDC hdcFood) {

//This function draws world and is not within the scope of my comments.

       Things *idx, *pidx;

       HBRUSH pen1,pen2,pen3,pen4, whitepen;

       RECT r;

       bool notdead=false;

 

       pen1=CreateSolidBrush((COLORREF)0x000000CF);

       pen2=CreateSolidBrush((COLORREF)0x0000CF00);

       pen3=CreateSolidBrush((COLORREF)0x00CF0000);

       pen4=CreateSolidBrush((COLORREF)0x00000000);

  whitepen=CreateSolidBrush((COLORREF)0x00FFFFFF);

       num1Left=0;

       num2Left=0;

       num3Left=0;

       foodLeft=0;

 

       for (idx=Deadlist,pidx=NULL;idx!=NULL;pidx=idx,idx!=NULL?idx=idx->next:idx=NULL, delete pidx) {

              switch (idx->ID) {

              case ID_Bug1M:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug1M.bmWidth, s_bug1M.bmHeight, hdcBug1M, 0, 0, WHITENESS);

                     break;

              case ID_Bug1F:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug1F.bmWidth, s_bug1F.bmHeight, hdcBug1F, 0, 0, WHITENESS);

                     break;

              case ID_Bug2M:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug2M.bmWidth, s_bug2M.bmHeight, hdcBug2M, 0, 0, WHITENESS);

                     break;

              case ID_Bug2F:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug2F.bmWidth, s_bug2F.bmHeight, hdcBug2F, 0, 0, WHITENESS);

                     break;

              case ID_Bug3M:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug3M.bmWidth, s_bug3M.bmHeight, hdcBug3M, 0, 0, WHITENESS);

                     break;

              case ID_Bug3F:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug3F.bmWidth, s_bug3F.bmHeight, hdcBug3F, 0, 0, WHITENESS);

                     break;

              case ID_Food:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_Food.bmWidth, s_Food.bmHeight, hdcFood, 0, 0, WHITENESS);

                     break;

              }

              if (ShowSig && (idx->ID&ID_Bug)>0) {

                     r.bottom=idx->Getoy()+1;

                     r.right=idx->Getox()+9;

                     r.top=r.bottom-5;

                     r.left=r.right-18;

                     FillRect(hdc,&r,whitepen);

              }            

       }

       Deadlist=NULL;

      

       //* Actual drawing onto screen of stuff

       for (idx=World,pidx=NULL;idx!=NULL;pidx=idx, idx!=NULL?idx=idx->next:idx=NULL) {

              //Clears the object off screen

              switch (idx->ID) {

              case ID_Bug1M:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug1M.bmWidth, s_bug1M.bmHeight, hdcBug1M, 0, 0, WHITENESS);

                     break;

              case ID_Bug1F:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug1F.bmWidth, s_bug1F.bmHeight, hdcBug1F, 0, 0, WHITENESS);

                     break;

              case ID_Bug2M:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug2M.bmWidth, s_bug2M.bmHeight, hdcBug2M, 0, 0, WHITENESS);

                     break;

              case ID_Bug2F:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug2F.bmWidth, s_bug2F.bmHeight, hdcBug2F, 0, 0, WHITENESS);

                     break;

              case ID_Bug3M:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug3M.bmWidth, s_bug3M.bmHeight, hdcBug3M, 0, 0, WHITENESS);

                     break;

              case ID_Bug3F:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_bug3F.bmWidth, s_bug3F.bmHeight, hdcBug3F, 0, 0, WHITENESS);

                     break;

              case ID_Food:

                     BitBlt(hdc, idx->Getox(), idx->Getoy(), s_Food.bmWidth, s_Food.bmHeight, hdcFood, 0, 0, WHITENESS);

                     break;

              }

 

              if (ShowSig && (idx->ID&ID_Bug)>0) {

                     r.bottom=idx->Getoy()+1;

                     r.right=idx->Getox()+9;

                     r.top=r.bottom-5;

                     r.left=r.right-18;

                     FillRect(hdc,&r,whitepen);

              }

              //Update last draw position

              idx->UpdatePos();

 

              if (ShowSig) {

                     r.bottom=idx->Gety();

                     r.right=idx->Getx()+9;

                     r.top=r.bottom-4;

 

                     if (idx->GetAction(0)>1) {//Mate

                           r.left=r.right-2;

                           FillRect(hdc,&r,pen1);

                           r.right-=4;

                     }

                     if (idx->GetAction(1)>1) {//Eat

                           r.left=r.right-2;

                           FillRect(hdc,&r,pen2);

                           r.right-=4;

                     }

                     if (idx->GetAction(2)>1) {//Attack

                           r.left=r.right-2;

                           FillRect(hdc,&r,pen3);

                           r.right-=4;

                     }

                     if (idx->GetAction(7)>1) {//Signal

                           r.left=r.right-2;

                           FillRect(hdc,&r,pen4);

                     }

              }

              //Draws the object on screen

              switch (idx->ID) {

              case ID_Food:

                     foodLeft++;

                     BitBlt(hdc, idx->Getx(), idx->Gety(), s_Food.bmWidth, s_Food.bmHeight, hdcFood, 0, 0, SRCCOPY);

                     break;

              case ID_Bug1M:

                     num1Left++;

                     BitBlt(hdc, idx->Getx(), idx->Gety(), s_bug1M.bmWidth, s_bug1M.bmHeight, hdcBug1M, 0, 0, SRCCOPY);

                     break;

              case ID_Bug1F:

                     num1Left++;

                     BitBlt(hdc, idx->Getx(), idx->Gety(), s_bug1F.bmWidth, s_bug1F.bmHeight, hdcBug1F, 0, 0, SRCCOPY);

                     break;

              case ID_Bug2M:

                     num2Left++;

                     BitBlt(hdc, idx->Getx(), idx->Gety(), s_bug2M.bmWidth, s_bug2M.bmHeight, hdcBug2M, 0, 0, SRCCOPY);

                     break;

              case ID_Bug2F:

                     num2Left++;

                     BitBlt(hdc, idx->Getx(), idx->Gety(), s_bug2F.bmWidth, s_bug2F.bmHeight, hdcBug2F, 0, 0, SRCCOPY);

                     break;

              case ID_Bug3M:

                     num3Left++;

                     BitBlt(hdc, idx->Getx(), idx->Gety(), s_bug3M.bmWidth, s_bug3M.bmHeight, hdcBug3M, 0, 0, SRCCOPY);

                     break;

              case ID_Bug3F:

                     num3Left++;

                     BitBlt(hdc, idx->Getx(), idx->Gety(), s_bug3F.bmWidth, s_bug3F.bmHeight, hdcBug3F, 0, 0, SRCCOPY);

                     break;

              }//End switch

       }//End for loop

 

       DeleteObject(pen1);

       DeleteObject(pen2);

       DeleteObject(pen3);

       DeleteObject(pen4);

       DeleteObject(whitepen);

 

}//End cycle

 

void DoMyExit() {

       ClearWorld();

       DeleteSmell();

       deletenearlist();

       logfile.close();

       timefile.close();

       //     if (smellmap!=NULL)

       //     delete smellmap[];

}

 

void deletenearlist() {

       //Deletes the neighborhood list

       Neighbor *idx, *oidx;

       int i;

       for(i=0;i<maxX*maxY; i++) {

              for(idx=nearlist[i].next,oidx=NULL;idx!=NULL;oidx=idx,idx=idx->next,delete oidx);

       }

       delete [] nearlist;

}

 

void DeleteSmell() {

       //Delete all the smells

       delete [] smellmap;

}

 

void Begin(HWND hwnd) {

       //Runs whenever we add objects

       int i;

       Things *idx;

 

       //Type 1 Bugs

       i=num1Bugs;

       while (i>0) {

              idx=new Bug1();

              idx->next=World;

              World=idx;

              i--;

       }

 

       //Type 2 Bugs

              i=num2Bugs;

       while (i>0) {

              idx=new Bug2();

              idx->next=World;

              World=idx;

              i--;

       }

 

       //Type 3 Bugs

              i=num3Bugs;

       while (i>0) {

              idx=new Bug3();

              idx->next=World;

              World=idx;

              i--;

       }

      

       //Food

       i=numFood;

       while (i>0) {

              idx=new Food();

              idx->next=World;

              World=idx;

              i--;

       }

 

       //Wrap around bounds

       if (idx->Getx()>maxX) idx->Setx(idx->Getx()-maxX);

       if (idx->Getx()<0) idx->Setx(maxX+idx->Getx());

       if (idx->Gety()>maxY) idx->Sety(idx->Gety()-maxY);

       if (idx->Gety()<0) idx->Sety(maxY+idx->Gety());

 

       RECT b={0,0,maxX,maxY};

       //Forces a refresh

       InvalidateRect(hwnd,&b,1);  

 

}

 

void SaveWorld(char *filename) {

       //Save all the bugs in the world

       Things *idx;

       ofstream savefile(filename);

       int num=0;

 

       for(idx=World;idx!=NULL;idx=idx->next) {

              if ((idx->ID & ID_Bug)!=0) num++;

       }

      

       savefile << num << endl;

 

       for(idx=World;idx!=NULL;idx=idx->next) {

              if ((idx->ID & ID_Bug)!=0) {

                     savefile << *(Bug *)idx;

              }

       }

       savefile.close();

       logfile << "Saved file " << filename << endl;

}

 

void LoadWorld(char *filename) {

       //Loads up bugs into the world

       Things *idx;

       int count;

 

       count=0;

       ifstream loadfile(filename);

      

       loadfile >> count;

 

       while(count>0) {

              idx=new Bug;

              loadfile >> *(Bug *)idx;

              idx->next=World;

              World=idx;

              count--;

       }

       loadfile.close();

 

       logfile << "Loaded file " << filename << endl;

 

}

 

 

 

 


Paper Project with appendix max 10

 

Hypothesis

Issues

Motivation

Architecture

Sensors/motors

Environment/physics

Algorithms

 

Evaluation/experiment

Status-works/doesn’t

No-related work

 

Appendix any length

Documented code

Annotated runs

Datafiles

 

4532-A

dyer mail slot

 

 


Home | About Me | Text Depository | Future Enhancements | Guest Book | Links

Copyright © 1998-2008 Michael Chungkun Chen
All Rights Reserved.