/* evolving snails */ /* v0.8 tom #9 */ /* (c) 1993 Timewasters Online Magazine / Koen Holtman */ /* define UNIX or DOS */ #define DOS /* define DOSTEXT for text mode version, DOSVGA for graph mode version, CURSES for unix curses version */ #define DOSVGA #include #include #ifdef UNIX #include #include #include #include #endif #ifdef DOS #define HAVEUSLEEP #include #endif #ifdef DOSVGA #include #define BGIPATH "." /* size of one field element in pixels. */ int blokje=8; #endif #include #include void die(); char *genefile=NULL; char *dea_genefile="genepool"; char *genelog; FILE *logfile; int makelog=1; int seed=-1; int sleeptime=2; int mutafactor=8; int updatefac=1; int musleeptime=0; /* playfield characteristics */ int begindist=10; /* xsize and ysize must be multiples of begindist */ int xsize=80; #ifdef DOSVGA int ysize=60; #else int ysize=30; #endif /* screen dimensions , -1 = set to current terminal size */ int scrxdimen=-1; int scrydimen=-1; const char food='+'; const char visitedfood='*'; const char nofood=' '; #ifdef DOSVGA /* note: the slak bitmap colors are defined elsewhere */ const int foodcol=GREEN; const int visitedfoodcol=LIGHTGREEN; const int nofoodcol=BLACK; const int slakcol=YELLOW; #endif /* gene pool */ #ifdef DOSVGA int poolsize=48; #else int poolsize=24; #endif struct genom { char table[45]; }; struct genom *genepool; struct ranking { int score; int number; }; struct ranking *genescore; /* slak control */ struct slakstate { int emote0; int emote1; int hungercount; int x,y; /* position */ int orient; struct genom* genes; int score; char looks; int playerno; }; int acemote0=1; int acemote1=1; int ackoffie=1; int acMTV=1; int htresh0=4; int htresh1=10; /* round playing stuff */ int months=1; int tijdfactor=3; struct slakstate *players; int *playernumbers; char *playfield; int numplayers,numrow,fieldsize; int day,offset,month; int year=0; /* options */ struct optstruct { int *var; const int minv; const int maxv; const char *swi; const char *meaning; }; #define INF -1 struct optstruct options[]= { { NULL,0,0,NULL,"---Options--- (default in brackets)" }, { NULL,0,0,NULL,"Playfield" }, { &begindist, 1, 256, "d", "Initial distance between snails" }, { &xsize, 1, INF, "x", "X dimension of playfield (must be multiple of -d)" }, { &ysize, 1, INF, "y", "Y dimension of playfield (must be multiple of -d)" }, { &months, 1, INF, "mon", "Number of months in a year" }, { &tijdfactor, 1, INF, "day", "Month has -day * -d * -d days" }, { NULL,0,0,NULL,"Evolution" }, { &poolsize, 3, INF, "g", "Gene pool size" }, { &mutafactor, 1, 100, "ms", "Mutation speed" }, { &seed, 0, INF, "rnd", "Random number seed" }, { NULL,0,0,NULL,"Presentation" }, { &scrxdimen, 1, INF, "sx", "X dimension of screen" }, { &scrydimen, 1, INF, "sy", "Y dimension of screen" }, #ifdef CURSES { &updatefac, 1, INF, "u", "Days between a screen update" }, #endif #ifdef DOSVGA { &blokje , 1, 20, "el", "Size of one field element" }, #endif #ifdef HAVEUSLEEP { &musleeptime, 0, INF, "sle", "1/100 seconds to sleep between screen updates" }, #endif { &sleeptime, 0, 60, "pau", "Seconds to pause between years" }, { &makelog, 0, 1, "log", "Make a .log file" }, { NULL,0,0,NULL,"Snail brain" }, { &acemote0, 0, 1, "e0", "Activate emotion 0" }, { &acemote1, 0, 1, "e1", "Activate emotion 1" }, { &ackoffie, 0, 1, "cof", "Activate coffee" }, { &acMTV, 0, 1, "MTV", "Activate MTV" }, { &htresh0, 0, 1000, "h0", "Hunger treshhold 0" }, { &htresh1, 0, 1000, "h1", "Hunger treshhold 1" }, { NULL, 0, 0, NULL, NULL } }; /************/ /* OS-dependent code starts here */ /* checks if user wants to stop */ #ifdef UNIX /* unix version, checks if user pressed enter. */ int stoppressed() { int stat; fd_set desc; struct timeval wacht; wacht.tv_sec=(long)0; wacht.tv_usec=(long)0; desc=(fd_set){ 1 }; stat=select(1,&desc,0,0,&wacht); return(stat); } #endif #ifdef DOS /* dos version, checks if user pressed key. */ int stoppressed() { return(kbhit()); } #endif /**************/ /* curses version */ #ifdef CURSES /* playfield visualisation (curses) */ void fieldinit() { initscr(); signal(SIGINT,die); if(scrxdimen==-1) scrxdimen=COLS; if(scrydimen==-1) scrydimen=LINES-2; if((LINES=scrxdimen) return; if(y>=scrydimen) return; mvaddch(y,x,c); } void slakupd(int x, int y,char c) { if(x>=scrxdimen) return; if(y>=scrydimen) return; standout(); mvaddch(y,x,c); standend(); } void fieldtitles() { move(scrydimen,0); printw("Year: %d ",year); printw("Month: %d ",month); printw("Offset: %d ",offset); move(scrydimen,40); printw("Day: 00"); } void fielddayupdate() { move(scrydimen,40); printw("Day: %d ",day); } /**************/ /* printing of statistics (curses) */ int staty; void statbegin() { staty=0; } void statprint(char *s) { if (staty>=LINES-4) return; move(staty++,25); printw("%s",s); } void stattotal(char *s) { move(staty+1,25); printw("%s",s); } void statend() { refresh(); } #endif /* curses version */ /* dos textmode version */ #ifdef DOSTEXT #define COLS 80 #define LINES 24 /* playfield visualisation */ void fieldinit() { struct text_info att; if(scrxdimen==-1) scrxdimen=COLS; if(scrydimen==-1) scrydimen=LINES-2; if((LINES=scrxdimen) return; if(y>=scrydimen) return; gotoxy(x+1,y+1); putch(c); } void slakupd(int x, int y,char c) { if(x>=scrxdimen) return; if(y>=scrydimen) return; gotoxy(x+1,y+1); highvideo(); putch(c); normvideo(); } void fieldtitles() { gotoxy(1,scrydimen+1); printf("Year: %d ",year); printf("Month: %d ",month); printf("Offset: %d ",offset); gotoxy(41,scrydimen+1); printf("Day: 00"); } void fielddayupdate() { gotoxy(41,scrydimen+1); printf("Day: %d ",day); } /**************/ /* printing of statistics */ int staty; void statbegin() { staty=0; } void statprint(char *s) { if (staty>=LINES-4) return; gotoxy(25+1,(staty++)+1); printf("%s",s); } void stattotal(char *s) { gotoxy(25+1,staty+1+1); printf("%s",s); } void statend() { } #endif /* dos textmode version */ /*****************************/ /* dos graph mode version */ #ifdef DOSVGA /* playfield visualisation */ int LINES,COLS; void opengraph() { /* request auto detection */ int gdriver = DETECT, gmode, errorcode; /* initialize graphics mode */ initgraph(&gdriver, &gmode, BGIPATH); /* read result of initialization */ errorcode = graphresult(); if (errorcode != grOk) /* an error occurred */ { printf("Graphics error: %s (bgi path=%s)\n", grapherrormsg(errorcode),BGIPATH); printf("Press any key to halt:"); getch(); exit(1); /* return with error code */ } LINES=getmaxy(); COLS=getmaxx(); } void fieldexit() { closegraph(); gotoxy(1,24); } void far *images[8]; char *plaatjes[]={ "..o..o.. .....o..", "...ss... .....s..", "...ss... ...hssso", "..hhhh.. ..hhhs..", "..hhhh.. .hhhhh..", "..hhhh.. .shhh...", "..hhhh.. sssh....", "...ss... .ss.....", }; void makeimages() { int i,x,y,c,imsize; for(x=0; x<8; x++) for(y=0; y<8; y++) { switch(plaatjes[y][x]) { case 'o' : c=WHITE; break; case 's' : c=YELLOW; break; case 'h' : c=LIGHTGRAY; break; default : c=BLACK; break; } putpixel(00+x,y,c); putpixel(16+(7-y),x,c); putpixel(32+x,(7-y),c); putpixel(48+y,x,c); } for(x=0; x<8; x++) for(y=0; y<8; y++) { switch(plaatjes[y][x+9]) { case 'o' : c=WHITE; break; case 's' : c=YELLOW; break; case 'h' : c=LIGHTGRAY; break; default : c=BLACK; break; } putpixel(8+00+x,y,c); putpixel(8+16+x,(7-y),c); putpixel(8+32+y,x,c); putpixel(8+48+y,7-x,c); } for(i=0; i<8; i++) { imsize=imagesize(i*8,0,i*8+7,7); images[i]=(void far *)malloc(imsize); getimage(i*8,0,i*8+7,7,images[i]); } cleardevice(); } void fieldinit() { opengraph(); if(scrxdimen==-1) scrxdimen=COLS/blokje; if(scrydimen==-1) scrydimen=(LINES-10)/blokje; if( (((LINES-10)/blokje)=scrxdimen) return; if(y>=scrydimen) return; if (c==food) col=foodcol; else if (c==visitedfood) col=visitedfoodcol; else col=nofoodcol; if(blokje==1) putpixel(x,y,col); else { x*=blokje; y*=blokje; setfillstyle(SOLID_FILL,col); bar(x,y,x+blokje-1,y+blokje-1); } } void slakupd(int x, int y,int c) { if(x>=scrxdimen) return; if(y>=scrydimen) return; if(blokje==1) putpixel(x,y,slakcol); else if(blokje==8) { x*=blokje; y*=blokje; putimage(x,y,images[(c+6)&7],COPY_PUT); } else { x*=blokje; y*=blokje; setfillstyle(SOLID_FILL,slakcol); bar(x,y,x+blokje-1,y+blokje-1); } } int daypos; void fieldtitles() { char s[81]; sprintf(s,"Year: %d Month: %d Offset: %d",year,month,offset); outtextxy(1,LINES-9,s); outtextxy((COLS/3)*2,LINES-9,"Day:"); daypos=(COLS/3)*2+textwidth("Day: "); } void fielddayupdate() { char s[21]; int w; sprintf(s,"%d ",day); w=textwidth(s); setfillstyle(EMPTY_FILL,BLACK); bar(daypos,LINES-9,daypos+w,LINES-9+textheight(s)); outtextxy(daypos,LINES-9,s); } /**************/ /* printing of statistics */ int staty,statx; void statbegin() { staty=0; statx=COLS/3; } void statprint(char *s) { if (staty>=LINES-14) return; outtextxy(statx,staty,s); staty+=9; } void stattotal(char *s) { outtextxy(statx,staty+14,s); } void statend() { } #endif /* dos graph mode version */ /* OS-dependent code ends here */ /************/ /* initialisation */ void memfull() { fieldexit(); printf("Out of memory!\n"); exit(1); } void initmove(void); void initvars() { /* note: we rely in the OS to free the allocated memory on exit, amiga porters beware! */ genepool=(struct genom *)malloc(sizeof(struct genom)*poolsize); if(genepool==NULL) memfull(); genescore=(struct ranking *)malloc(sizeof(struct ranking)*poolsize); if(genescore==NULL) memfull(); playernumbers=(int *)malloc(sizeof(int)*poolsize); if(playernumbers==NULL) memfull(); numplayers=(xsize/begindist)*(ysize/begindist); numrow=xsize/begindist; players=(struct slakstate *)malloc(sizeof(struct slakstate)*numplayers); if(players==NULL) memfull(); fieldsize=xsize*ysize; playfield=(char *)malloc(sizeof(char)*fieldsize); if(playfield==NULL) memfull(); initmove(); } /**************/ /* gene pool management */ void randompool() { int i,j; for(i=0; i99) val=50; genepool[i].table[j]=(char)(val%100); } fclose(f); } void genewrite(char *fnam) { FILE *f; int i,j; f=fopen(fnam,"w"); if(f==NULL) { fprintf(stderr,"WRITE ERROR!!\n"); sleep(1); return; } for(i=0; iy*xsize+slak->x; /* calculate vision */ view=&seearray[(slak->orient+6)&7]; for(i=0; i<5; i++) { s[i]= ( playfield[(myplace+view[i])%fieldsize] &1); } /* neural net */ g=slak->genes->table; /* calc t */ side=slak->hungercount>=htresh0 ? 1 : 0; for(i=1; i<=3; i++) { a= side ? *g : 50; g++; a+=s[i-1] ? *g : 50; g++; a+=s[i ] ? *g : 50; g++; a+=s[i+1] ? *g : 50; g++; t[i]= a < (*g++)*4 ? 0 : 1; } if(acemote0) t[0]=slak->emote0; else t[0]=0; if(acemote1) t[4]=slak->emote1; else t[4]=0; /* calc u */ side=slak->hungercount>htresh1 ? 1 : 0; for(i=1; i<=3; i++) { a= side ? *g : 50; g++; a+=t[i-1] ? *g : 50; g++; a+=t[i ] ? *g : 50; g++; a+=t[i+1] ? *g : 50; g++; u[i]= a < (*g++)*4 ? 0 : 1; } /* koffie emotie */ if(ackoffie) u[0]=day%30>25 ? 1 : 0; else u[0]=0; /* MTV emotie */ if(acMTV) u[4]=rand()&1; else u[4]=0; /* calc v */ side=(playfield[myplace]&1) ? 1 : 0; for(i=1; i<=3; i++) { a= side ? *g : 50; g++; a+=u[i-1] ? *g : 50; g++; a+=u[i ] ? *g : 50; g++; a+=u[i+1] ? *g : 50; g++; v[i]= a < (*g++)*4 ? 0 : 1; } slak->emote0=v[2]; slak->emote1=u[1]; slak->hungercount++; /* do not uncomment unless you're running the curses version */ /* if(slak->looks=='A') { move(scrydimen,8); printw("s %d %d %d %d %d ",s[0],s[1],s[2],s[3],s[4]); printw("t %d %d %d %d %d ",t[0],t[1],t[2],t[3],t[4]); printw("u %d %d %d %d %d ",u[0],u[1],u[2],u[3],u[4]); printw("v %d %d %d ",v[1],v[2],v[3]); } */ /* perform command */ if(v[1]) slak->orient=(slak->orient+1)&7; if(v[3]) slak->orient=(slak->orient+7)&7; if(v[2]==0) { /* eat */ if(playfield[myplace]==1) { slak->score++; slak->hungercount=0; } playfield[myplace]=0; return; } /* move */ dx=movetab[slak->orient][0]; dy=movetab[slak->orient][1]; fieldupd(slak->x,slak->y, playfield[myplace]==0 ? nofood : visitedfood ); if(dx) slak->x=(slak->x+dx+xsize)%xsize; if(dy) slak->y=(slak->y+dy+ysize)%ysize; #ifdef DOSVGA slakupd(slak->x,slak->y,slak->orient); #else slakupd(slak->x,slak->y,slak->looks); #endif } /**************/ /* playing a round */ void setupround() { int i,n; for(i=0; iscore - ((struct ranking*)a)->score ); } void procreate() { int i,lastones,third,s,d; qsort(genescore,poolsize,sizeof(struct ranking),&rankcompare); third=poolsize/3; lastones=poolsize-third; printscores(third,lastones); for(i=0; imeaning!=NULL; o++) if(o->var!=NULL) { printf(" -%-3s : %s",o->swi,o->meaning); if(*(o->var)==-1) printf(".\n"); else printf(" (%d).\n",*(o->var)); } else printf("%s\n",o->meaning); printf(" -h or -? for help\n"); } void oneoption(char *opt) { struct optstruct *o,*p; int val; char *vs; p=NULL; for(o=options; o->meaning!=NULL; o++) if(o->var!=NULL) if(strncmp(&opt[1],o->swi,strlen(o->swi))==0) p=o; if(p==NULL) { fprintf(stderr," Unknown option %s\n",opt); exit(1); } vs=opt+1+strlen(p->swi); if(sscanf(vs,"%d",&val)!=1) { if(vs[0]=='\0') fprintf(stderr," Option %s: need an integer\n",p->swi); else fprintf(stderr," Option %s: `%s' is not an integer\n",p->swi,vs); exit(1); } if(valminv) { fprintf(stderr," Value too low in option %s\n",opt); exit(1); } if(p->maxv!=INF) if(val>p->maxv) { fprintf(stderr," Value too high in option %s\n",opt); exit(1); } *(p->var)=val; } void dooptions(int argc, char *argv[]) { int i; for(i=1; i