#include #include #include #include #include #include #include #define Acc 2 #define Acd -1 #define Adc 4 #define Add 0 #define ThKill 2 #define ThSpawn 4 #define MutationRate 0.01 extern double drand48(); XtAppContext app_con; Widget app_sh, draw, StartButton, StopButton; Boolean Running = False; typedef struct { short mag, size, n_play; } ApplicationData, *ApplicationDataPtr; ApplicationData AppData; String fallback_resources[] = { "*FontList: *-helvetica-bold-r-*-140-75-*", "*background: grey90", "*.Quit.accelerator: Altq", "*.Quit.acceleratorText: Alt+Q", NULL }; XrmOptionDescRec options[] = { {"-mag","*nMag",XrmoptionSepArg,NULL}, {"-size","*nSize",XrmoptionSepArg,NULL}, {"-nplay","*nNPlay",XrmoptionSepArg,NULL} }; #define N_OPTIONS 3 XtResource resources[] = { {"nMag","NMag",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,mag),XtRImmediate,(XtPointer)4}, {"nSize","NSIZE",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,size),XtRImmediate,(XtPointer)100}, {"nNPlay","NNPlay",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,n_play),XtRImmediate,(XtPointer)10}, }; typedef struct { int score; char gene, action; short state, n, c[4]; } Cell; Cell *field; Display *dpy = NULL; GC gc; Window win; Pixmap pmap; unsigned short size; unsigned long Step = 0; int ViewMode = 0; void redisplay(); #define MaxColors 7 Pixel black, white, StateColor[MaxColors]; char *ColorNames[] = { "white", /* Others */ "blue", /* ALL C */ "red", /* ALL D */ "green", /* TFT */ "magenta", /* Hesomagari */ "yellow", /* S & H */ "orange", /* H & S */ NULL }; #define action(f) ((f)? 'C':'D') char SpcC[] = { 0x5f, 0x0 }, SpcD[] = { 0x40, 0x0 }, SpcS[] = { 0x50, 0x58, 0x5c, 0x5e, 0x0 }, SpcH[] = { 0x41, 0x43, 0x47, 0x4f, 0x0 }, SpcSH[] = { 0x51, 0x53, 0x57, 0x59, 0x5b, 0x5d, 0x0 }, SpcHS[] = { 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4e, 0x0 }; char *Species[] = { SpcC, SpcD, SpcS, SpcH, SpcSH, SpcHS, NULL }; char SpcTable[32]; void reset() { int f, t, i, j; Cell *p; Step = 0; memset(field,0,AppData.size*AppData.size*sizeof(Cell)); f = AppData.size / 4; t = AppData.size * 3 / 4; for (i = f; i < t ; i ++) for (j = f; j < t; j ++) if (lrand48() & 1) { p = &field[i * AppData.size + j]; p->gene = lrand48() & 0x3f; p->action = action(p->gene & 0x20); } redisplay(); } void setup_draw_info() { int i; char **s, *p; XColor scol, ecol; dpy = XtDisplay(app_sh); gc = DefaultGC(dpy,0); win = XtWindow(draw); pmap = XCreatePixmap(dpy,win,size,size,DefaultDepth(dpy,0)); black = BlackPixel(dpy,0); white = WhitePixel(dpy,0); for (i = 0; i < MaxColors; i ++) { XAllocNamedColor(dpy,DefaultColormap(dpy,0), ColorNames[i],&scol,&ecol); StateColor[i] = scol.pixel; } memset(SpcTable,0,sizeof(SpcTable)); for (i = 1, s = Species; *s; s ++, i ++) for (p = *s; *p; p ++) SpcTable[*p & 0x1f] = i; } void redisplay() { int i, j, v; Cell *p; XSetForeground(dpy,gc,black); XFillRectangle(dpy,pmap,gc,0,0,size,size); for (p = field, i = 0; i < AppData.size; i ++) for (j = 0; j < AppData.size; j ++, p ++) if (p->action) { switch (ViewMode) { case 0: v = SpcTable[p->gene & 0x1f]; break; case 1: v = (p->action == 'D')? 2 : 0; } XSetForeground(dpy,gc,StateColor[v]); if (AppData.mag == 1) XDrawPoint(dpy,pmap,gc,j,i); else XFillRectangle(dpy,pmap,gc, j*AppData.mag,i*AppData.mag,AppData.mag,AppData.mag); } XCopyArea(dpy,pmap,win,gc,0,0,size,size,0,0); } void play(i, j) int i, j; { Cell *p = &field[i], *q = &field[j]; switch (p->action) { case 'C': switch (q->action) { case 'C': p->score += Acc; q->score += Acc; break; case 'D': p->score += Acd; q->score += Adc; } break; case 'D': switch (q->action) { case 'C': p->score += Adc; q->score += Acd; break; case 'D': p->score += Add; q->score += Add; } } } void play_one_game() { int i, j, all = AppData.size * AppData.size; Cell *p; static char mask[] = { 0x10, 0x08, 0x04, 0x02, 0x01 }; for (i = 0; i < AppData.size-1; i ++) for (j = 0; j < AppData.size; j ++) { play(i*AppData.size+j, (i+1)*AppData.size+j); /* up-down */ play(j*AppData.size+i, j*AppData.size+i+1); /* left-right */ } for (i = 0; i < all; i ++) field[i].state = 0; for (p = field, i = 0; i < AppData.size; i ++) for (j = 0; j < AppData.size; j ++, p ++) if (p->action == 'D') { if (j > 0) p[-1].state ++; if (j < AppData.size-1) p[1].state ++; if (i > 0) p[-AppData.size].state ++; if (i < AppData.size-1) p[AppData.size].state ++; } for (p = field, i = 0; i < all; i ++, p++) if (p->action) p->action = action(p->gene & mask[p->state]); Step ++; } void selection() { int i, j, all = AppData.size * AppData.size; int n, k, c[4]; Cell *p; for (p = field, i = 0; i < all; i ++, p++) { if (p->action && p->score < ThKill*AppData.n_play) p->action = 0; if (!p->action) p->n = 0; } for (p = field, i = 0; i < AppData.size; i ++) for (j = 0; j < AppData.size; j ++, p++) if (p->action && p->score > ThSpawn*AppData.n_play) { n = 0; if (j > 0 && !p[-1].action) c[n++] = -1; if (j < AppData.size-1 && !p[1].action) c[n++] = 1; if (i > 0 && !p[-AppData.size].action) c[n++] = -AppData.size; if (i < AppData.size-1 && !p[AppData.size].action) c[n++] = AppData.size; if (n > 0) { k = c[lrand48() % n]; p[k].c[p[k].n++] = -k; } } for (p = field, i = 0; i < all; i ++, p++) if (!p->action && p->n > 0) { k = p->c[lrand48() % p->n]; p[0] = p[k]; for (j = 1; !(j & 0x40); j <<= 1) if (drand48() < MutationRate) p->gene ^= j; p->action = action(p->gene & 0x20); } } Boolean work_one_step(cl) XtPointer cl; { int i; for (i = 0; i < AppData.size*AppData.size; i ++) field[i].score = 0; for (i = 0; i < AppData.n_play; i ++) play_one_game(); selection(); redisplay(); return !Running; } void show_cell(x, y) int x, y; { Cell *p; int m; x /= AppData.mag; y /= AppData.mag; p = &field[y * AppData.size + x]; printf("(%2d,%2d):",x,y); if (p->action) { for (m = 0x20; m; m >>= 1) putchar(action(p->gene & m)); putchar(':'); putchar(p->action); printf(":%d\n",p->score); } else puts("empty"); } void ClickCB(w,cl,cd) Widget w; XtPointer cl,cd; { XmDrawingAreaCallbackStruct *d = (XmDrawingAreaCallbackStruct *)cd; XButtonEvent *e = &(d->event->xbutton); if (e->type != ButtonPress) return; show_cell(e->x, e->y); } void RedrawCB(w,cl,cd) Widget w; XtPointer cl,cd; { XmDrawingAreaCallbackStruct *d = (XmDrawingAreaCallbackStruct *)cd; XExposeEvent *e = &(d->event->xexpose); XCopyArea(dpy,pmap,win,gc,e->x,e->y,e->width,e->height,e->x,e->y); } void ResetCB(w,cl,cd) Widget w; XtPointer cl,cd; { reset(); } void QuitCB(w,cl,cd) Widget w; XtPointer cl,cd; { exit(0);} void StartCB(w,cl,cd) Widget w; XtPointer cl,cd; { Running = True; XtAppAddWorkProc(app_con,work_one_step,NULL); XtVaSetValues(StartButton,XmNsensitive,False,NULL); XtVaSetValues(StopButton,XmNsensitive,True,NULL); } void StopCB(w,cl,cd) Widget w; XtPointer cl,cd; { Running = False; XtVaSetValues(StopButton,XmNsensitive,False,NULL); XtVaSetValues(StartButton,XmNsensitive,True,NULL); } void StepCB(w,cl,cd) Widget w; XtPointer cl,cd; { StopCB(w,cl,cd); XtAppAddWorkProc(app_con,work_one_step,NULL); } void ViewCB(w,cl,cd) Widget w; XtPointer cl,cd; { if (((XmToggleButtonCallbackStruct *)cd)->set) { ViewMode = (int)cl; redisplay(); } } main(argc,argv) int argc; char *argv[]; { Widget main_win, menu_bar, menu, button; Arg args[2]; app_sh = XtAppInitialize(&app_con,"Life Game",options,N_OPTIONS, &argc,argv,fallback_resources,NULL,0); XtGetApplicationResources(app_sh,(XtPointer)&AppData,resources, XtNumber(resources),NULL,0); if (AppData.mag < 1) AppData.mag = 1; if (AppData.size < 20) AppData.size = 20; field = (Cell *)malloc(AppData.size * AppData.size * sizeof(Cell)); if (!field) { perror("malloc"); exit(1); } size = AppData.mag * AppData.size; XtManageChild(main_win=XmCreateMainWindow(app_sh,"main",NULL,0)); XtManageChild(menu_bar=XmCreateMenuBar(main_win,"bar",NULL,0)); menu = XmCreatePulldownMenu(menu_bar,"FileMenu",NULL,0); XtManageChild(button=XmCreatePushButton(menu,"Reset",NULL,0)); XtAddCallback(button,XmNactivateCallback,ResetCB,NULL); XtManageChild(button=XmCreatePushButton(menu,"Quit",NULL,0)); XtAddCallback(button,XmNactivateCallback,QuitCB,NULL); XtSetArg(args[0],XmNsubMenuId,menu); XtManageChild(XmCreateCascadeButton(menu_bar,"File",args,1)); XtManageChild(button=XmCreateCascadeButton(menu_bar,"Step",NULL,0)); XtAddCallback(button,XmNactivateCallback,StepCB,NULL); StartButton = XmCreateCascadeButton(menu_bar,"Start",NULL,0); XtManageChild(StartButton); XtAddCallback(StartButton,XmNactivateCallback,StartCB,NULL); XtSetArg(args[0],XmNsensitive,False); StopButton = XmCreateCascadeButton(menu_bar,"Stop",args,1); XtManageChild(StopButton); XtAddCallback(StopButton,XmNactivateCallback,StopCB,NULL); XtSetArg(args[0],XmNradioBehavior,True); menu = XmCreatePulldownMenu(menu_bar,"ViewMenu",args,1); XtSetArg(args[0],XmNset,True); XtManageChild(button=XmCreateToggleButton(menu,"Species",args,1)); XtAddCallback(button,XmNvalueChangedCallback,ViewCB,(XtPointer)0); XtManageChild(button=XmCreateToggleButton(menu,"Action",NULL,0)); XtAddCallback(button,XmNvalueChangedCallback,ViewCB,(XtPointer)1); XtSetArg(args[0],XmNsubMenuId,menu); XtManageChild(XmCreateCascadeButton(menu_bar,"View",args,1)); XtSetArg(args[0],XmNwidth,size); XtSetArg(args[1],XmNheight,size); XtManageChild(draw=XmCreateDrawingArea(main_win,"field",args,2)); XtRealizeWidget(app_sh); setup_draw_info(); reset(); XtAddCallback(draw,XmNinputCallback,ClickCB,NULL); XtAddCallback(draw,XmNexposeCallback,RedrawCB,NULL); XtAppMainLoop(app_con); }