brain.cpp #6

  • //
  • guest/
  • sam_stafford/
  • scenesaver/
  • brain.cpp
  • View
  • Commits
  • Open Download .zip Download (8 KB)
// Genesaver: copyright 2003 Sam Stafford.

#include <math.h>
#include <GL/glut.h>

#include "globals.h"
#include "Brain.h"
#include "DNA.h"

float light;

Brain::Brain( DNA* dna, float* o )
{
	int i, j, k;
	char c;

	//Initialize input neurons to zero.
	for ( i = 0 ; i < 14 ; i++ )
	{
		input[i] = Neuron();
		input[i].axon = 0.0;
		input[i].x = ( i+1 ) * 2.0 / 15.0 - 1.0;
		input[i].active = true;
	}

	//Initialize lobes.
	for ( i = 0 ; i < 6 ; i++ )
	{
		lobe[i] = Lobe();

		//Remember, top level neurons have ONE dendrite each.
		for ( j = 0 ; j < 4 ; j++ )
			for ( k = 1 ; k < 4 ; k++ )
			{
				lobe[i].neur[0][j].dendrite[k] = NULL;
				lobe[i].neur[0][j].weight[k] = 0;
			}

		//Establish input pointers.
		//Left half of each lobe first, for historical reasons.
		c = dna->hchr.iden[i];
		lobe[i].neur[0][0].dendrite[0] = &( input[ abs( (c%7)*2 ) ] );
		lobe[i].neur[0][1].dendrite[0] = &( input[ abs( (c%7)*2 )+1 ] );

		c = dna->hchr.iwgt[i];
		lobe[i].neur[0][0].weight[0] = float( c / 32.0 );
		lobe[i].neur[0][1].weight[0] = float( c / 32.0 );
		CheckActive( & lobe[i].neur[0][0] );
		CheckActive( & lobe[i].neur[0][1] );

		//Now the right half.
		c = dna->hchr.iden[i+6];
		lobe[i].neur[0][2].dendrite[0] = &( input[ abs( (c%7)*2 ) ] );
		lobe[i].neur[0][3].dendrite[0] = &( input[ abs( (c%7)*2 )+1 ] );

		c = dna->hchr.iwgt[i+6];
		lobe[i].neur[0][2].weight[0] = float( c / 32.0 );
		lobe[i].neur[0][3].weight[0] = float( c / 32.0 );
		CheckActive( & lobe[i].neur[0][2] );
		CheckActive( & lobe[i].neur[0][3] );

		//Top level axons.
		for ( j = 0 ; j < 4 ; j++ )
		{
			lobe[i].neur[0][j].thres = float( dna->ichr[i].ax0[j] / 255.0  );
		}

		//Connect layer 1 to layer 0.
		for ( j = 0 ; j < 4 ; j++ )
		{
			for ( k = 0 ; k < 4 ; k++ )
			{
				lobe[i].neur[1][j].dendrite[k] = &( lobe[i].neur[0][k] );
				if ( !lobe[i].neur[0][k].active && RandFloat() < D_M / 255.0 )
					dna->ichr[i].wgt[j][k] = 0;
				lobe[i].neur[1][j].weight[k] = dna->ichr[i].wgt[j][k] / 32.0;
			}
			CheckActive( & lobe[i].neur[1][j] );
		}

		//Bottom level axons.
		for ( j = 0 ; j < 4 ; j++ )
		{
			lobe[i].neur[1][j].thres = float( dna->ichr[i].ax1[j] / 255.0  );
		}

		lobe[i].neur[0][0].x = ( i * 4 + 1 ) * 2.0 / 25.0 - 1.0;
		lobe[i].neur[0][1].x = ( i * 4 + 2 ) * 2.0 / 25.0 - 1.0;
		lobe[i].neur[0][2].x = ( i * 4 + 3 ) * 2.0 / 25.0 - 1.0;
		lobe[i].neur[0][3].x = ( i * 4 + 4 ) * 2.0 / 25.0 - 1.0;
		lobe[i].neur[1][0].x = ( i * 4 + 1 ) * 2.0 / 25.0 - 1.0;
		lobe[i].neur[1][1].x = ( i * 4 + 2 ) * 2.0 / 25.0 - 1.0;
		lobe[i].neur[1][2].x = ( i * 4 + 3 ) * 2.0 / 25.0 - 1.0;
		lobe[i].neur[1][3].x = ( i * 4 + 4 ) * 2.0 / 25.0 - 1.0;
	}

	//Initialize outputs.
	for ( i = 0 ; i < 4 ; i++ ) //output neurons
	{
		for ( j = 0 ; j < 6 ; j++ ) //lobes
		{
			for ( k = 0 ; k < 4 ; k++ ) //bottom lobe neurons
			{
				output[i].dendrite[j*4+k] = &lobe[j].neur[1][k];
				if ( !lobe[j].neur[1][k].active && RandFloat() < D_M / 255.0 )
					dna->hchr.owgt[i][j*4+k] = 0;
				output[i].weight[j*4+k] = float( dna->hchr.owgt[i][j*4+k] / 32.0 );
			}
		}
	}

	//Set pointer to "muscles" of animal.
	muscles = o;
}

