// Genesaver: copyright 2003 Sam Stafford. #define _USE_MATH_DEFINES #include <math.h> #include <GL/glut.h> #include "globals.h" #include "animal.h" #include "world.h" #include "pixel.h" Animal::Animal( DNA* d ) :brain( d, muscles ), Thing() { hi = lo = NULL; meter_hue = 0.0; tagged = false; fitness = fitness_relative = 0.0; velocity_x = 4.5; velocity_y = 1.5; dna = d; //initialize muscles for ( int m = 0 ; m < 4 ; m++ ) muscles[m] = 0.0; //establish creature color from genome short i; char cs[10]; for ( i = 0 ; i < 4 ; i++ ) cs[i] = dna->hchr.colr[i]; for ( i = 4 ; i < 10 ; i++ ) cs[i] = dna->ichr[i - 4].colr; for ( i = 0 ; i < 10 ; i++ ) { switch( abs( cs[i] % 3 ) ) { case 0: r++; break; case 1: g++; break; case 2: b++; break; } } float sum = r + g + b; r /= sum; g /= sum; b /= sum; } Animal::~Animal(void) { delete dna; } void Animal::Render() { glPushMatrix(); glTranslatef( x, y, 0 ); r = 1; float ax, ay; float da = M_PI / 13.0; glBegin( GL_TRIANGLES ); for ( float a = 0.0 ; a < 2 * M_PI ; a += da ) { ax = A_R * cos( a ); ay = A_R * sin( a ); glColor3f( r, g, b ); glVertex2f( ax, ay ); glVertex2f( A_R * cos( a + da ), A_R * sin( a + da ) ); glColor3f( fitness_relative, fitness_relative, fitness_relative ); glVertex2f( 0, 0 ); } glEnd(); if ( tagged && settings.wake ) { glBegin( GL_LINES ); glColor3f( 1, 1, 1 ); glVertex2f( -A_R*1.5*cos(angle) + A_R*0.5, -A_R*1.5*sin(angle) ); glColor3f( 0, 0, 0 ); glVertex2f( -A_R*2.0*speed*cos(angle)-A_R*1.5*cos(angle) + A_R*0.5, -A_R*2.0*speed*sin(angle)-A_R*1.5*sin(angle) ); glColor3f( 1, 1, 1 ); glVertex2f( -A_R*1.5*cos(angle) - A_R*0.5, -A_R*1.5*sin(angle) ); glColor3f( 0, 0, 0 ); glVertex2f( -A_R*2.0*speed*cos(angle)-A_R*1.5*cos(angle) - A_R*0.5, -A_R*2.0*speed*sin(angle)-A_R*1.5*sin(angle) ); glColor3f( 1, 1, 1 ); glVertex2f( -A_R*1.5*cos(angle), -A_R*1.5*sin(angle) + A_R*0.5 ); glColor3f( 0, 0, 0 ); glVertex2f( -A_R*2.0*speed*cos(angle)-A_R*1.5*cos(angle), -A_R*2.0*speed*sin(angle)-A_R*1.5*sin(angle) + A_R*0.5 ); glColor3f( 1, 1, 1 ); glVertex2f( -A_R*1.5*cos(angle), -A_R*1.5*sin(angle) - A_R*0.5 ); glColor3f( 0, 0, 0 ); glVertex2f( -A_R*2.0*speed*cos(angle)-A_R*1.5*cos(angle), -A_R*2.0*speed*sin(angle)-A_R*1.5*sin(angle) - A_R*0.5 ); glEnd(); } glPopMatrix(); } void Animal::RenderFitness() { float f1, f2; f1 = 2 * fitness / 1.0 /*MAX_FITNESS ? MAX_FITNESS : 1*/ ; if ( f1 > 2.0 ) f1 = 2.0; //stupid sanity check, kill it later if ( f1 > 1.0 ) { f2 = f1 - 1.0; f1 = 1.0; } else f2 = 0.0; meter_hue += 0.001; if ( meter_hue > 1.0 ) meter_hue = 0.0; float c1, c2; c1 = meter_hue; c2 = meter_hue - f2; if ( c2 < 0.0 ) c2 += 1.0; glBegin( GL_POLYGON ); glColor3f( 1.0 - f1, f1, 0 ); glVertex2f( -0.76, 0.5 - f1 / 2.1 ); glVertex2f( -0.74, 0.5 - f1 / 2.1 ); glColor3f( c1, 0, 1.0 - c1 ); glVertex2f( -0.74, 0.5 + f1 / 2.1 ); glVertex2f( -0.76, 0.5 + f1 / 2.1 ); glEnd(); if ( f2 == 0.0 ) return; glBegin( GL_POLYGON ); glColor3f( 1.0 - f2, 0, f2 ); glVertex2f( 0.76, 0.5 - f2 / 2.1 ); glVertex2f( 0.74, 0.5 - f2 / 2.1 ); glColor3f( c2, 1.0 - c2, 0 ); glVertex2f( 0.74, 0.5 + f2 / 2.1 ); glVertex2f( 0.76, 0.5 + f2 / 2.1 ); glEnd(); } void Animal::CheckFitness( World* w ) { Animal* a; //check fitness of neighbors, promote or demote as appropriate if ( ( a = hi ) && hi->fitness < fitness ) //king me! { hi = a->hi; a->hi = this; a->lo = lo; lo = a; } else if ( ( a = lo ) && lo->fitness > fitness ) //d'oh! { lo = a->lo; a->lo = this; a->hi = hi; hi = a; } if ( !hi ) w->pop = this; } void Animal::Eat( Pixel**p, int w, int h ) { int ix = floor( x ); int iy = floor( y ); int ars = A_R * A_R; float fp; for ( int px = ix - A_R ; px < ix + A_R ; px++ ) { if ( px < 0 || px > w - 1 ) continue; for ( int py = iy - A_R ; py < iy + A_R ; py ++ ) { if ( py < 0 || py > h - 1 ) continue; if ( (px-ix)*(px-ix) + (py-iy)*(py-iy) > ars ) continue; //eat red fp = min( p[px][py].d_r, r * A_D ); fitness += fp; consume_diff( & p[px][py], fp, 'r' ); //eat green fp = min( p[px][py].d_g, g * A_D ); fitness += fp; consume_diff( & p[px][py], fp, 'g' ); //eat blue fp = min( p[px][py].d_b, b * A_D ); fitness += fp; consume_diff( & p[px][py], fp, 'b' ); } } } void Animal::LookNear( Pixel** p, int w, int h ) { //This is the linear vector to the "nearest food". float nx = 0.0; float ny = 0.0; //We'll calculate it by summing unit vectors multiplied //by "food potential" towards all nearby pixels. int ix = floor( x ); int iy = floor( y ); int avs = A_V * A_V; int dx, dy, dxs, dys; float fp, u, v, m; //Scan a square with side = A_V * 2. for ( int px = ix - A_V ; px < ix + A_V ; px++ ) { if ( px < 0 || px > w - 1 ) continue; for ( int py = iy - A_V ; py < iy + A_V ; py ++ ) { if ( py < 0 || py > h - 1 ) continue; dx = px - ix; dy = py - iy; dxs = dx * dx; dys = dy * dy; if ( dx == 0 && dy == 0 ) continue; if ( dxs + dys > avs ) continue; //unit vector toward this pixel m = sqrt( dxs + dys ); u = dx / m; v = dy / m; //red food potential fp = min( p[px][py].d_r, r * A_D ); nx += u * fp; ny += v * fp; //green food potential fp = min( p[px][py].d_g, g * A_D ); nx += u * fp; ny += v * fp; //blue food potential fp = min( p[px][py].d_b, b * A_D ); nx += u * fp; ny += v * fp; } } //Normalize nearest-food vector to unit length. m = sqrt( nx * nx + ny * ny ); nx /= m; ny /= m; //Feed to brain at neurons 0 and 1. brain.input->axon = nx; brain.input->axon = ny; } void Animal::LookFar( int rx, int ry, int gx, int gy, int bx, int by ) { //translate absolute coordinates to relative vectors //feed inputs to brain } void Animal::Step( World* w ) { r = g = b = 1; //Get inputs. LookNear( w->image_p, w->image_w, w->image_h ); //Process inputs. brain.Think(); //adjust velocity based on muscle values //adjust position based on velocity x += velocity_x; y += velocity_y; //bounce off walls if ( x < w->world_l ) { x += ( w->world_l - x ) * 2; velocity_x *= -1; } else if ( x > w->world_r ) { x -= ( x - w->world_r ) * 2; velocity_x *= -1; } if ( y < w->world_b ) { y += ( w->world_b - y ) * 2; velocity_y *= -1; } else if ( y > w->world_t ) { y -= ( y - w->world_t ) * 2; velocity_y *= -1; } //other state updates like eating, fitness, etc go here Eat( w->image_p, w->image_w, w->image_h ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#15 | 5818 | Sam Stafford | Configurable painter opacity. | ||
#14 | 5096 | Sam Stafford |
Make build work with VS 2003. (No functional change.) |
||
#13 | 4577 | Sam Stafford | Add new "smudge distance" tunable. | ||
#12 | 4572 | Sam Stafford |
New "smudge" feature. REALLY COOL. Off by default (pctsmudge=0) since it's a CPU hog. |
||
#11 | 4452 | Sam Stafford | Fix a couple of small bugs. | ||
#10 | 4451 | Sam Stafford | All significant variables are now user-tweakable. | ||
#9 | 4449 | Sam Stafford | Speed lines, toggle creatures on and off. | ||
#8 | 4448 | Sam Stafford | Turn this thing into a Windows screensaver. | ||
#7 | 4447 | Sam Stafford | Cleanup size-heredity code. | ||
#6 | 4446 | Sam Stafford |
Finished neural inputs, made size hereditary, auto-rotation of images once a certain amount of diffs have been consumed, saving genomes at finish. |
||
#5 | 4441 | Sam Stafford | Ported chase-cam view. | ||
#4 | 4440 | Sam Stafford | Bug fixes, new features, the usual. | ||
#3 | 4439 | Sam Stafford | Hooked the brain up to its muscles, gave the world physics. | ||
#2 | 4433 | Sam Stafford |
More work on this little project. The AI is still nonexistent. |
||
#1 | 4430 | Sam Stafford |
Start importing alife/AI code from Genesaver. Much tweaking will need to be done. |
||
//guest/sam_stafford/genesaver/src/Animal.cpp | |||||
#2 | 3348 | Sam Stafford | Decrease length of tail-color-flashes to 5 timesteps. | ||
#1 | 3052 | Sam Stafford |
Add Genesaver to the Public Depot. It's not in any way Perforce-related, but it does share a bit of code with Jamgraph, and it feels strange to have an open-source project that's not in the PD. |