#include #include #include #include #include #include XtAppContext app_con; Widget app_sh, draw, StartButton, StopButton; Boolean Running = False; typedef struct { short mag, size; } ApplicationData, *ApplicationDataPtr; ApplicationData AppData; String fallback_resources[] = { "*FontList: *-helvetica-bold-r-*-140-75-*", "*background: grey90", "*.main.width: 484", "*.main.height: 518", "*.Quit.accelerator: Altq", "*.Quit.acceleratorText: Alt+Q", NULL }; XrmOptionDescRec options[] = { {"-mag","*nMag",XrmoptionSepArg,NULL}, {"-size","*nSize",XrmoptionSepArg,NULL} }; #define N_OPTIONS 2 XtResource resources[] = { {"nMag","NMag",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,mag),XtRImmediate,(XtPointer)4}, {"nSize","NSIZE",XmRShort,sizeof(short), XtOffset(ApplicationDataPtr,size),XtRImmediate,(XtPointer)120}, }; char *field, *work; Display *dpy = NULL; GC gc; Window win; Pixmap pmap; unsigned short size; void redisplay(); #define NStates 8 #define MaxColors 8 Pixel black, white, StateColor[MaxColors]; char *ColorNames[] = { "black","red","blue","magenta", "green","yellow","cyan","white" }; char *InitPattern[] = { " 22222222", "2170140142", "2022222202", "272 212", "212 212", "202 212", "272 212", "21222222122222", "207107107111112", " 2222222222222", NULL}; void reset() { int x, i = AppData.size/2; char **p, *q, *r, *s; memset(field,0,AppData.size * AppData.size); s = (char *)field + (AppData.size+1)*AppData.size/2; for (p = InitPattern; *p; p ++, s += AppData.size) for (q = *p, r = s; *q; q ++, r ++) *r = (*q <= '0')? 0 : (*q & 7); /* for (i = 0; i < AppData.size * AppData.size; i ++) field[i] = lrand48() % NStates; memset(field,0,AppData.size * AppData.size); field[(AppData.size+1)*AppData.size/2] = NStates - 1; */ redisplay(); } static char *rule[] = { "00001 2","00006 3","00007 1","00011 2","00012 2","00013 2","00021 2", "00026 2","00027 2","00052 5","00062 2","00072 2","00102 2","00212 5", "00232 2","00522 2","01232 1","01242 1","01252 5","01262 1","01272 1", "01275 1","01422 1","01432 1","01442 1","01472 1","01625 1","01722 1", "01725 5","01752 1","01762 1","01772 1","02527 1", "10001 1","10006 1","10007 7","10011 1","10012 1","10021 1","10024 4", "10027 7","10051 1","10101 1","10111 1","10124 4","10127 7","10202 6", "10212 1","10221 1","10224 4","10226 3","10227 7","10232 7","10242 4", "10262 6","10264 4","10267 7","10272 7","10542 7","11112 1","11122 1", "11124 4","11125 1","11126 1","11127 7","11152 2","11212 1","11222 1", "11224 4","11225 1","11227 7","11232 1","11242 4","11262 1","11272 7", "11322 1","12224 4","12227 7","12243 4","12254 7","12324 4","12327 7", "12425 5","12426 7","12527 5", "20001 2","20002 2","20004 2","20007 1","20012 2","20015 2","20021 2", "20022 2","20023 2","20024 2","20026 2","20027 2","20032 6","20042 3", "20051 7","20052 2","20057 5","20072 2","20102 2","20112 2","20122 2", "20142 2","20172 2","20202 2","20203 2","20205 2","20207 3","20212 2", "20215 2","20221 2","20222 2","20227 2","20232 1","20242 2","20245 2", "20255 2","20262 2","20272 2","20312 2","20321 6","20322 6","20342 2", "20422 2","20512 2","20521 2","20522 2","20552 1","20572 5","20622 2", "20672 2","20712 2","20722 2","20742 2","20772 2","21122 2","21126 1", "21222 2","21224 2","21226 2","21227 2","21422 2","21522 2","21622 2", "21722 2","22227 2","22244 2","22246 2","22276 2","22277 2", "30001 3","30002 2","30004 1","30007 6","30012 3","30042 1","30062 2", "30102 1","30251 1", "40222 1","40232 6","40322 1", "50002 2","50021 5","50022 5","50023 2","50027 2","50202 2","50212 2", "50215 2","50224 4","50272 2","51212 2","51242 2","51272 2", "60001 1","60002 1","61212 5","61213 1","61222 5", "70007 7","70222 1","70225 1","70232 1","70252 5", NULL}; static char Rule[32768]; /* possible condition = 8^5 = 32768 */ static void set_rule(me,e1,e2,e3,e4,next) char me,e1,e2,e3,e4,next; { Rule[((me&7)<<12)|((e1&7)<<9)|((e2&7)<<6)|((e3&7)<<3)|(e4&7)] = next & 7; } void setup_rule_table() { char **p, *q; memset(Rule,0,sizeof(Rule)); for (p = rule; *p; p ++) { q = *p; set_rule(q[0],q[1],q[2],q[3],q[4],q[6]); set_rule(q[0],q[2],q[3],q[4],q[1],q[6]); set_rule(q[0],q[3],q[4],q[1],q[2],q[6]); set_rule(q[0],q[4],q[1],q[2],q[3],q[6]); } } char next_state(me,e1,e2,e3,e4) char me,e1,e2,e3,e4; { return Rule[(me<<12)|(e1<<9)|(e2<<6)|(e3<<3)|e4]; } void setup_draw_info() { int i; 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; } } void redisplay() { int i, j, v; XSetForeground(dpy,gc,black); XFillRectangle(dpy,pmap,gc,0,0,size,size); for (i = 0; i < AppData.size; i ++) for (j = 0; j < AppData.size; j ++) if (v = field[i*AppData.size+j]) { 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); } Boolean work_one_step(cl) XtPointer cl; { int i, j, i_pre, i_post, j_pre, j_post, w; char *p; for (i = 0; i < AppData.size; i ++) { i_pre = (i + AppData.size-1) % AppData.size; i_post = (i + 1) % AppData.size; for (j = 0; j < AppData.size; j ++) { j_pre = (j + AppData.size-1) % AppData.size; j_post = (j + 1) % AppData.size; work[i*AppData.size+j] = next_state( field[i*AppData.size+j], field[i_post*AppData.size+j], field[i*AppData.size+j_pre], field[i_pre*AppData.size+j], field[i*AppData.size+j_post]); } } p = work; work = field; field = p; redisplay(); return !Running; } 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); } 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 = (char *)malloc(AppData.size * AppData.size * 2); if (!field) { perror("malloc"); exit(1); } work = field + AppData.size * AppData.size; size = AppData.mag * AppData.size; XtSetArg(args[0],XmNscrollingPolicy,XmAUTOMATIC); XtManageChild(main_win=XmCreateMainWindow(app_sh,"main",args,1)); 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],XmNwidth,size); XtSetArg(args[1],XmNheight,size); XtManageChild(draw=XmCreateDrawingArea(main_win,"field",args,2)); XtRealizeWidget(app_sh); setup_draw_info(); setup_rule_table(); reset(); XtAddCallback(draw,XmNexposeCallback,RedrawCB,NULL); XtAppMainLoop(app_con); }