Brain::~Brain(void)
{
}

void Brain::CheckActive( Neuron* n ) //check if a neuron is in use
{
	n->active = false;
	for ( int i = 0 ; i < 4 ; i++ )
	{
		if ( n->weight[i] && n->dendrite[i] && n->dendrite[i]->active )
			n->active = true;
	}
}

void Brain::Clear() //reset inputs
{
	for ( int i = 0 ; i < 14 ; i++ ) input[i].axon = 0.0;
}

void Brain::Render()
{
	int i, j, k;

	//Lobe synapses
	for ( i = 0 ; i < 6 ; i++ )
		for ( j = 0 ; j < 4 ; j++ )
		{
			for ( k = 0 ; k < 4 ; k++ )
			{
				RenderSyn
					( lobe[i].neur[1][j].weight[k], 
						lobe[i].neur[1][j].dendrite[k], -0.4,
						lobe[i].neur[1][j].x, -0.6 
					);
			}
			RenderSyn
				( lobe[i].neur[0][j].weight[0], 
					lobe[i].neur[0][j].dendrite[0], -0.2,
					lobe[i].neur[0][j].x, -0.4 
				);
		}

	//Input neurons
	for ( i = 0 ; i < 14 ; i++ )
	{
		RenderNeuron( input[i].axon, input[i].x, -0.2 );
	}

	//Output synapses and neurons
	for ( i = 0 ; i < 4 ; i++ )
	{
		for ( j = 0 ; j < 24 ; j++ )
		{
			RenderSyn
				( output[i].weight[j],
					output[i].dendrite[j], -0.6,
					( i + 1 ) * 2.0 / 5.0 - 1.0, -0.8
				);
		}
		RenderNeuron( output[i].axon, ( i + 1 ) * 2.0 / 5.0 - 1.0, -0.8 );
	}
	
	//Lobe neurons
	for ( i = 0 ; i < 6 ; i++ )
		for ( j = 0 ; j < 4 ; j++ )
		{
			RenderNeuron( lobe[i].neur[0][j].axon, lobe[i].neur[0][j].x, -0.4 );
			RenderNeuron( lobe[i].neur[1][j].axon, lobe[i].neur[1][j].x, -0.6 );
		}
	
	//Label over visual inputs.
	RenderLights();
}

void Brain::RenderLights()
{
	int i;
	if ( light > 0.6 ) light = -1.0;
	else if ( light < -1.0 ) light = 0.6;
	else light += 0.03 * /**step*/ 1; //replace with velocity magnitude
	float r, g, b, lp, rp;
	Color draw;

	for ( i = 0 ; i < 10 ; i++ )
	{
		r = g = b = 0.0;

		switch( i )
		{
		case 0:
		case 1:
			draw = Grey; break;
		case 2:
		case 3:
			draw = Red; break;
		case 4:
		case 5:
			draw = Green; break;
		case 6:
		case 7:
			draw = Blue; break;
		default:
			draw = Grey; break;
		}

		switch( draw )
		{
		case Grey: r = g = b = 0.5; break;
		case Red: r = 1; break;
		case Green: g = 1 ; break;
		case Blue: b = 1 ; break;
		case Magenta: r = b = 1; break;
		case Yellow: r = g = 1; break;
		}
		if ( ( light > input[i].x - N_L ) && ( light < input[i].x + N_L ) )
		{
			lp = 1.0 - ( light - ( input[i].x - N_L )  ) / N_L;
			rp = 1.0 - ( ( input[i].x + N_L ) - light  ) / N_L;
			glBegin( GL_POLYGON );
				SetColor( draw );
				glVertex2f( light, -0.14 );
				glVertex2f( light, -0.15 );
				glColor3f( r * lp, g * lp, b * lp );
				glVertex2f( input[i].x - N_L, -0.15 );
				glVertex2f( input[i].x - N_L, -0.14 );
			glEnd();
			glBegin( GL_POLYGON );
				SetColor( draw );
				glVertex2f( light, -0.14 );
				glVertex2f( light, -0.15 );
				glColor3f( r * rp, g * rp, b * rp );
				glVertex2f( input[i].x + N_L, -0.15 );
				glVertex2f( input[i].x + N_L, -0.14 );
			glEnd();
		}
		else
		{
			glColor3f( r * 0.1, g * 0.1, b * 0.1 );
			glBegin( GL_POLYGON );
				glVertex2f( input[i].x - N_L, -0.15 );
				glVertex2f( input[i].x - N_L, -0.14 );
				glVertex2f( input[i].x + N_L, -0.14 );
				glVertex2f( input[i].x + N_L, -0.15 );
			glEnd();
		}
	}
}

