#include "SDL/SDL.h" #include #include // this is the pure GP version. // adhoc changelog // 4.99 -> 4.99.99: saveall/loadall added. last 4.xx ever // 4.98 -> 4.99: save/load made binary, windows-safe // ?? -> 4.98: export/import DNA IP // fuck maybe when they flip over 255 i should breed them to a random square // keys to let user toggle: // dna phase // ca phase // breeding (opposed to splitting) // get DNA loading in! // CA is pretty hard so now gives add 1 energy, ok? // views: // actions (needs a new grid to store em) // age? (add lifetime array then, too) // sexiness (% operands > 8) * 2.55 < do this still // skip counters // generation count (highestgen-lowestgen)/((gen-lowestgen)+1) // dna IP // // read how to set the palette // why is avggen wrong // have cell selection and ip in the dna view // end old notes, start configurables //define gridrows 170 //define gridcols 213 // weird plasma vortex w/ nature patterns #define gridrows 140 #define gridcols 213 // ropes (?) // these dimensions were chosen to fit in the window well // after scaling... if you bump them you can change the // appearance of the stripes you see if you turn DNA off // I think these are involved in making the weird knots // and weaves you might see... // also change float DNA_View_Cell_Size_Divisor way under this if you change the sizes very much // because cell sizes (when displayed) will also change... // note at certain sizes the drawgrid function will crash. my bad. crash-proof resizing coming soon. // just try different sizes if that happens for now int popsize = gridrows*gridcols; #define screenwidth 1280 #define screenheight 1024 #define biteAmount 4 // energy moved per bite. this is also how much a give transfers #define freeGiveBonus 6 // energy added on a give // see if this is enough they can generate among // relatives with gives if so #define freeEnergyToOffspring 8 // who knows. 5/7/8 here is also nice #define DNA_Length 2048 // hm #define mutantrate 33 // 1/n offspring will be mutated. minimum is 1 (100%) #define remutaterate 10 // 9/n chance of repeat mutations #define sexoperandpersistance 5 // frames of sim time (cumulative so 5 is high) #define max_breed_fairness 20 // number of allowed recursions, max 255 // many more configurables below... in main() /* * Set the pixel at (x, y) to the given value * NOTE: The surface must be locked before calling this! */ void putpixel(SDL_Surface *surface, int x, int y, Uint8 pixel) { // int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ // Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 1; // switch(1) { // case 1: *p = pixel; // break; return; /* case 2: *(Uint16 *)p = pixel; break; case 3: if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { p[0] = (pixel >> 16) & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = pixel & 0xff; } else { p[0] = pixel & 0xff; p[1] = (pixel >> 8) & 0xff; p[2] = (pixel >> 16) & 0xff; } break; case 4: *(Uint32 *)p = pixel; break; } */ } void fillcell(SDL_Surface *surface, int cellw, int cellh, int x, int y, int xspace, int yspace, int yoff, Uint8 color) { int xstart = (cellw+xspace)*x; int xend = (cellw+xspace)*(x+1)-xspace; int ystart = ((cellh+yspace)*y)+yoff; int yend = ((cellh+yspace)*(y+1)-yspace)+yoff; int j; int i; unsigned int randomdivisor = RAND_MAX>>8; // printf ("%i\n", color); for (j = ystart; j < yend; j++) { for (i = xstart; i < xend; i++) { putpixel(surface, i, j, color); } } if ( SDL_MUSTLOCK(surface) ) { SDL_UnlockSurface(surface); } } void drawgrid(SDL_Surface *surface, Uint8 **DNA, Uint8 *grid, int drawgrid_gridrows, int drawgrid_gridcols, int cellw, int cellh, int xspace, int yspace, int drawgrid_screenwidth, int drawgrid_screenheight, int DNA_View_Cell_Size_Divisor, int drawgrid_DNA_Length, int view, int viewdata1, int viewdata2, int * viewdata3, Uint8 * viewdata4) { int i; int j; for (i = 0; i < drawgrid_gridrows; i++) { for (j = 0; j < drawgrid_gridcols; j++) { // printf ("draw %i,%i,%i",i,j,*grid); if (view == 0) { fillcell(surface, cellw, cellh, j, i, xspace, yspace, 0, *grid); grid += 1; } else if (view > 0) { // generations, stuns int c; if (view == 1 || view == 4) { // integer tables c = ((int) 255.0f*(((float)(*viewdata3)-(float)viewdata1)/(((float)viewdata2-(float)viewdata1)+1.0f))); viewdata3 += 1; } else if (view == 2 || view == 3 || (view >= 5 && view <= 9)) { // uint8 tables c = ((int) 255.0f*(((float)(*viewdata4)-(float)viewdata1)/(((float)viewdata2-(float)viewdata1)+1.0f))); viewdata4 += 1; } if (c > 255) { c = 255; } // if (view == 2 && c > 0) { printf ("graph individual of stun count %i as color %i. low = %i high = %i \n", *viewdata4, c, viewdata1, viewdata2); } fillcell(surface, cellw, cellh, j, i, xspace, yspace, 0, c); } } } int t = drawgrid_DNA_Length/((drawgrid_gridcols*DNA_View_Cell_Size_Divisor)-3)+1; int dnactr=0; Uint8 *somedna = *DNA; for (i = drawgrid_gridrows; i < drawgrid_gridrows+t; i++) { for (j = 0; j < (drawgrid_gridcols*DNA_View_Cell_Size_Divisor)-3; j++) { // printf("debug: draw dna %i,%i\n", j, i-drawgrid_gridrows); fillcell(surface, cellw/DNA_View_Cell_Size_Divisor, cellh/DNA_View_Cell_Size_Divisor, j, i-drawgrid_gridrows, xspace, yspace, drawgrid_gridrows*(cellh+yspace), *somedna); somedna++; dnactr++; if (dnactr >= drawgrid_DNA_Length) { break; } } if (dnactr >= drawgrid_DNA_Length) { break; } } /* Update just the part of the display that we've changed */ SDL_UpdateRect(surface, 0, 0, drawgrid_screenwidth-1, drawgrid_screenheight-1); } void loadcrit (int dnalength, int popsize, Uint8 **DNA, unsigned int *DNA_IP, unsigned int *generations, char *fn) { int i; int j; int q = (random()/(RAND_MAX>>8))%4; Uint8 loaddna[dnalength]; printf("Attempting to load from ./ca-ga.load.dna\n"); FILE*iff=fopen(fn,"rb"); if (iff == NULL) { printf("puke (no such dna file)\n"); return; } unsigned int loadedgeneration = 0; unsigned int loadeesdnaip = 0; loadedgeneration = (int) getc(iff)*256; loadedgeneration+= (int) getc(iff); loadeesdnaip = (int) getc(iff)*256; loadeesdnaip+= (int) getc(iff); for (i = 0; i < dnalength; i++) { loaddna[i] = getc(iff); } fclose(iff); printf( "DNA loaded\n"); int many = 0; for (i = 0; i < popsize; i++) { q++; if (q == 4) { // printf("Load one to pop offset #%i\n", i); q = 0; *generations = loadedgeneration; *DNA_IP = loadeesdnaip; Uint8 *somedna = *DNA; for (j=0;j 0; soughtgen--) { while (*generations != soughtgen && offs < popsize) { //printf("debug: skipping animal of gen %i not of %i\n", *generations, soughtgen); generations++; DNA_IP++; offs++; } if (offs >= popsize) { generations-=popsize; DNA_IP-=popsize; offs = 0; } else {break;} } if (soughtgen>0) { // DNA+=(dnalength*offs); pre malloc? DNA+=offs; Uint8 *somedna = *DNA; printf ("Succeeds at population offset %i with critter of generation #%i\n", offs, soughtgen); int c; printf ("Write "); FILE*of=fopen(fn,"wb"); putc((char) (*generations/ 256), of); putc((char) (*generations% 256), of); //or what putc((char) (*DNA_IP/ 256), of); putc((char) (*DNA_IP% 256), of); //or what for (c = 0; c < dnalength; c++) { putc((char) somedna[c], of); // DNA++; } fclose(of); printf ("succeeded\n"); } else { printf ("wtf i couldn't find any DNA over generation -1\n"); } } void loadall(int dnalength, int popsize, Uint8 **DNA, unsigned int *DNA_IP, unsigned int *generations, char *fn) { // untested yet in ca-ga.c int i; int j; Uint8 loaddna[dnalength]; int many = 0; printf("Attempting to load DNA from %s\n", fn); FILE*iff=fopen(fn,"rb"); if (iff == NULL) { printf("puke (no such dna file)\n"); return; } unsigned int loadedgeneration = 0; unsigned int loadeesdnaip = 0; for (i = 0; i < popsize; i++) { loadedgeneration = (int) getc(iff)*256; loadedgeneration+= (int) getc(iff); loadeesdnaip = (int) getc(iff)*256; loadeesdnaip+= (int) getc(iff); for (j = 0; j < dnalength; j++) { loaddna[j] = getc(iff); } printf("generation %i DNA_IP %i pop offset #%i\n", loadedgeneration, loadeesdnaip, i); *generations = loadedgeneration; *DNA_IP = loadeesdnaip; Uint8 *somedna = *DNA; for (j=0;j>8; unsigned int c; // Uint8 *somedna = DNA[source_x][source_y]; recurse += 1; // printf ("recursive_fair_breed(start)\n"); if (offspring[dest_x][dest_y][0] != 255) { // not safe to breed yet. recurse if (x_3 != 255 && (dest_x == x_3 && dest_y == y_3)) { // printf("recurse: Three cells trying to loop the recurser. Prioritizing the first\n"); } else if ((offspring[dest_x][dest_y][0] == source_x && offspring[dest_y][dest_x][1] == source_y) ) { // printf("recurse: Two cells trying to overwrite each other, prioritizing the first\n"); // would be better to do the swap they want rather than cancel the second or // third breeder in the loop... but how } else { // could still get stuck on loops of 3 or more cells so. use a // max recursion, max_breed_fairness ! if (recurse <= max_breed_fairness) { // printf("recurse: recursive_fair_breed(source_x=%i source_y=%i dest_x=%i dest_y=%i)\n", dest_x, dest_y, offspring[dest_x][dest_y][0], offspring[dest_x][dest_y][1]); recurse = recursive_fair_breed(dest_x, dest_y, offspring[dest_x][dest_y][0], offspring[dest_x][dest_y][1], source_x, source_y, offspring, DNA, generations, sexctr, skips, DNA_IP, dnarun_add, breeds, splits, maxIP, sex_on, recurse); // printf("recurse: comes back after recurse of %i\n", recurse); } else { } // printf("recurse: recursed too deep\n"); } } } // fall thru Uint8 *thisdna = (Uint8 *) DNA[source_x][source_y]; dnarun_add[dest_x][dest_y] += freeEnergyToOffspring; // recolor int lastip = DNA_IP[dest_x][dest_y]; if (lastip > *maxIP) { *maxIP = lastip; } DNA_IP[dest_x][dest_y] = 0; // reboot sexctr[dest_x][dest_y] = 0; skips[dest_x][dest_y] = 0; int mutant = (random()/randomdivisor) % mutantrate; // n% are mutants //breedorsplit = (random()/randomdivisor) % 2; // half the time breed // half the time split if (sexctr[source_x][source_y]>0 && sex_on) { // mingle (slow!) // printf ("mingle\n"); generations[dest_x][dest_y] = ((generations[source_x][source_y] + generations[dest_x][dest_y])>>1);//+1; // same generation dont increment.. *breeds += 1; int r = 0; char b = (random()/randomdivisor); // printf ("init newdna\n"); Uint8 *newdna = (Uint8 *) DNA[dest_x][dest_y]; // printf ("newdna init'd\n"); for (c = 0; c < DNA_Length; c++) { if (b&1) { // parent newdna[c] = thisdna[c]; // printf ("2\n"); } // else { // DNA[destx][desty][c] = thisdna[c]; // keeps its own byte // printf ("1\n"); // } } b>>1; r++; if (r == 8) { r = 0; b = (random()/randomdivisor); } } else { // split // printf ("3\n"); // printf ("split\n"); generations[dest_x][dest_y] = generations[source_x][source_y]; *splits += 1; // printf ("init newdna\n"); Uint8 *newdna = (Uint8 *) DNA[dest_x][dest_y]; // printf ("newdna init'd\n"); for (c = 0; c < DNA_Length; c++) { newdna[c] = thisdna[c]; } } if (mutant == 0) { // printf("mutate\n"); generations[dest_x][dest_y]++; int maxoffset; // if ((random())>(RAND_MAX>>1)) { // bias if (lastip>DNA_Length) {lastip=DNA_Length-2;} maxoffset = (lastip>>1)+1; // last op // } else { // dont // maxoffset = (DNA_Length_div_two); // } // trying if i always bias. this is only bad when // IP's start hitting max and rolling over. using // a table of lifespans to decide what offset if // any to mutate under would be superior to this, // for when that happens. otherwise biasing half // the time i think is an expensive hack int first = 1; int oporarg = (random()/randomdivisor)%2; // damn a whole byte of randomness for this int limit; // ^ this is ok now if (oporarg > 0) { limit = 24; } else { limit = 4; } while (((random()/randomdivisor)%remutaterate < 9) || first) { first = 0; // int offset = ( ( ( (int)(random()/randomdivisor) )*256 )+(int)(random()/randomdivisor) ) % (DNA_Length/2); // as long as all mutations reboot you we can just mutate bytes up to the // highest IP this cell has reached yet and get more useful mutations in // cold parts of the world that way // it's not the destination's DNA we use after a kill // unless it was a breed. but i think collecting mutations // to under the IP of the dead cell about half the time // say, will make species faster and promote strategies // to live long to preserve early genetic material. only // problem is critters who live to the end of the genome // and loop will still only get mutated under the point // where they died in spite of having run the whole thing // unless i had a table for ones that had or an extra // check here so i'll just do it half the time instead // kind of a bias. well it looks good in practice tbh int offset = ( ( ( (int)(random()/randomdivisor) )<<8 )+(int)(random()/randomdivisor) ) % (maxoffset); int c = ((random()/randomdivisor)%limit)%16; thisdna[offset*2 + oporarg] = c; } } offspring[source_x][source_y][0] = 255; offspring[source_x][source_y][1] = 255; offspring[dest_x][dest_y][0] = 255; offspring[dest_x][dest_y][1] = 255; return recurse; } int main(int argc, char *argv[]) { FILE*rand=fopen("/dev/urandom","r"); srand(getc(rand)); srandom(getc(rand)); fclose(rand); // printf("cat /dev/urandom to stdin to start it\n"); Uint8 CA_on = 1; Uint8 DNA_on = 1; Uint8 sex_on = 1; Uint8 view = 0; // int drawevery = 60; // int drawevery = 13; int autosaveevery = 30000; // if 50 cycles is one second this is about an // an hour unsigned int randomdivisor = RAND_MAX>>8; int drawevery = 3; int exitafter = 0; // int biteAmount = 7; // i evolved for a while at these settings but // int freeGiveBonus = 5; // i dont think they're enough // int biteAmount = 12; // // int freeGiveBonus = 7; // cells still don't live long at these values // int biteAmount = 5; // int freeGiveBonus = 3; // int freeEnergyToOffspring = 7; // int gridrows = 170; // int gridcols = 213; // you get weird ropes around this ratio // fuck with it, maybe smaller and they // knot up and shit // int gridrows = 70; // ok // int gridcols = 110; // int gridrows = 52; // also ok // int gridrows = 66; // int gridrows = 104; // int gridcols = 142; // int gridrows = 111; // int gridcols = 142; // make it fit (ropy) // int minspacingx = 2; // int minspacingy = 2; int minspacingx = 1; int minspacingy = 1; // maybe store a max IP per cell and only mutate offsets up to it would be // smart // int mutantrate = 9; // 1/n offspring will be mutated. minimum is 1 (100%) // int remutaterate = 4; // 2/n chance of repeat mutations // int DNA_Length = 16384; // even numbers only ok, over 256 is ok (offset takes 2 bytes randomness) // int DNA_Length = 8192; int DNA_Length_div_two = DNA_Length / 2; // remember only even dna lengths float DNA_View_Cell_Size_Divisor = 2; // or use 2 most of the time // it crashed for me at 3 one time printf("init dna\n"); Uint8 **DNA[gridcols][gridrows]; Uint8 **dnaptr = &DNA; unsigned int DNA_IP[gridcols][gridrows]; // maybe I can give them n heads a piece and when bumped, they can jmp // the head which some index i just increment to dnalength per frame is // closest to... rather than every head or something. then they can // have some parallel evaluation. just add [heads] here and a heads // loop to the dna run. later on // oh give them a head for each direction then pokes can jump the head // for the dir they came from, 8 heads unsigned int generations[gridcols][gridrows]; Uint8 skips[gridcols][gridrows]; Uint8 newskips[gridcols][gridrows]; // DNA: // 1 byte, 1 byte // byte 1: suck/give/wait // byte 2: direction // if sucking puts a cell under 0 copy dna to it // with mutations int drawsbetweenscoreoutput = 1000; int c = 0; int i = 0; int j = 0; int lostfights = 0; int wonfights = 0; int nops = 0; // not too sure... maybe a fight should be harder with a cell who is NOP'ing // ok. it is printf ("load dna\n"); for (i = 0; i < gridrows; i++) { // what if it was self-modifying? three new for (j = 0; j < gridcols; j++) { // opcodes could move a head and pop DNA_IP[j][i] = 0; // the cell's value or one from a stack. // hm skips[j][i] = 0; newskips[j][i] = 0; generations[j][i] = 0; DNA[j][i] = malloc(DNA_Length+1); Uint8 *thisdna = DNA[j][i]; // these should be bit packed (its only 6 bits information per opcode & operand atm) for (c = 0; c <= DNA_Length; c++) { thisdna[c] = (random()/randomdivisor)%4; c++; thisdna[c] = (random()/randomdivisor)%16; } } } printf ("random dna ready\n"); Uint8 *thisdna = &DNA; printf ("%i\n", (int) thisdna[0]); printf ("%i\n", (int) (random()/RAND_MAX)); int cellwidth = (screenwidth/gridcols)-minspacingx; int cellheight = (screenheight/(gridrows+((DNA_Length/DNA_View_Cell_Size_Divisor)/(gridcols*DNA_View_Cell_Size_Divisor))+1))-minspacingy; int xspace = minspacingx+((screenwidth-(gridcols*(cellwidth+minspacingx))) / gridcols); int yspace = minspacingy+((screenheight-((gridrows+((DNA_Length/DNA_View_Cell_Size_Divisor)/(gridcols*DNA_View_Cell_Size_Divisor))+1)*(cellheight+minspacingy))) / (gridrows+(DNA_Length/gridcols)+1)); printf ("screenwidth %i\nscreenheight %i\ngridX %i\ngridY %i\ncellwidth %i\ncellheight %i\nxspace %i\nyspace %i\n", screenwidth, screenheight, gridcols, gridrows, cellwidth, cellheight, xspace, yspace); Uint8 grid[gridcols][gridrows]; // int tctr=0; printf ("get grid\n"); for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { // grid[j][i] = (j*i)*4; // interesting seed grid[j][i] = (random()/randomdivisor); // grid[j][i] = tctr; tctr++; if(tctr>255){tctr=0;} // printf ("grid[%i][%i] = %i\n", j, i, grid[j][i]); if (grid[j][i] > 256) { grid[j][i] = 0; } // grid[j][i] = 30; } } printf("Initializing SDL.\n"); /* Initialize defaults, Video and Audio */ if((SDL_Init(SDL_INIT_VIDEO)<0)) { printf("Could not initialize SDL: %s.\n", SDL_GetError()); exit(-1); } printf("SDL initialized.\n"); /* Clean up on exit */ atexit(SDL_Quit); SDL_Event event; /* * Initialize the display in a 640x480 8-bit palettized mode, * requesting a software surface */ SDL_Surface *screen; screen = SDL_SetVideoMode(screenwidth, screenheight, 8, SDL_SWSURFACE); if ( screen == NULL ) { fprintf(stderr, "Couldn't set %ix%ix8 video mode: %s\n", screenwidth, screenheight, SDL_GetError()); exit(1); } Uint8 tgrid[gridcols][gridrows]; for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { tgrid[j][i] = grid[j][i]; } } Uint8 dnarun[gridcols][gridrows]; for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { dnarun[j][i] = grid[j][i]; } } Uint8 dnarun_sub[gridcols][gridrows]; for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { dnarun[j][i] = grid[j][i]; } } Uint8 dnarun_add[gridcols][gridrows]; for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { dnarun[j][i] = grid[j][i]; } } Uint8 actions_view[gridcols][gridrows]; for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { dnarun[j][i] = grid[j][i]; } } Uint8 offspring[gridcols][gridrows][2]; // to buffer reproduction for second run // NOTE if you need a grid larger than // 254x254, change Uint8 here to an int ! // and initialize offspring[] initial // values to -1 instead of 255 and // change the check in the breed run // accordingly and the set in the // dna run for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { offspring[j][i][0] = 255; offspring[j][i][1] = 255; } } // int lastip[gridcols][gridrows]; // for better mutations // for (i = 0; i < gridrows; i++) { // for (j = 0; j < gridcols; j++) { // lastip[j][i]=1; // } // } // oh it only takes one int int maxIP = 0; // probably need a table for graphing actions // what about buffering the actions of low energy critters for n frames // and letting high energy critters act faster? int giveamount = biteAmount+freeGiveBonus; // careful Uint8 sexctr[gridcols][gridrows]; for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { sexctr[j][i] = 0; } } int t = 0; int tt = 0; // no float avggen = 0; // int y = 0; int gridlastx = gridcols-1; int gridlasty = gridrows-1; int up; int down; int left; int right; int maxrecursions = 0; int cycles=0; int highgen = 0; int lowgen = -1; int lowgeninpop = -1; int highestgen = 0; int skipsctr = 0; int pokes = 0; int gives = 0; int bites = 0; int kills = 0; int breeds = 0; int splits = 0; int autosavectr = 0; int viewdata1; int viewdata2; int *viewdata3; Uint8 *viewdata4; for (t = 0; t < 100; t++) { drawgrid(screen, DNA, *grid, gridrows, gridcols, cellwidth, cellheight, xspace, yspace, screenwidth, screenheight, DNA_View_Cell_Size_Divisor, DNA_Length, view, 0, 0, 0, 0); } //printf("intro draw\n"); } t = 0; printf("\nHit 'h' in the window for options\n"); int reverseEvaluation = 0; signed int inc; int startx; int starty; int lastx; int lasty; Uint8 z = (Uint8) gridcols>>1; Uint8 y = gridrows>>1; Uint8 z2 = (Uint8) gridcols>>2; Uint8 y2 = gridrows>>2; Uint8 z3 = (Uint8) gridcols>>4; Uint8 y3 = gridrows>>4; Uint8 gridrowsminusy2 = gridrows - y2; Uint8 gridcolsminusz2 = gridcols - z2; // ^ move these inside the loop if you allow resizing the grid while(1) { // live Uint8 run; int i; int j; /* Poll for events. SDL_PollEvent() returns 0 when there are no */ /* more events on the event queue, our while loop will exit when */ /* that occurs. */ while( SDL_PollEvent( &event ) ){ /* We are only worried about SDL_KEYDOWN and SDL_KEYUP events */ switch( event.type ){ case SDL_KEYDOWN: /* Check the SDLKey values and move change the coords */ switch( event.key.keysym.sym ){ case SDLK_SLASH: printf(""); case SDLK_h: printf ("(( Key help\n\ (V) to toggle views\n\ (D) to toggle DNA\n\ (C) to toggle CA\n\ (S) to toggle sex\n\ (X) to export a DNA\n\ (L) to load some DNA\n\n\ PgDwn saves the whole population to files starting ca-ga.whole-pop.*\n\ PgUp loads the whole population from files starting ca-ga.whole-pop.*\n\n\ (Q) to export some strains & quit\n"); break; case SDLK_d: if (DNA_on) {DNA_on=0;printf("DNA run suspended! D to resume\n"); } else {DNA_on=1;printf("DNA run enabled. Thank you\n");} break; case SDLK_c: if (CA_on) {CA_on=0;printf("CA run suspended! C to resume\n"); } else {CA_on=1;printf("CA run enabled. Good luck\n");} break; case SDLK_s: if (sex_on) {sex_on=0;printf("Sex disallowed, S to resume\n"); } else {sex_on=1;printf("The reproductive suppression field has been disabled\n");} break; case SDLK_v: if (view == 0) {view=1;printf("Generation count view on, V to switch\n");} else if (view == 1) {view=2;printf("Stun view on, V to switch\n");} else if (view == 2) {view=3;printf("Breed mood view on, V to switch\n");} else if (view == 3) {view=4;printf("DNA IP view on, V to switch\n");} else if (view == 4) {view=5;printf("Give view on, V to switch\n");} else if (view == 5) {view=6;printf("Bite view on, V to switch\n");} else if (view == 6) {view=7;printf("Poke view on, V to switch\n");} else if (view == 7) {view=8;printf("Fight view on, V to switch\n");} else if (view == 8) {view=9;printf("NOP view on, V to switch\n");} else if (view == 9) {view=0;printf("Normal view on, V to switch\n");} break; case SDLK_x: savecrit(highgen, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.best.dna"); savecrit(avggen, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.average.dna"); savecrit(lowgen+1, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.low.dna"); break; case SDLK_q: savecrit(highgen, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.best.dna"); savecrit(avggen, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.average.dna"); savecrit(lowgen+1, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.low.dna"); printf("Free DNA\n"); for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { Uint8 *temp = DNA[gridcols][gridrows]; // free(&temp); } } printf("Shutdown\n"); return 0; break; case SDLK_l: printf("Load ca-ga.load.dna\n"); loadcrit(DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.load.dna"); break; case SDLK_PAGEUP: printf("Load ca-ga.whole-pop.load.dna (make sure its exists)\n"); loadall(DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.whole-pop.load.dna"); break; case SDLK_PAGEDOWN: saveall(DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.whole-pop.dna"); break; default: break; } break; case SDL_KEYUP: break; default: break; } } highgen = 0; avggen = 0; if (reverseEvaluation > 0) { startx = gridlastx; lastx = -1; inc = -1; starty = gridlasty; lasty = -1; // startx = gridlastx; lastx = 255; inc = -1; // set 255 to allow underflow // on Uint8 loop counters // its just faster // starty = gridlasty; lasty = 255; reverseEvaluation = 0; } else { startx = 0; lastx = gridlastx+1; inc = 1; starty = 0; lasty = gridlasty+1; reverseEvaluation = 1; } // i think the GA is so fair we don't need to do this anymore... // oh the recursive fair breeder will prioritize first comers on // the board eval order so we might as well still go both ways... // darn if (view >= 5 && view <= 9) { for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { actions_view[j][i] = 0; } } } for (run = 0; run < 3; run++) { // eval in reverse half the time // to get rid of the 'wind' from // not using enough temp grids to // make all the actions fair // in both directions // all the time // printf("run %i\n", run); for (i = starty; i != lasty; i+=inc) { for (j = startx; j != lastx; j+=inc) { // for (i = 0; i < gridrows; i++) { // for (j = 0; j < gridcols; j++) { signed int newcell; if (run == 0) { // dna run offspring[j][i][0] = 255; offspring[j][i][1] = 255; // newskips[j][i] = 0; if (DNA_on) { newcell = grid[j][i]; newcell *= .97; // fade // dnarun[j][i] = newcell; if (sexctr[j][i]>0) { sexctr[j][i]--; } if (skips[j][i] > 7) { // printf("skip"); skipsctr++; // skip makes goto's now, like direction sense sorta (no see below) //DNA_IP[j][i] += (skips[j][i]%8)*2; //while (DNA_IP[j][i] >= DNA_Length) {DNA_IP[j][i] -= DNA_Length;} // ^ since Pokes and Fights both push out a critter's IP, and NOP // doesn't except at this stage, and is a defense against Fight // ... this line would turn NOP's into JMP's... without it, they // could NOP twice to stun themselves into spending an extra // frame on the defensive NOP. newskips[j][i] = skips[j][i] - 8; } else { if (skips[j][i] > 0) { newskips[j][i] = 0; } Uint8 *thisdna = DNA[j][i]; Uint8 op = thisdna[DNA_IP[j][i]]; Uint8 arg = thisdna[DNA_IP[j][i]+1]; Uint8 destx = 0; // NOTE if you ever need a grid bigger than Uint8 desty = 0; // 254x254, make these ints! // and initialize offspring[] initial // values to -1 instead of 255 and // change the check in the breed run // accordingly... and the set in the // dna run... ok! if (op != 0) { if (i == 0) { up = gridlasty; } else { up = i-1; } if (i == gridlasty) { down = 0; } else { down = i+1; } if (j == 0) { left = gridlastx; } else { left = j-1; } if (j == gridlastx) { right = 0; } else { right = j+1; } while (arg > 7) { arg -= 8; sexctr[j][i] += sexoperandpersistance; } if (arg == 0) { destx = left; desty = up; } else if (arg == 1) { destx = j; desty = up; } else if (arg == 2) { destx = right; desty = up; } else if (arg == 3) { destx = left; desty = i; } else if (arg == 4) { destx = right; desty = i; } else if (arg == 5) { destx = left; desty = down; } else if (arg == 6) { destx = j; desty = down; } else if (arg == 7) { destx = right; desty = down; } /* Uint8 wonafight = 0; if (op == 4) { // fight if (view == 8 && t == drawevery-1) { actions_view[destx][desty] += 1; } int high = grid[destx][desty]; int low = grid[j][i]; Uint8 *fighteedna = DNA[destx][desty]; Uint8 fighteeop = fighteedna[DNA_IP[destx][desty]]; if (fighteeop == 0) { low = low >> 1; // double fight difficulty // if victim is un busy // (NOP) which also // opens them to // poke skips and // communication... err if (view == 8 && t == drawevery-1) { actions_view[destx][desty] += 2; actions_view[j][i] += 2; } } // if (low > high) { int T = low; low = high; high = T; } // if ((random()/randomdivisor) % (high+1) <= (low>>4)) { // win fight (oops always uses high cell's odd) if ((random()/randomdivisor) % ((low>>2)+2) >= (random()/randomdivisor) % (high+1)) { // win fight (~ 1/4 chance against cell of equal energy, // ~ 1/2 chance against cell of half energy, // ~ 1/10 chance against cell of double energy, // 2.5% chance against cell of 10x energy) op = 2; wonafight = 1; wonfights += 1; if (view == 8 && t == drawevery-1) { actions_view[j][i] += 2; } //dnarun_add[destx][desty] += biteAmount; } else { // newcell -= biteAmount>>1; newcell -= biteAmount; // they fight too much take off full biteAmount instead... // dnarun_sub[destx][desty] += biteAmount>>1; // both lose some energy for a lost fight if (newcell < 0) { newcell = 0; } lostfights += 1; if (fighteeop != 0) { DNA_IP[destx][desty] += (arg+1)<<2; // lost fight signals the winner // with a skip (up to // 32 bytes), if it // is not nopping while(DNA_IP[destx][desty] > DNA_Length) { DNA_IP[destx][desty] -= DNA_Length; } } else { newskips[destx][desty] += (arg+8); newskips[j][i] += (arg+12); // so defender can sit on a // NOP if it wants, stun both // instead... loser for longer // on average. actually 'skip' // refers to turns not operations newcell -= biteAmount >> 1; dnarun_add[destx][desty] += biteAmount>>1; // minimal energy transfer // to NOPper to help keep // mad energy dynamics // among the extra stunning if (newcell < 0) { newcell = 0; } } if (view == 8 && t == drawevery-1) { actions_view[destx][desty] += 2; actions_view[j][i] += 1; } } } */ if (op == 2) { // suck if (view == 6 && t == drawevery-1) { actions_view[destx][desty] += 1; } // signed int w = (signed int) dnarun[destx][desty]; signed int w = (signed int) grid[destx][desty]; w -= biteAmount; newcell += biteAmount; if (w < 0) { // kill & breed offspring[j][i][0] = destx; offspring[j][i][1] = desty; kills += 1; } else { // no kill just bite dnarun_sub[destx][desty] += biteAmount; } bites += 1; } else if (op == 1) { // give dnarun_add[destx][desty] += giveamount; newcell -= biteAmount; if (newcell < 0) { newcell = 0; } gives += 1; if (view == 5 && t == drawevery-1) { actions_view[destx][desty] += 1; } } else if (op == 3) { // poke newskips[destx][desty] += arg+1; DNA_IP[destx][desty] += (arg+1)<<1; while(DNA_IP[destx][desty] > DNA_Length) { DNA_IP[destx][desty] -= DNA_Length; } pokes += 1; if (view == 7 && t == drawevery-1) { actions_view[destx][desty] += 1; } } } else { // no-op, vulnerable to poke, harder to fight newskips[j][i] += 7; nops += 1; if (view == 9 && t == drawevery-1) { actions_view[j][i] += 1; } } // unindented poke skip check ends } // newcell += (signed int) ((signed int) grid[j][i] - (signed int) dnarun[j][i]); while (newcell > 255) { newcell -= 255; } // if (newcell < 0) { newcell == 1; } dnarun[j][i] = newcell; //if (dnarun[j][i] <= 0) { dnarun[j][i] = 1; } DNA_IP[j][i]+=2; while (DNA_IP[j][i] >= DNA_Length) { DNA_IP[j][i] -= DNA_Length; } // end DNA run } else { // if DNA_on is off newcell = grid[j][i]; // newcell *= .97; // no fade dnarun[j][i] = newcell; } } else if (run == 1) { // breed run if (DNA_on) { if (offspring[j][i][0] != 255) { // change 255 to -1 here, // at the top of the DNA // run, and where we declare // offspring[] if you need // grids > 254x254... grr if (recursive_fair_breed(j, i, offspring[j][i][0], offspring[j][i][1], 255, 255, offspring, DNA, generations, sexctr, skips, DNA_IP, dnarun_add, &breeds, &splits, &maxIP, sex_on, 0) > max_breed_fairness) { maxrecursions += 1; } } // indent this, flamoot } else {// DNA_on off } // end breed run if (highgen < generations[j][i]) {highgen = generations[j][i];} avggen += generations[j][i]; if (lowgeninpop > generations[j][i]) {lowgeninpop = generations[j][i]; lowgen = generations[j][i];} } else { // CA run newcell = dnarun[j][i]; newcell += dnarun_add[j][i]; newcell -= dnarun_sub[j][i]; dnarun_add[j][i] = 0; dnarun_sub[j][i] = 0; skips[j][i] = newskips[j][i]; // newskips[j][i] = 0; if (CA_on) { newcell *= .97; // fade while (newcell > 255) { newcell -= 255; } // newcell += 5; // what is this rule /* newcell += 1-(abs((signed int)(i-y))/(gridrows/7)); newcell += 1-(abs((signed int)(j-z))/(gridcols/7)); */ /* newcell -= dnarun[z+1][y]>>4; newcell -= dnarun[z+1][y+1]>>4; newcell -= dnarun[z][y]>>4; newcell -= dnarun[z][y+1]>>4; newcell += dnarun[gridlastx][gridlasty]>>4; newcell += dnarun[0][0]>>4; newcell += dnarun[0][gridlasty]>>4; newcell += dnarun[gridlastx][0]>>4; newcell += dnarun[gridcolsminusz2][y2]>>4; newcell -= dnarun[z2][y2]>>4; newcell += dnarun[gridcolsminusz2][gridrowsminusy2]>>4; newcell -= dnarun[z2][gridrowsminusy2]>>4; */ // wilder if you use modulos not divides. but you can seek homeostasis instead, using the above code if you want // ... then the temperature changes in jumps as cell values enter // certain ranges... /64 means the granularity is only four, though. // newcell should be a float, then it would be better. what i want // with the %4 shit below is to get them to carefully tune the // values of hotspot neighbourhoods, cooperatively... eventually. // best way to hold a temperature is to hold a cell's value still // if possible then and if it jumps it should be by 4 // i can't decide which way is better yet // newcell += (-3)*(abs((signed int)(i-y))/(gridrows/5)); // newcell += (-3)*(abs((signed int)(j-z))/(gridcols/5)); // ^ five habitable bands, one really cold // newcell -= 2*(abs((signed int)(i-y))/(y2)); newcell -= 2*(abs((signed int)(j-z))/(z2)); // ^ three habitable bands out of a 4x4 grid... and faster math // if you modulo these by y2/z2 or some other value rather than // divide, you get a diamond grid with hot and coldspots // distributed across the neighbourhoods... kind of cool // newcell -= (abs((signed int)(i-y))/(y3)); // newcell -= (abs((signed int)(j-z))/(z3)); // ^ yet more bands, 8x8 grid, real nice but looks like goatse // newcell += 1; // then warming for the corners that always reboot newcell -= dnarun[(z)+1][(y)]%4; // far corners newcell -= dnarun[(z)+1][(y)+1]%4; newcell -= dnarun[(z)][(y)]%4; newcell -= dnarun[(z)][(y)+1]%4; newcell += dnarun[gridlastx][gridlasty]%4; // center newcell += dnarun[0][0]%4; newcell += dnarun[0][gridlasty]%4; newcell += dnarun[gridlastx][0]%4; newcell += dnarun[gridcolsminusz2][y2]%4; // middle corners newcell -= dnarun[z2][y2]%4; newcell += dnarun[gridcolsminusz2][gridrowsminusy2]%4; newcell -= dnarun[z2][gridrowsminusy2]%4; // end if (i == 0) { up = gridlasty; } else { up = i-1; } if (i == gridlasty) { down = 0; } else { down = i+1; } if (j == 0) { left = gridlastx; } else { left = j-1; } if (j == gridlastx) { right = 0; } else { right = j+1; } // if (dnarun[left][up] < newcell) { newcell--; } else { newcell++; } // if (dnarun[left][i] < newcell) { newcell--; } else { newcell++; } // if (dnarun[left][down] < newcell) { newcell--; } else { newcell++; } // if (dnarun[right][up] < newcell) { newcell--; } else { newcell++; } // if (dnarun[right][i] < newcell) { newcell--; } else { newcell++; } // if (dnarun[right][down] < newcell) { newcell--; } else { newcell++; } // if (dnarun[j][up] < newcell) { newcell--; } else { newcell++; } // if (dnarun[j][down] < newcell) { newcell--; } else { newcell++; } // get wind then int mod = 0; if (dnarun[left][up] < newcell) { mod--; } else { mod++; } if (dnarun[left][i] < newcell) { mod--; } else { mod++; } if (dnarun[left][down] < newcell) { mod--; } else { mod++; } if (dnarun[right][up] < newcell) { mod--; } else { mod++; } if (dnarun[right][i] < newcell) { mod--; } else { mod++; } if (dnarun[right][down] < newcell) { mod--; } else { mod++; } if (dnarun[j][up] < newcell) { mod--; } else { mod++; } if (dnarun[j][down] < newcell) { mod--; } else { mod++; } newcell += mod; if (newcell > 255) { newcell = newcell % 255; } else if (newcell < 0) { // oops but cool // newcell = 255; newcell = 0; } } else {} // if CA off tgrid[j][i] = newcell; } } } } lowgeninpop = highgen; // eh for (i = 0; i < gridrows; i++) { for (j = 0; j < gridcols; j++) { grid[j][i] = tgrid[j][i]; } } if (highgen > highestgen) { highestgen = highgen; } avggen = avggen / (float) popsize; // whats wrong with this t++; if (t == drawevery) { if (view == 1) { viewdata1 = lowgen; viewdata2 = highgen; viewdata3 = &generations; viewdata4 = 0; } else if (view == 2) { viewdata1 = 0; viewdata2 = 96; viewdata3 = 0; viewdata4 = &skips; } else if (view == 3) { viewdata1 = 0; viewdata2 = sexoperandpersistance*5; viewdata3 = 0; viewdata4=&sexctr; } else if (view == 4) { viewdata1 = 0; viewdata2 = DNA_Length; viewdata3 = &DNA_IP; viewdata4=0; } else if (view >= 5 && view <= 9) { viewdata1 = 0; viewdata2 = 8+(view-5); viewdata4 = &actions_view; viewdata3=0; } else if (view == 0) { viewdata1 = 0; viewdata2 = 0; viewdata3 = 0; viewdata4=0; } drawgrid(screen, DNA, *grid, gridrows, gridcols, cellwidth, cellheight, xspace, yspace, screenwidth, screenheight, DNA_View_Cell_Size_Divisor, DNA_Length, view, viewdata1, viewdata2, viewdata3, viewdata4); t=0; tt++; if (tt == drawsbetweenscoreoutput) { printf("in world high score %i, highest was %i, lowest is %i, average %f ", highgen, highestgen, lowgen, avggen); if (view == 1) {printf ("(generation view)\n");} else if (view == 2) {printf ("(stunned view)\n");} else if (view == 3) {printf ("(breed mood view)\n");} else if (view == 4) {printf ("(DNA IP view)\n"); } else if (view == 5) {printf ("(Gives view)\n");} else if (view == 6) {printf("(Bites view)\n");} else if (view == 7) {printf("(Pokes view)\n");} else if (view == 8) {printf("(Fights view)\n");} else if (view == 9) {printf("(NOP view)\n");} else {printf("\n");} printf("%i gives, %i pokes, %i skips, %i bites, %i nops %i max recursions\n%i lost fights, %i won fights, %i kills, %i breeds, %i splits. max IP %i\n", gives, pokes, skipsctr, bites, nops, maxrecursions, lostfights, wonfights, kills, breeds, splits, maxIP); gives = 0; pokes = 0; skipsctr = 0; bites = 0; kills = 0; breeds = 0; splits = 0; maxIP = 0; lostfights = 0; wonfights = 0; nops = 0; maxrecursions = 0; tt = 0; } } autosavectr++; if (autosavectr == autosaveevery) { printf("Autosaving\n"); savecrit(highgen, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.best.dna"); savecrit(avggen, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.average.dna"); savecrit(lowgen+1, DNA_Length, popsize, DNA, &DNA_IP, &generations, "ca-ga.low.dna"); // save lowest generation critter too they get generations necrophiling autosavectr = 0; } cycles++; if (cycles == exitafter) { return; } } printf("Quiting SDL.\n"); /* Shutdown all subsystems */ SDL_Quit(); printf("Quiting....\n"); exit(0); }