// Genesaver: copyright 2003 Sam Stafford. #include <stdio.h> #include "globals.h" #include "dna.h" DNA::DNA(void) { } DNA::~DNA(void) { } DNA::DNA( DNA* d ) { hchr = d->hchr; for ( int i = 0 ; i < 6 ; i++ ) ichr[i] = d->ichr[i]; for ( int m = 0 ; m < D_M ; m++ ) Mutate(); } DNA::DNA( DNA* d, DNA* e ) { DNA* f; f = RandFloat() < 0.5 ? d : e; hchr = f->hchr; for ( int i = 0 ; i < 6 ; i++ ) { f = RandFloat() < 0.5 ? d : e; ichr[i] = f->ichr[i]; } for ( int m = 0 ; m < D_M ; m++ ) Mutate(); } void DNA::Dump( FILE* f ) { //Convert characters to ASCII hex and dump to file. int i, j, k; //write H-chromosome first // input dendrites for ( i = 0 ; i < 12 ; i++ ) PutChar( f, hchr.iden[i] ); fputc( '\n', f ); // input weights for ( i = 0 ; i < 12 ; i++ ) PutChar( f, hchr.iwgt[i] ); fputc( '\n', f ); // output weights for ( i = 0 ; i < 4 ; i++ ) { for ( j = 0 ; j < 24 ; j++ ) PutChar( f, hchr.owgt[i][j] ); fputc( '\n', f ); } // color for ( i = 0 ; i < 4 ; i++ ) PutChar( f, hchr.colr[i] ); fputc( '\n', f ); // size for ( i = 0 ; i < 4 ; i++ ) PutChar( f, hchr.size[i] ); fputc( '\n', f ); fputc( '/', f ); fputc( '\n', f ); //now the six I-chromosomes for ( i = 0 ; i < 6 ; i++ ) { // top level axons for ( j = 0 ; j < 4 ; j++ ) PutChar( f, ichr[i].ax0[j] ); fputc( '\n', f ); // weights for ( j = 0 ; j < 4 ; j++ ) { for ( k = 0 ; k < 4 ; k++ ) PutChar( f, ichr[i].wgt[j][k] ); fputc( '\n', f ); } // lower level axons for ( j = 0 ; j < 4 ; j++ ) PutChar( f, ichr[i].ax1[j] ); fputc( '\n', f ); // color PutChar( f, ichr[i].colr ); fputc( '\n', f ); // size PutChar( f, ichr[i].size ); fputc( '\n', f ); fputc( '/', f ); fputc( '\n', f ); } fputc( '%', f ); fputc( '\n', f ); } //load one DNA from a null- or EOF-terminated ASCII array. //return the position in the array reached. char* DNA::Load( char* file ) { char* f = file; char c; int i, j, k; //chomp '%' and '\n' delimiters while ( *f == '%' || *f == '\n' ) f++; //standard check for end of DNA strand, to be repeated. if ( *f == EOF || *f == NULL || *f == '%' ) return f; //H-chromosome time! // input dendrites for ( i = 0 ; i < 12 ; i++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; hchr.iden[i] = c; f++; } // input weights for ( i = 0 ; i < 12 ; i++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; hchr.iwgt[i] = c; f++; } // output weights for ( i = 0 ; i < 4 ; i++ ) { for ( j = 0 ; j < 24 ; j++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; hchr.owgt[i][j] = c; f++; } } // color for ( i = 0 ; i < 4 ; i++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; hchr.colr[i] = c; f++; } // size for ( i = 0 ; i < 4 ; i++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; hchr.size[i] = c; f++; } //chomp next '/', bail if EOF or % while (!( *f == EOF || *f == NULL || *f == '%' || *f == '/') ) f++; if ( *f != '/' ) return f; f++; //now the six I-chromosomes for ( i = 0 ; i < 6 ; i++ ) { // top level axons for ( j = 0 ; j < 4 ; j++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; ichr[i].ax0[j] = c; f++; } // weights for ( j = 0 ; j < 4 ; j++ ) { for ( k = 0 ; k < 4 ; k++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; ichr[i].wgt[j][k] = c; f++; } } // lower level axons for ( j = 0 ; j < 4 ; j++ ) { f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; ichr[i].ax1[j] = c; f++; } // color f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; ichr[i].colr = c ; f++; // size f = LoadChar( f, &c ); if ( *f == EOF || *f == NULL || *f == '%' ) return f; if ( *f == '/' ) break; ichr[i].size = c; f++; //chomp next '/', bail if EOF or % while (!( *f == EOF || *f == NULL || *f == '%' || *f == '/') ) f++; if ( *f != '/' ) return f; f++; } while (!( *f == EOF || *f == NULL || *f == '%' || *f == '/') ) f++; while ( *f == '%' || *f == '/' ) f++; return f; } // grab one char from ASCII hex and return pointer to last thing read. char* DNA::LoadChar( char* f, char* c ) { char s, o; while ( *f != EOF && *f && *f != '/' && *f != '%' ) { if ( ( *f >= '0' && *f <= '9' ) || ( *f >= 'A' && *f <= 'F' ) ) { s = *f; break; } f++; } if ( *f == EOF || !*f || *f == '/' || *f == '%' ) return f; f++; while ( *f != EOF && *f && *f != '/' && *f != '%' ) { if ( ( *f >= '0' && *f <= '9' ) || ( *f >= 'A' && *f <= 'F' ) ) { o = *f; break; } f++; } if ( *f == EOF || !*f || *f == '/' || *f == '%' ) return f; *c = Squish( s, o ); return f; } // Thanks to Mandi for humoring me and talking about gene mutation. void DNA::Mutate() { char* m; char* d = NULL; if ( RandFloat() < 0.35 ) //mutate the H-chromosome { int r = RandInt( 127 ); if ( r < 4 ) m = & hchr.colr[ RandInt( 3 ) ]; else if ( r < 8 ) m = & hchr.size[ RandInt( 3 ) ]; else if ( r < 20 ) m = & hchr.iden[ RandInt( 11 ) ]; else if ( r < 32 ) m = d = & hchr.iwgt[ RandInt( 11 ) ]; else m = d = & hchr.owgt[ RandInt( 3 ) ][ RandInt( 23 ) ]; } else //mutate a random I-chromosome //There is a disproportionately high chance of mutating a color //gene. This reduces the chance of one color overwhelming the //others and causing the genepool to grow stagnant. { int i = RandInt( 5 ); int r = RandInt( 31 ); if ( r < 4 ) m = & ichr[i].ax0[ RandInt( 3 ) ]; else if ( r < 8 ) m = & ichr[i].ax1[ RandInt( 3 ) ]; else if ( r < 15 ) m = & ichr[i].colr; else if ( r < 16 ) m = & ichr[i].size; else m = d = & ichr[i].wgt[ RandInt( 3 ) ][ RandInt( 3 ) ]; } char v = *m; float r = RandFloat(); if ( r < 0.5 ) //decrease *m = char( v - RandInt( v + 128 ) ); else //increase *m = char( v + RandInt( 127 - v ) ); if ( d && RandFloat() < 0.5 ) *d = 0; //50% chance of pruning a synapse } void DNA::PutChar( FILE* f, char c ) { unsigned char u = c + 128; char o = u & 0x0f; char s = u >> 4; if ( o < 10 ) o += 48; else o += 55; if ( s < 10 ) s += 48; else s += 55; fputc( s, f ); fputc( o, f ); } void DNA::Randomize() { char random[2*128+1+(2*26+1)*6+3]; char r; int n = 0; //H-chromosome - 128 bytes for ( int i = 0 ; i < 128*2 ; i++ ) { r = char( RandInt( 15 ) ); if ( r < 10 ) r += 48; else r += 55; random[n] = r; n++; } random[n] = '/'; n++; //6 I-chromosomes - 26 bytes each for ( int j = 0 ; j < 6 ; j++ ) { for ( int k = 0 ; k < 26*2 ; k++ ) { r = char( RandInt( 15 ) ); if ( r < 10 ) r += 48; else r += 55; random[n] = r; n++; } random[n] = '/'; n++; } random[n] = '%'; n++; random[n] = EOF; Load( random ); } char DNA::Squish( char s, char o ) { if ( s < 'A' ) s -= 48; else s -= 55; if ( o < 'A' ) o -= 48; else o -= 55; unsigned char u = s * 16 + o; return u - 128; } void DNA::Clear() { //zero everything out int i, j, k; for ( i = 0 ; i < 4 ; i++ ) { hchr.colr[i] = hchr.size[i] = 0; for ( j = 0 ; j < 24 ; j++ ) hchr.owgt[i][j] = 0; } for ( i = 0 ; i < 12 ; i++ ) hchr.iden[i] = hchr.iwgt[i] = 0; for ( i = 0 ; i < 6 ; i++ ) { ichr[i].colr = ichr[i].size = 0; for ( j = 0 ; j < 4 ; j++ ) { ichr[i].ax0[j] = ichr[i].ax1[j] = 0; for ( k = 0 ; k < 4 ; k++ ) ichr[i].wgt[j][k] = 0; } } } void DNA::CreatePainter( char color ) { Clear(); //set color as specified int i; char c; switch( color ) { case 'r': c = 0; break; case 'g': c = 1; break; case 'b': c = 2; break; default: c = RandInt( 2 ); } for ( i = 0 ; i < 4 ; i++ ) { hchr.colr[i] = c; } for ( i = 0 ; i < 6 ; i++ ) { ichr[i].colr = c; } //create the robotic painter //absolute pointer at favorite color //connect appropriate color input to left pair of 3rd lobe hchr.iden[2] = c + 1; hchr.iwgt[2] = 32; //parallel connections down ichr[2].wgt[0][0] = 32; ichr[2].wgt[1][1] = 32; //outputs hchr.owgt[0][8] = 12; hchr.owgt[1][9] = 12; //lean towards close food hchr.iden[0] = 0; hchr.iwgt[0] = 32; ichr[0].wgt[0][0] = 32; ichr[0].wgt[1][1] = 32; hchr.owgt[0][0] = 16; hchr.owgt[1][9] = 16; //now the logic to slow down if getting good food hchr.iden[11] = 6; hchr.iwgt[11] = 32; ichr[5].wgt[0][2] = 32; hchr.owgt[2][19] = -32; //gravitate towards neighbors just a bit hchr.iden[9] = 4; hchr.iwgt[9] = 32; ichr[3].wgt[2][2] = 32; ichr[3].wgt[3][3] = 32; hchr.owgt[0][18] = 4; hchr.owgt[1][19] = 4; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#3 | 4465 | Sam Stafford |
Genetically engineered organisms - there's now an option to seed the initial population with these relentlessly efficient creatures rather than random mutants. Kinda neat-looking, but not as organic-looking as pure evolved creatures. |
||
#2 | 4447 | Sam Stafford | Cleanup size-heredity code. | ||
#1 | 4430 | Sam Stafford |
Start importing alife/AI code from Genesaver. Much tweaking will need to be done. |
||
//guest/sam_stafford/genesaver/src/DNA.cpp | |||||
#3 | 3351 | Sam Stafford | Fixed a typo in change 3347 (increase odds of color mutation). | ||
#2 | 3347 | Sam Stafford | Increase likelihood of color mutation. | ||
#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. |