void Brain::RenderNeuron( float a, float x, float y )
{
	float r, g, b;
	if ( a >= 0.0 )
	{
		r = 0.0;
		g = 0.0;
		b = a;
	}
	else
	{
		r = -a;
		g = 0.0;
		b = 0.0;
	}
	glColor3f( r, g, b );
	
	glBegin( GL_POLYGON );
		glVertex2f( x + N_R, y + N_R * 0.5 );
		glVertex2f( x + N_R, y - N_R * 0.5 );
		glVertex2f( x + N_R * 0.5, y - N_R );
		glVertex2f( x - N_R * 0.5, y - N_R );
		glVertex2f( x - N_R, y - N_R * 0.5 );
		glVertex2f( x - N_R, y + N_R * 0.5 );
		glVertex2f( x - N_R * 0.5, y + N_R );
		glVertex2f( x + N_R * 0.5, y + N_R );
	glEnd();
}

void Brain::RenderSyn( float w, Neuron* n, float y1, float x2, float y2 )
{
	if ( !w || !n->active ) return;
	float r, g, b;
	float x1 = n->x;
	if ( w >= 0.0 )
	{
		r = 0.0;
		g = w / 4.0;
		b = w / 4.0;
	}
	else
	{
		r = -w / 4.0;
		g = -w / 4.0;
		b = 0.0;
	}
	float d = 2.0 - n->axon ;

	r /= d;
	g /= d;
	b /= d;

	glBegin( GL_LINE_STRIP );
		glColor3f( 0, 0, 0 );
		glVertex2f( x1, y1 );
		glColor3f( r, g, b );
		glVertex2f( ( x1 + x2 ) / 2.0, ( y1 + y2 ) / 2.0 );
		glColor3f( 0, 0, 0 );
		glVertex2f( x2, y2 );
	glEnd();
}

void Brain::Think() //act on inputs previously cleared by Clear() and accumulated by See().
{
	int i, j, k;
	for ( i = 0; i < 2 ; i++ )
		for ( j = 0; j < 6 ; j++ )
			for( k = 0; k < 4 ; k++ )
			{
				Fire( &( lobe[j].neur[i][k] ) );
			}

	for ( i = 0; i < 4 ; i++ )
		Fire( &output[i] );

	for ( i = 0 ; i < 4 ; i++ )
	{
		muscles[i] = output[i].axon;
	}
}

void Brain::Fire( Neuron* n )
{
	n->axon = 0.0;
	float d = 0.0;
	int e = n->dendrite[1] ? 4 : 1;
	
	for( int i = 0 ; i < e ; i++ )
	{
		if ( n->weight[i] )
		{
			n->axon += n->dendrite[i]->axon * n->weight[i];
			d++;
		}
	}
	if ( d ) n->axon /= d;

	if ( n->thres > 0 ) n->axon = float( n->axon >= n->thres ? 1.0 : 0.0 );

	if ( n->axon > 1.0 ) n->axon = 1.0;
	if ( n->axon < -1.0 ) n->axon = -1.0;
}

void Brain::Fire( BigNeuron* n )
{
	n->axon = 0.0;
	float d = 0.0;
	for ( int i = 0 ; i < 24 ; i++ )
	{
		if ( n->weight[i] )
		{
			n->axon += float( n->dendrite[i]->axon * n->weight[i] );
			d++;
		}
	}
	if ( d ) n->axon /= d;

	if ( n->axon > 1.0 ) n->axon = 1.0;
	if ( n->axon < -1.0 ) n->axon = -1.0;
}
# Change User Description Committed
#6 4463 Sam Stafford Notes on the genome.
 In the process of reviewing the neural wiring
code I fixed an ancient bug with "boolean" neurons.  Oops.
#5 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.
#4 4441 Sam Stafford Ported chase-cam view.
#3 4440 Sam Stafford Bug fixes, new features, the usual.
#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/Brain.cpp
#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.