/************************************************* * * The tower of Hanoi, test WorkArea Items. */ #include "EZ.h" #define WWIDTH 640 #define WHEIGHT 420 #define RWIDTH 20 #define RHEIGHT 10 #define DIST 200 #define PWIDTH 6 #define PHEIGHT 300 #define PHEIGHT 300 #define BASE 8 #define BASEY (WHEIGHT - BASE) #define BASEX 90 #define STEPS 32 /********************************************************/ static char *fallbackResources = "\n\ *frame.bgImageFile: guilin.gif\n\ *iWorkArea.highlightPad: 0\n\ "; /********************************************************/ int nrings = 4; int nRs[3]; /* number of rings on pole 0,1,2 */ EZ_Item *Rs[3][16]; /* to hold the rings on pole 0,1,2 */ EZ_Item *items[200]; EZ_Widget *frame, *workarea; int trashed = 0; /* if nrings changes, flag to abort .. */ int stopped = 0; int speed=8000, speedC=1; void moveRing(int from, int to) { if( !trashed && nRs[from] > 0) { int idx = --nRs[from]; /* index of the top ring on 'from' */ int jdx = nRs[to]++; /* index of the next ring on 'to' */ EZ_Item *titem, *item = Rs[from][idx]; /* top ring on 'from' */ int x0 = (1+from) * DIST + PWIDTH; /* x0, x1 are used to */ int x1 = (1+to) * DIST + PWIDTH; /* calc x displacement */ int i, dx, dy, rx, ry; EZ_FigPiece *fpiece = (EZ_FigPiece *)EZ_GetItemPtrData(item); /* the tail, hide it during motion, show when done */ Rs[to][jdx] = item; /* 1. move out from 'from'. Move in the y direction */ ry = (-PHEIGHT); dy = ry/STEPS; ry = ry - dy * STEPS; EZ_FigItemHidePiece(item,fpiece,0); /* hide the tail ! */ for(i = 0; !trashed && i < STEPS+1; i++) { int tt = (i == STEPS)? ry: dy; EZ_WorkAreaScaleItem(workarea, item, 0, 1.0, 1.0, 0, tt, 0); EZ_SitForALittleBit(speed); EZ_ServiceEvents(); } /* 2. move to pole 'to'. Move in the x direction */ rx = (to - from) * DIST; dx = rx / STEPS; rx = rx - STEPS * dx; for(i = 0; !trashed && i < STEPS+1; i++) { int tt = ( i == STEPS)? rx: dx; EZ_WorkAreaScaleItem(workarea, item, 0, 1.0, 1.0, tt, 0, 0); EZ_SitForALittleBit(speed); EZ_ServiceEvents(); } /* 3. and move it to the right place. Move in the y direction */ ry = (PHEIGHT - (jdx - idx) * RHEIGHT); dy = ry/STEPS; ry = ry - STEPS * dy ; for(i = 0; !trashed && i < STEPS+1; i++) { int tt = (i == STEPS)? ry: dy; EZ_WorkAreaScaleItem(workarea, item, 0, 1.0, 1.0, 0, tt, 0); EZ_SitForALittleBit(speed); EZ_ServiceEvents(); } if(!trashed) EZ_FigItemShowPiece(item,fpiece, 0); /* show the tail ! */ } } /* The heart of the algorithm */ void hanoiWork(int n, int from, int to, int tmp) { if(trashed == 0 && n >= 0) { /* 1. move n-1 rings from 'from' to 'tmp' */ hanoiWork(n-1, from, tmp, to); /* 2. move the nth ring from 'from' to 'to' */ moveRing(from, to); /* 3. move n-1 rings from 'tmp' to 'to' */ hanoiWork(n-1, tmp, to, from); } } /* make a ring. Each ring is a FIG item with 3 parts: * 1. a golden rectangle, * 2. a black outline of the rectangle and * 3. a blue tail, to create the illusion that the * ring under it is on the pole. */ EZ_Item *makeRing(int n) { GC gc1, gc2; XGCValues gcv; int i, dx; EZ_FigPiece *pole; EZ_Item *item = EZ_CreateItem(EZ_FIG_ITEM, NULL); /* a golden rectangle */ gcv.foreground = EZ_AllocateColorFromName("gold"); gc1 = EZ_GetGC(GCForeground, &gcv); EZ_FigItemAddFilledRectangle(item, gc1,0,0, (n+1)*RWIDTH, RHEIGHT-2); /* a black outline */ gcv.foreground = EZ_AllocateColorFromName("black"); gc2 = EZ_GetGC(GCForeground, &gcv); EZ_FigItemAddRectangle(item, gc2,0,0, (n+1)*RWIDTH, RHEIGHT-2); /* and a blue tail */ gcv.foreground = EZ_AllocateColorFromName("blue"); gc2 = EZ_GetGC(GCForeground, &gcv); pole = EZ_FigItemAddFilledRectangle(item, gc2, (n+1)*RWIDTH/2 -2, RHEIGHT-2, 6, RHEIGHT/2); EZ_SetItemPtrData(item, pole); /* remember the last piece */ return(item); } /****************************************************************/ int setup() { int i, cnt,dy; GC gc; XPoint xpoints[10]; XGCValues gcvalues; gcvalues.foreground = EZ_AllocateColorFromName("blue"); gcvalues.line_width = 0; gc = EZ_GetGC(GCForeground|GCLineWidth, &gcvalues); /* base */ xpoints[0].x = 0; xpoints[0].y = 0; xpoints[1].x = 760; xpoints[1].y = 0; items[0] = EZ_CreateItem(EZ_FIG_ITEM, EZ_X, 0, EZ_Y, BASEY, NULL); EZ_FigItemAddFilledRectangle(items[0],gc, 0,0, 760, 6); cnt = 1; /* pole 1 */ xpoints[0].x = 0; xpoints[0].y = 0; xpoints[1].x = 0; xpoints[1].y = RHEIGHT/2; for(i= 0; i < 2*PHEIGHT/RHEIGHT; i++) { items[cnt] = EZ_CreateItem(EZ_FIG_ITEM, EZ_X, DIST-BASEX -2, EZ_Y, BASEY-PHEIGHT+i*RHEIGHT/2-3, NULL); EZ_FigItemAddFilledRectangle(items[cnt++],gc, 0,0, RHEIGHT/2, 6); /*EZ_FigItemAddLines(items[cnt++],gc,xpoints, 2, CoordModeOrigin);*/ } /* pole 2 */ for(i= 0; i < 2*PHEIGHT/RHEIGHT; i++) { items[cnt] = EZ_CreateItem(EZ_FIG_ITEM, EZ_X, 2*DIST-BASEX -2, EZ_Y, BASEY-PHEIGHT+i*RHEIGHT/2-3, NULL); EZ_FigItemAddFilledRectangle(items[cnt++],gc, 0,0, RHEIGHT/2, 6); /*EZ_FigItemAddLines(items[cnt++],gc,xpoints, 2, CoordModeOrigin);*/ } /* pole 3 */ for(i= 0; i < 2*PHEIGHT/RHEIGHT; i++) { items[cnt] = EZ_CreateItem(EZ_FIG_ITEM, EZ_X, 3*DIST-BASEX -2, EZ_Y, BASEY-PHEIGHT+i*RHEIGHT/2-3, NULL); EZ_FigItemAddFilledRectangle(items[cnt++],gc, 0,0, RHEIGHT/2, 6); } /* the rings */ for(i=0; i < nrings; i++) { Rs[0][nrings-i-1] = items[cnt+nrings-i-1] = makeRing(i); EZ_ConfigureItem(items[cnt+nrings-i-1], EZ_X, DIST - (i+1) * (RWIDTH/2)-BASEX, EZ_Y, BASEY - (nrings -i) * RHEIGHT, EZ_CLIENT_INT_DATA, (i+1) * RWIDTH/2, /* offset to center */ NULL); } cnt += nrings; nRs[0] = nrings; nRs[1] = nRs[2] = 0; gcvalues.foreground = EZ_AllocateColorFromName("red"); gcvalues.font = EZ_GetFontFromName("-adobe-helvetica-bold-r-normal-*-*-180-*-*-*-*-*-*")->fid; gc = EZ_GetGC(GCForeground|GCFont, &gcvalues); items[cnt] = EZ_CreateItem(EZ_FIG_ITEM, EZ_X, 220, EZ_Y, 35, NULL); EZ_FigItemAddString(items[cnt++], gc, "The Tower of Hanoi", 18,0,0,0); return(cnt); } /********************************************************/ void stopCB(EZ_Widget *widget, void *data) { if(stopped == 0) { stopped = 1; while(stopped) { EZ_WaitAndServiceNextEvent(); } } } /********************************************************/ void runCB(EZ_Widget *widget, void *data) { if(stopped) stopped = 0; else { int cnt; trashed = 0; EZ_WorkAreaClear(workarea); cnt = setup(); EZ_WorkAreaInsertItems(workarea, items, cnt); hanoiWork(nrings, 0, 1, 2); } } /********************************************************/ void nringsCB(EZ_Widget *slider, void *data) { int cnt, n = (int)EZ_GetSliderValue(slider); if( n > 0 && nrings != n) { trashed = 1; EZ_WorkAreaClear(workarea); nrings = n; cnt = setup(); EZ_WorkAreaInsertItems(workarea, items, cnt); } } /********************************************************/ void speedCB(EZ_Widget *slider, void *data) { int n = (int)EZ_GetSliderValue(slider); speed = ((5 - n) * (5 - n) + speedC) * 1000; if(speed < 0) speed = 0; } /********************************************************/ main(int argc, char **argv) { int i, cnt; EZ_InitializeXrm("Hanoi", /* class name */ NULL, /* cmd line options */ 0, /* # of cmd line options */ &argc, /* arg count, in and out */ argv, /* cmd args, in and out */ fallbackResources, /* fallback resources */ 0); /* useless junk */ i = 1; while(i < argc) { if(!strcmp(argv[i], "-s") ) speedC = 0; i++; } if(nrings <= 0) nrings = 5; else if(nrings > 10) nrings = 10; frame = EZ_CreateWidget(EZ_WIDGET_FRAME, NULL, /*EZ_WM_HINTS, PMinSize|PMaxSize,*/ /* so the toplevel won't resize */ EZ_WM_ICON_XPM_FILE, "twotails.xpm", EZ_BG_IMAGE_FILE, "bg.gif", EZ_FILL_MODE, EZ_FILL_BOTH, EZ_ORIENTATION, EZ_VERTICAL, EZ_PADX, 0, EZ_PADY, 0, NULL); workarea = EZ_CreateWidget(EZ_WIDGET_WORK_AREA, frame, EZ_BORDER_WIDTH, 0, EZ_OPTIONAL_HSCROLLBAR, False, EZ_OPTIONAL_VSCROLLBAR, False, EZ_RUBBER_BAND, True, EZ_ITEM_MOVABLE, False, EZ_SIZE, WWIDTH, WHEIGHT, EZ_IPADX, 1, EZ_IPADY, 1, 0); EZ_SetWorkAreaGeometryManager(workarea, NULL, NULL); /* disable the default GM manager */ cnt = setup(); EZ_WorkAreaInsertItems(workarea, items, cnt); /* a few control widgets */ { EZ_Widget *bframe, *sliderR, *sliderS, *stopBtn, *runBtn; bframe = EZ_CreateWidget(EZ_WIDGET_FRAME, frame, EZ_HEIGHT, 0, EZ_FILL_MODE, EZ_FILL_BOTH, NULL); sliderR = EZ_CreateWidget(EZ_WIDGET_HORIZONTAL_SLIDER, bframe, EZ_LABEL_STRING, "N Rings", EZ_SLIDER_RESOLUTION, 1.0, EZ_SLIDER_RANGE, 2.0, 10.0, EZ_SLIDER_INIT_VALUE, 4.0, EZ_CALLBACK, nringsCB, NULL, NULL); runBtn = EZ_CreateWidget(EZ_WIDGET_NORMAL_BUTTON, bframe, EZ_SIZE, 0,0, EZ_LABEL_STRING, "Run", EZ_UNDERLINE, 0, EZ_CALLBACK, runCB, NULL, NULL); stopBtn = EZ_CreateWidget(EZ_WIDGET_NORMAL_BUTTON, bframe, EZ_SIZE, 0,0, EZ_LABEL_STRING, "Stop", EZ_UNDERLINE, 0, EZ_CALLBACK, stopCB, NULL, NULL); sliderS = EZ_CreateWidget(EZ_WIDGET_HORIZONTAL_SLIDER, bframe, EZ_LABEL_STRING, "Speed", EZ_SLIDER_RESOLUTION, 1.0, EZ_SLIDER_RANGE, 0.0, 5.0, EZ_SLIDER_INIT_VALUE, 2.0, EZ_CALLBACK, speedCB, NULL, NULL); } EZ_DisplayWidget(frame); EZ_EventMainLoop(); } /********************************************************/