1 /*-
2 # X-BASED PANEX(tm)
3 #
4 # Panex.c
5 #
6 ###
7 #
8 # Copyright (c) 1996 - 99 David Albert Bagley, bagleyd@tux.org
9 #
10 # All Rights Reserved
11 #
12 # Permission to use, copy, modify, and distribute this software and
13 # its documentation for any purpose and without fee is hereby granted,
14 # provided that the above copyright notice appear in all copies and
15 # that both that copyright notice and this permission notice appear in
16 # supporting documentation, and that the name of the author not be
17 # used in advertising or publicity pertaining to distribution of the
18 # software without specific, written prior permission.
19 #
20 # This program is distributed in the hope that it will be "playable",
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 #
24 */
25
26 /* Methods file for Panex */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef VMS
31 #include <unixlib.h>
32 #else
33 #if HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #endif
37 #include <X11/IntrinsicP.h>
38 #include <X11/Intrinsic.h>
39 #include <X11/StringDefs.h>
40 #include <X11/CoreP.h>
41 #include "PanexP.h"
42
43 #ifndef DATAFILE
44 #define DATAFILE "/usr/games/lib/panex.data"
45 #endif
46
47 static void InitializePanex(Widget request, Widget renew);
48 static void ExposePanex(Widget renew, XEvent * event, Region region);
49 static void ResizePanex(PanexWidget w);
50 static void DestroyPanex(Widget old);
51 static Boolean SetValuesPanex(Widget current, Widget request, Widget renew);
52 static void QuitPanex(PanexWidget w, XEvent * event, char **args, int nArgs);
53 static void SelectPanex(PanexWidget w, XEvent * event, char **args, int nArgs);
54 static void ReleasePanex(PanexWidget w, XEvent * event, char **args, int nArgs);
55 static void ResetPanex(PanexWidget w, XEvent * event, char **args, int nArgs);
56 static void GetPanex(PanexWidget w, XEvent * event, char **args, int nArgs);
57 static void WritePanex(PanexWidget w, XEvent * event, char **args, int nArgs);
58 static void UndoPanex(PanexWidget w, XEvent * event, char **args, int nArgs);
59 static void SolvePanex(PanexWidget w, XEvent * event, char **args, int nArgs);
60 static void IncrementPanex(PanexWidget w, XEvent * event, char **args, int nArgs);
61 static void DecrementPanex(PanexWidget w, XEvent * event, char **args, int nArgs);
62 static void ModePanex(PanexWidget w, XEvent * event, char **args, int nArgs);
63
64 static int SelectTile(PanexWidget w, int x);
65 static void SetAllColors(PanexWidget w, Boolean init);
66 static void GetColor(PanexWidget w, int pyramid, Boolean init);
67 static void CheckTiles(PanexWidget w);
68 static void ResetTiles(PanexWidget w);
69 static int MoveTile(PanexWidget w, int fromStack, int fromPosition, int toStack);
70 static void SlideTile(PanexWidget w, int fromStack, int fromPosition, int toStack, int toPosition);
71 static int RequestMove(PanexWidget w, int fromStack, int fromPosition, int toStack);
72 static void DrawFrame(PanexWidget w, GC gc);
73 static void DrawTile(PanexWidget w, int i, int j, Boolean erase, int offset);
74 static void DrawPyramid(PanexWidget w, int color, int i, int j, int size, int offset);
75
76 #ifdef DEBUG
77 static void PrintStacks(PanexWidget w);
78 static void PrintTiles(PanexWidget w);
79
80 #endif
81
82 static char defaultTranslationsPanex[] =
83 "<KeyPress>q: Quit()\n\
84 Ctrl<KeyPress>C: Quit()\n\
85 <Btn1Down>: Select()\n\
86 <Btn1Up>: Release()\n\
87 <KeyPress>r: Reset()\n\
88 <Btn3Down>(2+): Reset()\n\
89 <KeyPress>g: Get()\n\
90 <KeyPress>w: Write()\n\
91 <KeyPress>u: Undo()\n\
92 <KeyPress>s: Solve()\n\
93 <KeyPress>i: Increment()\n\
94 <KeyPress>d: Decrement()\n\
95 <KeyPress>m: Mode()";
96
97 static XtActionsRec actionsListPanex[] =
98 {
99 {"Quit", (XtActionProc) QuitPanex},
100 {"Select", (XtActionProc) SelectPanex},
101 {"Release", (XtActionProc) ReleasePanex},
102 {"Reset", (XtActionProc) ResetPanex},
103 {"Get", (XtActionProc) GetPanex},
104 {"Write", (XtActionProc) WritePanex},
105 {"Undo", (XtActionProc) UndoPanex},
106 {"Solve", (XtActionProc) SolvePanex},
107 {"Increment", (XtActionProc) IncrementPanex},
108 {"Decrement", (XtActionProc) DecrementPanex},
109 {"Mode", (XtActionProc) ModePanex}
110 };
111
112 static XtResource resourcesPanex[] =
113 {
114 {XtNuserName, XtCUserName, XtRString, sizeof (String),
115 XtOffset(PanexWidget, panex.username), XtRString, "nobody"},
116 {XtNpyramidColor0, XtCLabel, XtRString, sizeof (String),
117 XtOffset(PanexWidget, panex.pyramidName[0]), XtRString, "Blue"},
118 {XtNpyramidColor1, XtCLabel, XtRString, sizeof (String),
119 XtOffset(PanexWidget, panex.pyramidName[1]), XtRString, "Red"},
120 {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
121 XtOffset(PanexWidget, panex.foreground), XtRString, XtDefaultForeground},
122 {XtNtileColor, XtCBackground, XtRPixel, sizeof (Pixel),
123 XtOffset(PanexWidget, panex.tileColor), XtRString, XtDefaultBackground},
124 {XtNtileBorder, XtCForeground, XtRPixel, sizeof (Pixel),
125 XtOffset(PanexWidget, panex.borderColor), XtRString, XtDefaultForeground},
126 {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
127 XtOffset(PanexWidget, core.width), XtRString, "400"},
128 {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
129 XtOffset(PanexWidget, core.height), XtRString, "200"},
130 {XtNtiles, XtCTiles, XtRInt, sizeof (int),
131 XtOffset(PanexWidget, panex.tiles), XtRString, "10"}, /*DEFAULTTILES */
132 {XtNmode, XtCMode, XtRInt, sizeof (int),
133 XtOffset(PanexWidget, panex.mode), XtRString, "1"}, /*DEFAULTMODE */
134 {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
135 XtOffset(PanexWidget, panex.mono), XtRString, "FALSE"},
136 {XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
137 XtOffset(PanexWidget, panex.reverse), XtRString, "FALSE"},
138 {XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
139 XtOffset(PanexWidget, panex.started), XtRString, "TRUE"},
140 {XtNdelay, XtCDelay, XtRInt, sizeof (int),
141 XtOffset(PanexWidget, panex.delay), XtRString, "300"},
142 {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
143 XtOffset(PanexWidget, panex.select), XtRCallback, NULL}
144 };
145
146 PanexClassRec panexClassRec =
147 {
148 {
149 (WidgetClass) & widgetClassRec, /* superclass */
150 "Panex", /* class name */
151 sizeof (PanexRec), /* widget size */
152 NULL, /* class initialize */
153 NULL, /* class part initialize */
154 FALSE, /* class inited */
155 (XtInitProc) InitializePanex, /* initialize */
156 NULL, /* initialize hook */
157 XtInheritRealize, /* realize */
158 actionsListPanex, /* actions */
159 XtNumber(actionsListPanex), /* num actions */
160 resourcesPanex, /* resources */
161 XtNumber(resourcesPanex), /* num resources */
162 NULLQUARK, /* xrm class */
163 TRUE, /* compress motion */
164 TRUE, /* compress exposure */
165 TRUE, /* compress enterleave */
166 TRUE, /* visible interest */
167 (XtWidgetProc) DestroyPanex, /* destroy */
168 (XtWidgetProc) ResizePanex, /* resize */
169 (XtExposeProc) ExposePanex, /* expose */
170 (XtSetValuesFunc) SetValuesPanex, /* set values */
171 NULL, /* set values hook */
172 XtInheritSetValuesAlmost, /* set values almost */
173 NULL, /* get values hook */
174 NULL, /* accept focus */
175 XtVersion, /* version */
176 NULL, /* callback private */
177 defaultTranslationsPanex, /* tm table */
178 NULL, /* query geometry */
179 NULL, /* display accelerator */
180 NULL /* extension */
181 },
182 {
183 0 /* ignore */
184 }
185 };
186
187 WidgetClass panexWidgetClass = (WidgetClass) & panexClassRec;
188
189 static int startPositions[MAXMODES][MAXSTACKS] =
190 {
191 {0, -1, -1},
192 {0, -1, 1}
193 };
194 static int finishPositions[MAXMODES][MAXSTACKS] =
195 {
196 {-1, -1, 0},
197 {1, -1, 0}
198 };
199
200 static XPoint trapazoidUnit[5] =
201 {
202 {0, 0},
203 {1, 1},
204 {-3, 0},
205 {1, -1},
206 {2, 0}
207 };
208
209 #ifndef HAVE_USLEEP
210 #if !defined( VMS ) || defined( XVMSUTILS ) || ( __VMS_VER >= 70000000 )
211 #ifdef USE_XVMSUTILS
212 #include <X11/unix_time.h>
213 #endif
214 #if HAVE_SYS_TIME_H
215 #include <sys/time.h>
216 #else
217 #if HAVE_SYS_SELECT_H
218 #include <sys/select.h>
219 #endif
220 #endif
221 #endif
222 #if defined(SYSV) || defined(SVR4)
223 #ifdef LESS_THAN_AIX3_2
224 #include <sys/poll.h>
225 #else /* !LESS_THAN_AIX3_2 */
226 #include <poll.h>
227 #endif /* !LESS_THAN_AIX3_2 */
228 #endif /* defined(SYSV) || defined(SVR4) */
229
230 static int
usleep(unsigned int usec)231 usleep(unsigned int usec)
232 {
233 #if (defined (SYSV) || defined(SVR4)) && !defined(__hpux)
234 #if defined(HAVE_NANOSLEEP)
235 {
236 struct timespec rqt;
237
238 rqt.tv_nsec = 1000 * (usec % (unsigned int) 1000000);
239 rqt.tv_sec = usec / (unsigned int) 1000000;
240 return nanosleep(&rqt, (struct timespec *) NULL);
241 }
242 #else
243 (void) poll((void *) 0, (int) 0, usec / 1000); /* ms resolution */
244 #endif
245 #else
246 #ifdef VMS
247 long timadr[2];
248
249 if (usec != 0) {
250 timadr[0] = -usec * 10;
251 timadr[1] = -1;
252
253 sys$setimr(4, &timadr, 0, 0, 0);
254 sys$waitfr(4);
255 }
256 #else
257 struct timeval time_out;
258
259 #if 0
260 /* (!defined(AIXV3) && !defined(__hpux)) */
261 extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
262
263 #endif
264
265 time_out.tv_usec = usec % (unsigned int) 1000000;
266 time_out.tv_sec = usec / (unsigned int) 1000000;
267 (void) select(0, (void *) 0, (void *) 0, (void *) 0, &time_out);
268 #endif
269 #endif
270 return 0;
271 }
272 #endif
273
274 static void
Sleep(unsigned int cMilliseconds)275 Sleep(unsigned int cMilliseconds)
276 {
277 (void) usleep(cMilliseconds * 1000);
278 }
279
280 static void
InitializePanex(Widget request,Widget renew)281 InitializePanex(Widget request, Widget renew)
282 {
283 PanexWidget w = (PanexWidget) renew;
284 int stack;
285
286 for (stack = 0; stack < MAXSTACKS; stack++) {
287 w->panex.tileOfPosition[stack] = NULL;
288 w->panex.positionOfTile[stack] = NULL;
289 }
290 CheckTiles(w);
291 InitMoves();
292 ResetTiles(w);
293 w->panex.depth = DefaultDepthOfScreen(XtScreen(w));
294 SetAllColors(w, True);
295 ResizePanex(w);
296 }
297
298 static void
DestroyPanex(Widget old)299 DestroyPanex(Widget old)
300 {
301 PanexWidget w = (PanexWidget) old;
302 int pyramid;
303
304 for (pyramid = 0; pyramid <= w->panex.mode; pyramid++)
305 XtReleaseGC(old, w->panex.pyramidGC[pyramid]);
306 XtReleaseGC(old, w->panex.puzzleGC);
307 XtReleaseGC(old, w->panex.tileGC);
308 XtReleaseGC(old, w->panex.borderGC);
309 XtReleaseGC(old, w->panex.inverseGC);
310 XtRemoveCallbacks(old, XtNselectCallback, w->panex.select);
311 }
312
313 static void
ResizePanex(PanexWidget w)314 ResizePanex(PanexWidget w)
315 {
316 w->panex.delta.x = 8;
317 w->panex.delta.y = 2;
318 w->panex.pos.x = MAX(((int) w->core.width - w->panex.delta.x) /
319 MAXSTACKS, w->panex.delta.x);
320 w->panex.pos.y = MAX(((int) w->core.height - 2 * w->panex.delta.y - 3) /
321 (w->panex.tiles + 1), w->panex.delta.y);
322 w->panex.width = w->panex.pos.x * MAXSTACKS + w->panex.delta.x + 2;
323 w->panex.height = w->panex.pos.y * (w->panex.tiles + 1) +
324 w->panex.delta.y + 3;
325 w->panex.puzzleOffset.x = ((int) w->core.width - w->panex.width + 2) / 2;
326 w->panex.puzzleOffset.y = ((int) w->core.height - w->panex.height + 2) / 2;
327 /* Make the following even */
328 w->panex.tileSize.x = ((w->panex.pos.x - w->panex.delta.x) >> 1) << 1;
329 w->panex.tileSize.y = w->panex.pos.y - w->panex.delta.y;
330 w->panex.letterOffset.x = 3;
331 w->panex.letterOffset.y = 4;
332 }
333
334 static void
ExposePanex(Widget renew,XEvent * event,Region region)335 ExposePanex(Widget renew, XEvent * event, Region region)
336 {
337 PanexWidget w = (PanexWidget) renew;
338
339 if (w->core.visible) {
340 if (w->panex.reverse)
341 XFillRectangle(XtDisplay(w), XtWindow(w),
342 w->panex.inverseGC, 0, 0, w->core.width, w->core.height);
343 DrawFrame(w, w->panex.puzzleGC);
344 DrawAllTiles(w);
345 }
346 }
347
348 static Boolean
SetValuesPanex(Widget current,Widget request,Widget renew)349 SetValuesPanex(Widget current, Widget request, Widget renew)
350 {
351 PanexWidget c = (PanexWidget) current, w = (PanexWidget) renew;
352 Boolean redraw = False;
353 Boolean redrawTiles = False, setColors = False;
354 int pyramid;
355
356 CheckTiles(w);
357 for (pyramid = 0; pyramid <= w->panex.mode; pyramid++) {
358 if (strcmp(w->panex.pyramidName[pyramid], c->panex.pyramidName[pyramid])) {
359 setColors = True;
360 break;
361 }
362 }
363 if (w->core.background_pixel != c->core.background_pixel ||
364 w->panex.foreground != c->panex.foreground ||
365 w->panex.borderColor != c->panex.borderColor ||
366 w->panex.tileColor != c->panex.tileColor ||
367 w->panex.reverse != c->panex.reverse ||
368 w->panex.mono != c->panex.mono ||
369 setColors) {
370 SetAllColors(w, False);
371 redrawTiles = True;
372 }
373 if (w->panex.tiles != c->panex.tiles) {
374 DrawFrame(c, c->panex.inverseGC);
375 ResetTiles(w);
376 ResizePanex(w);
377 redraw = True;
378 } else if (w->panex.mode != c->panex.mode) {
379 ResetTiles(w);
380 redraw = True;
381 } else if (w->panex.puzzleOffset.x != c->panex.puzzleOffset.x ||
382 w->panex.puzzleOffset.y != c->panex.puzzleOffset.y) {
383 DrawFrame(c, c->panex.inverseGC);
384 ResizePanex(w);
385 redraw = True;
386 }
387 if (redrawTiles && !redraw && XtIsRealized(renew) && renew->core.visible) {
388 DrawFrame(c, c->panex.inverseGC);
389 DrawFrame(w, w->panex.puzzleGC);
390 DrawAllTiles(w);
391 }
392 return (redraw);
393 }
394
395 static void
QuitPanex(PanexWidget w,XEvent * event,char ** args,int nArgs)396 QuitPanex(PanexWidget w, XEvent * event, char **args, int nArgs)
397 {
398 XtCloseDisplay(XtDisplay(w));
399 exit(0);
400 }
401
402 static void
SelectPanex(PanexWidget w,XEvent * event,char ** args,int nArgs)403 SelectPanex(PanexWidget w, XEvent * event, char **args, int nArgs)
404 {
405 int stack;
406
407 if (!CheckSolved(w) &&
408 ((stack = SelectTile(w, event->xbutton.x)) >= 0) &&
409 ((w->panex.currentPosition = TopOfStack(w, stack)) >= 0)) {
410 w->panex.currentStack = stack;
411 DrawTile(w, stack, w->panex.currentPosition, False, TRUE);
412 } else
413 w->panex.currentStack = -1;
414 }
415
416 static void
ReleasePanex(PanexWidget w,XEvent * event,char ** args,int nArgs)417 ReleasePanex(PanexWidget w, XEvent * event, char **args, int nArgs)
418 {
419 panexCallbackStruct cb;
420 int toStack, toPosition;
421
422 if (w->panex.currentStack < 0)
423 return;
424 DrawTile(w, w->panex.currentStack, w->panex.currentPosition, True, TRUE);
425 DrawTile(w, w->panex.currentStack, w->panex.currentPosition, False, FALSE);
426 if ((toStack = SelectTile(w, event->xbutton.x)) >= 0 &&
427 toStack != w->panex.currentStack) {
428 if ((toPosition = MovePanex(w,
429 w->panex.currentStack, w->panex.currentPosition, toStack)) >= 0) {
430 if (CheckSolved(w)) {
431 cb.reason = PANEX_SOLVED;
432 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
433 }
434 } else if (toPosition == -1) {
435 cb.reason = PANEX_BLOCKED;
436 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
437 } else {
438 cb.reason = PANEX_ILLEGAL;
439 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
440 }
441 }
442 w->panex.currentStack = -1;
443 }
444
445 static void
ResetPanex(PanexWidget w,XEvent * event,char ** args,int nArgs)446 ResetPanex(PanexWidget w, XEvent * event, char **args, int nArgs)
447 {
448 panexCallbackStruct cb;
449
450 DrawFrame(w, w->panex.inverseGC);
451 ResetTiles(w);
452 DrawFrame(w, w->panex.puzzleGC);
453 DrawAllTiles(w);
454 cb.reason = PANEX_RESET;
455 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
456 }
457
458 static void
GetPanex(PanexWidget w,XEvent * event,char ** args,int nArgs)459 GetPanex(PanexWidget w, XEvent * event, char **args, int nArgs)
460 {
461 FILE *fp;
462 char c;
463 int i, tiles, mode, moves;
464 panexCallbackStruct cb;
465
466 if ((fp = fopen(DATAFILE, "r")) == NULL)
467 (void) printf("Can not read %s for get.\n", DATAFILE);
468 else {
469 FlushMoves(w);
470 while ((c = getc(fp)) != EOF && c != SYMBOL);
471 (void) fscanf(fp, "%d", &mode);
472 if (mode >= HANOI && mode <= PANEX) {
473 if (w->panex.mode != mode) {
474 cb.reason = PANEX_MODE;
475 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
476 }
477 } else
478 (void) printf("%s corrupted: mode %d should be between %d and %d\n",
479 DATAFILE, mode, HANOI, PANEX);
480 while ((c = getc(fp)) != EOF && c != SYMBOL);
481 (void) fscanf(fp, "%d", &tiles);
482 if (tiles >= MINTILES) {
483 for (i = w->panex.tiles; i < tiles; i++) {
484 cb.reason = PANEX_INC;
485 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
486 }
487 for (i = w->panex.tiles; i > tiles; i--) {
488 cb.reason = PANEX_DEC;
489 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
490 }
491 } else
492 (void) printf("%s corrupted: tiles %d should be between %d and MAXINT\n",
493 DATAFILE, tiles, MINTILES);
494 while ((c = getc(fp)) != EOF && c != SYMBOL);
495 (void) fscanf(fp, "%d", &moves);
496 ScanStartPosition(fp, w);
497 cb.reason = PANEX_RESTORE;
498 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
499 SetStartPosition(w);
500 ScanMoves(fp, w, moves);
501 (void) fclose(fp);
502 if (mode == 0)
503 (void) printf("%s: mode hanoi, tiles %d, moves %d.\n",
504 DATAFILE, tiles, moves);
505 else
506 (void) printf("%s: mode panex, tiles %d, moves %d.\n",
507 DATAFILE, tiles, moves);
508 }
509 }
510
511 static void
WritePanex(PanexWidget w,XEvent * event,char ** args,int nArgs)512 WritePanex(PanexWidget w, XEvent * event, char **args, int nArgs)
513 {
514 FILE *fp;
515
516 if ((fp = fopen(DATAFILE, "w")) == NULL)
517 (void) printf("Can not write to %s.\n", DATAFILE);
518 else {
519 (void) fprintf(fp, "mode%c %d\n", SYMBOL, w->panex.mode);
520 (void) fprintf(fp, "tiles%c %d\n", SYMBOL, w->panex.tiles);
521 (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
522 PrintStartPosition(fp, w);
523 PrintMoves(fp);
524 (void) fclose(fp);
525 (void) printf("Saved to %s.\n", DATAFILE);
526 }
527 }
528
529 static void
UndoPanex(PanexWidget w,XEvent * event,char ** args,int nArgs)530 UndoPanex(PanexWidget w, XEvent * event, char **args, int nArgs)
531 {
532 if (MadeMoves()) {
533 panexCallbackStruct cb;
534 int fromStack, fromPosition, toStack;
535
536 GetMove(&toStack, &fromStack);
537 if ((fromPosition = TopOfStack(w, fromStack)) < 0 ||
538 MoveTile(w, fromStack, fromPosition, toStack) < 0)
539 (void) printf(
540 "move from %d to %d can not be made.", fromStack, toStack);
541 else {
542 cb.reason = PANEX_UNDO;
543 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
544 }
545 }
546 }
547
548 static void
SolvePanex(PanexWidget w,XEvent * event,char ** args,int nArgs)549 SolvePanex(PanexWidget w, XEvent * event, char **args, int nArgs)
550 {
551 panexCallbackStruct cb;
552
553 /* Cheat and Reset To Start */
554 DrawFrame(w, w->panex.inverseGC);
555 ResetTiles(w);
556 DrawFrame(w, w->panex.puzzleGC);
557 DrawAllTiles(w);
558 cb.reason = PANEX_RESET;
559 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
560 SolveTiles(w);
561 }
562
563 static void
IncrementPanex(PanexWidget w,XEvent * event,char ** args,int nArgs)564 IncrementPanex(PanexWidget w, XEvent * event, char **args, int nArgs)
565 {
566 panexCallbackStruct cb;
567
568 cb.reason = PANEX_INC;
569 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
570 }
571
572 static void
DecrementPanex(PanexWidget w,XEvent * event,char ** args,int nArgs)573 DecrementPanex(PanexWidget w, XEvent * event, char **args, int nArgs)
574 {
575 panexCallbackStruct cb;
576
577 if (w->panex.tiles <= MINTILES)
578 return;
579 cb.reason = PANEX_DEC;
580 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
581 }
582
583 static void
ModePanex(PanexWidget w,XEvent * event,char ** args,int nArgs)584 ModePanex(PanexWidget w, XEvent * event, char **args, int nArgs)
585 {
586 panexCallbackStruct cb;
587
588 cb.reason = PANEX_MODE;
589 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
590 }
591
592 int
MovePanex(PanexWidget w,int fromStack,int fromPosition,int toStack)593 MovePanex(PanexWidget w, int fromStack, int fromPosition, int toStack)
594 {
595 panexCallbackStruct cb;
596 int toPosition;
597
598 if ((toPosition = MoveTile(w, fromStack, fromPosition, toStack)) >= 0) {
599 cb.reason = PANEX_MOVED;
600 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
601 PutMove(fromStack, toStack);
602 }
603 return toPosition;
604 }
605
606 static int
SelectTile(PanexWidget w,int x)607 SelectTile(PanexWidget w, int x)
608 {
609 int i;
610
611 x -= w->panex.puzzleOffset.x;
612 i = (x - w->panex.delta.x / 2) / w->panex.pos.x;
613 if (i < 0)
614 i = 0;
615 else if (i >= MAXSTACKS)
616 i = MAXSTACKS - 1;
617 /*
618 y -= w->panex.puzzleOffset.y;
619 j = (y - w->panex.delta.y / 2) / w->panex.pos.y;
620 if (j < 0)
621 j = 0;
622 else if (j > w->panex.tiles)
623 j = w->panex.tiles;
624 */
625 return i;
626 }
627
628 static void
SetAllColors(PanexWidget w,Boolean init)629 SetAllColors(PanexWidget w, Boolean init)
630 {
631 XGCValues values;
632 XtGCMask valueMask;
633 int pyramid;
634
635 valueMask = GCForeground | GCBackground;
636 if (w->panex.reverse) {
637 values.background = w->panex.foreground;
638 values.foreground = w->core.background_pixel;
639 } else {
640 values.foreground = w->core.background_pixel;
641 values.background = w->panex.foreground;
642 }
643 if (!init)
644 XtReleaseGC((Widget) w, w->panex.inverseGC);
645 w->panex.inverseGC = XtGetGC((Widget) w, valueMask, &values);
646 values.background = w->core.background_pixel;
647 values.foreground = w->panex.foreground;
648 if (!init)
649 XtReleaseGC((Widget) w, w->panex.puzzleGC);
650 w->panex.puzzleGC = XtGetGC((Widget) w, valueMask, &values);
651 if (w->panex.reverse) {
652 if (w->panex.depth < 2 || w->panex.mono) {
653 values.background = w->panex.foreground;
654 values.foreground = w->core.background_pixel;
655 } else {
656 values.background = w->panex.tileColor;
657 values.foreground = w->panex.borderColor;
658 }
659 } else {
660 if (w->panex.depth < 2 || w->panex.mono) {
661 values.foreground = w->panex.foreground;
662 values.background = w->core.background_pixel;
663 } else {
664 values.foreground = w->panex.tileColor;
665 values.background = w->panex.borderColor;
666 }
667 }
668 if (!init)
669 XtReleaseGC((Widget) w, w->panex.tileGC);
670 w->panex.tileGC = XtGetGC((Widget) w, valueMask, &values);
671 if (w->panex.reverse) {
672 if (w->panex.depth < 2 || w->panex.mono) {
673 values.foreground = w->panex.foreground;
674 values.background = w->core.background_pixel;
675 } else {
676 values.foreground = w->panex.tileColor;
677 values.background = w->panex.borderColor;
678 }
679 } else {
680 if (w->panex.depth < 2 || w->panex.mono) {
681 values.background = w->panex.foreground;
682 values.foreground = w->core.background_pixel;
683 } else {
684 values.background = w->panex.tileColor;
685 values.foreground = w->panex.borderColor;
686 }
687 }
688 if (!init)
689 XtReleaseGC((Widget) w, w->panex.borderGC);
690 w->panex.borderGC = XtGetGC((Widget) w, valueMask, &values);
691 for (pyramid = 0; pyramid <= w->panex.mode; pyramid++)
692 GetColor(w, pyramid, init);
693
694 }
695
696 static void
GetColor(PanexWidget w,int pyramid,Boolean init)697 GetColor(PanexWidget w, int pyramid, Boolean init)
698 {
699 XGCValues values;
700 XtGCMask valueMask;
701 XColor colorCell, rgb;
702
703 valueMask = GCForeground | GCBackground;
704 if (w->panex.reverse) {
705 values.background = w->panex.foreground;
706 } else {
707 values.background = w->core.background_pixel;
708 }
709 if (w->panex.depth > 1 && !w->panex.mono) {
710 if (XAllocNamedColor(XtDisplay(w),
711 DefaultColormap(XtDisplay(w), XtWindow(w)),
712 w->panex.pyramidName[pyramid], &colorCell, &rgb)) {
713 values.foreground = w->panex.pyramidColor[pyramid] = colorCell.pixel;
714 if (!init)
715 XtReleaseGC((Widget) w, w->panex.pyramidGC[pyramid]);
716 w->panex.pyramidGC[pyramid] = XtGetGC((Widget) w, valueMask, &values);
717 return;
718 } else {
719 char buf[121];
720
721 (void) sprintf(buf, "Color name \"%s\" is not defined",
722 w->panex.pyramidName[pyramid]);
723 XtWarning(buf);
724 }
725 }
726 if (w->panex.reverse) {
727 values.background = w->panex.foreground;
728 values.foreground = w->core.background_pixel;
729 } else {
730 values.background = w->core.background_pixel;
731 values.foreground = w->panex.foreground;
732 }
733 if (!init)
734 XtReleaseGC((Widget) w, w->panex.pyramidGC[pyramid]);
735 w->panex.pyramidGC[pyramid] = XtGetGC((Widget) w, valueMask, &values);
736 }
737
738 static void
CheckTiles(PanexWidget w)739 CheckTiles(PanexWidget w)
740 {
741 char buf[121];
742
743 if (w->panex.tiles < 1) {
744 (void) sprintf(buf, "Number of Tiles out of bounds, use 1..MAXINT");
745 XtWarning(buf);
746 w->panex.tiles = DEFAULTTILES;
747 }
748 if (w->panex.mode < HANOI || w->panex.mode > PANEX) {
749 XtWarning("Mode is in error, use 0 for Hanoi, 1 for Panex");
750 w->panex.mode = DEFAULTMODE;
751 }
752 if (w->panex.delay < 0) {
753 (void) sprintf(buf, "Delay out of bounds, use 0..MAXINT");
754 XtWarning(buf);
755 w->panex.delay = -w->panex.delay;
756 }
757 }
758
759 static void
ResetTiles(PanexWidget w)760 ResetTiles(PanexWidget w)
761 {
762 int stack, loc;
763 PanexLoc i;
764
765 w->panex.currentStack = -1;
766 for (stack = 0; stack < MAXMODES; stack++) {
767 if (w->panex.positionOfTile[stack]) {
768 (void) free((void *) w->panex.positionOfTile[stack]);
769 w->panex.positionOfTile[stack] = NULL;
770 }
771 if (startLoc[stack]) {
772 (void) free((void *) startLoc[stack]);
773 startLoc[stack] = NULL;
774 }
775 }
776 for (stack = 0; stack <= w->panex.mode; stack++) {
777 if (!(w->panex.positionOfTile[stack] = (PanexLoc *)
778 malloc(sizeof (PanexLoc) * w->panex.tiles)))
779 XtError("Not enough memory, exiting.");
780 if (!(startLoc[stack] = (PanexLoc *)
781 malloc(sizeof (PanexLoc) * w->panex.tiles)))
782 XtError("Not enough memory, exiting.");
783 }
784 for (stack = 0; stack < MAXSTACKS; stack++) {
785 if (w->panex.tileOfPosition[stack])
786 (void) free((void *) w->panex.tileOfPosition[stack]);
787 if (!(w->panex.tileOfPosition[stack] = (PanexLoc *)
788 malloc(sizeof (PanexLoc) * (w->panex.tiles + 1))))
789 XtError("Not enough memory, exiting.");
790 }
791 for (stack = 0; stack <= w->panex.mode; stack++) {
792 i.stack = 2 * stack;
793 for (loc = 0; loc < w->panex.tiles; loc++) {
794 i.loc = loc + 1;
795 w->panex.positionOfTile[stack][loc] = i;
796 }
797 }
798 for (stack = 0; stack < MAXSTACKS; stack++) {
799 i.stack = -1;
800 i.loc = -1;
801 w->panex.tileOfPosition[stack][0] = i;
802 if ((i.stack = startPositions[w->panex.mode][stack]) >= 0)
803 for (loc = 1; loc <= w->panex.tiles; loc++) {
804 i.loc = loc - 1;
805 w->panex.tileOfPosition[stack][loc] = i;
806 } else
807 for (loc = 1; loc <= w->panex.tiles; loc++)
808 w->panex.tileOfPosition[stack][loc] = i;
809 }
810 FlushMoves(w);
811 w->panex.started = False;
812 }
813
814 int
TopOfStack(PanexWidget w,int stack)815 TopOfStack(PanexWidget w, int stack)
816 {
817 int i;
818
819 for (i = 0; i <= w->panex.tiles; i++)
820 if (w->panex.tileOfPosition[stack][i].stack >= 0)
821 return i;
822 return -1;
823 }
824
825 static int
RequestMove(PanexWidget w,int fromStack,int fromPosition,int toStack)826 RequestMove(PanexWidget w, int fromStack, int fromPosition, int toStack)
827 {
828 int i;
829
830 /* Do not have to check above stack since it is the top one */
831 if (toStack > fromStack)
832 for (i = fromStack + 1; i <= toStack; i++) {
833 if (w->panex.tileOfPosition[i][0].stack >= 0)
834 return (-1);
835 } else /* Already ruled out toStack == fromStack */
836 for (i = fromStack - 1; i >= toStack; i--) {
837 if (w->panex.tileOfPosition[i][0].stack >= 0)
838 return (-1);
839 }
840 i = TopOfStack(w, toStack);
841 i = (i == -1) ? w->panex.tiles : i - 1;
842 if (w->panex.mode == HANOI) {
843 if (i == w->panex.tiles || w->panex.tileOfPosition[toStack][i + 1].loc >
844 w->panex.tileOfPosition[fromStack][fromPosition].loc)
845 return i;
846 else
847 return -2;
848 } else {
849 if (i > w->panex.tileOfPosition[fromStack][fromPosition].loc + 1)
850 return (w->panex.tileOfPosition[fromStack][fromPosition].loc + 1);
851 else
852 return i;
853 }
854 }
855
856 static int
MoveTile(PanexWidget w,int fromStack,int fromPosition,int toStack)857 MoveTile(PanexWidget w, int fromStack, int fromPosition, int toStack)
858 {
859 int toPosition;
860
861 if ((toPosition = RequestMove(w, fromStack, fromPosition, toStack)) >= 0)
862 SlideTile(w, fromStack, fromPosition, toStack, toPosition);
863 return toPosition;
864 }
865
866 static void
SlideTile(PanexWidget w,int fromStack,int fromPosition,int toStack,int toPosition)867 SlideTile(PanexWidget w, int fromStack, int fromPosition, int toStack, int toPosition)
868 {
869 PanexLoc top;
870 int currentStack = fromStack, currentPosition = fromPosition;
871 int nextStack = fromStack, nextPosition = fromPosition;
872
873 while (currentPosition > 0) {
874 DrawTile(w, currentStack, currentPosition, True, FALSE);
875 top = w->panex.tileOfPosition[currentStack][currentPosition];
876 nextPosition = currentPosition - 1;
877 w->panex.tileOfPosition[nextStack][nextPosition] = top;
878 w->panex.positionOfTile[top.stack][top.loc].stack = nextStack;
879 w->panex.positionOfTile[top.stack][top.loc].loc = nextPosition;
880 w->panex.tileOfPosition[currentStack][currentPosition].stack = -1;
881 currentPosition = nextPosition;
882 DrawTile(w, currentStack, currentPosition, False, FALSE);
883 XFlush(XtDisplay(w));
884 Sleep((unsigned int) w->panex.delay / (w->panex.tiles + MAXSTACKS - 1));
885 }
886 while (currentStack != toStack) {
887 DrawTile(w, currentStack, currentPosition, True, FALSE);
888 top = w->panex.tileOfPosition[currentStack][currentPosition];
889 nextStack = (currentStack < toStack) ? currentStack + 1 :
890 currentStack - 1;
891 w->panex.tileOfPosition[nextStack][nextPosition] = top;
892 w->panex.positionOfTile[top.stack][top.loc].stack = nextStack;
893 w->panex.positionOfTile[top.stack][top.loc].loc = nextPosition;
894 w->panex.tileOfPosition[currentStack][currentPosition].stack = -1;
895 currentStack = nextStack;
896 DrawTile(w, currentStack, currentPosition, False, FALSE);
897 XFlush(XtDisplay(w));
898 Sleep((unsigned int) w->panex.delay / (w->panex.tiles + MAXSTACKS - 1));
899 }
900 while (currentPosition < toPosition) {
901 DrawTile(w, currentStack, currentPosition, True, FALSE);
902 top = w->panex.tileOfPosition[currentStack][currentPosition];
903 nextPosition = currentPosition + 1;
904 w->panex.tileOfPosition[nextStack][nextPosition] = top;
905 w->panex.positionOfTile[top.stack][top.loc].stack = nextStack;
906 w->panex.positionOfTile[top.stack][top.loc].loc = nextPosition;
907 w->panex.tileOfPosition[currentStack][currentPosition].stack = -1;
908 currentPosition = nextPosition;
909 DrawTile(w, currentStack, currentPosition, False, FALSE);
910 XFlush(XtDisplay(w));
911 Sleep((unsigned int) w->panex.delay / (w->panex.tiles + MAXSTACKS - 1));
912 }
913 }
914
915 static void
DrawFrame(PanexWidget w,GC gc)916 DrawFrame(PanexWidget w, GC gc)
917 {
918 int i, dx, dy, x, y;
919
920 x = MAXSTACKS * w->panex.pos.x + w->panex.delta.x - 1;
921 dx = w->panex.tileSize.x / 3 + w->panex.delta.x + w->panex.puzzleOffset.x;
922 y = (w->panex.tiles + 1) * w->panex.pos.y + w->panex.delta.y;
923 dy = w->panex.delta.y / 2 + w->panex.puzzleOffset.y + w->panex.tileSize.y / 3;
924 if (gc == w->panex.inverseGC) {
925 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
926 w->panex.puzzleOffset.x, w->panex.puzzleOffset.y, x, y + 1);
927 return;
928 }
929 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
930 w->panex.puzzleOffset.x, w->panex.puzzleOffset.y, x, 1);
931 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
932 w->panex.puzzleOffset.x, y + w->panex.puzzleOffset.y, x, 1);
933 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
934 w->panex.puzzleOffset.x, w->panex.puzzleOffset.y, 1, y);
935 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
936 x + w->panex.puzzleOffset.x, w->panex.puzzleOffset.y, 1, y + 1);
937 XFillRectangle(XtDisplay(w), XtWindow(w), gc, dx, dy,
938 w->panex.tileSize.x / 3 + (MAXSTACKS - 1) * w->panex.pos.x,
939 w->panex.tileSize.y / 3);
940 for (i = 0; i < MAXSTACKS; i++) {
941 XFillRectangle(XtDisplay(w), XtWindow(w), gc, dx, dy,
942 w->panex.tileSize.x / 3, y - 1 - 2 * w->panex.tileSize.y / 3);
943 dx += w->panex.pos.x;
944 }
945 }
946
947 void
DrawAllTiles(PanexWidget w)948 DrawAllTiles(PanexWidget w)
949 {
950 int i, j;
951
952 for (i = 0; i < MAXSTACKS; i++)
953 for (j = 0; j <= w->panex.tiles; j++)
954 if (w->panex.tileOfPosition[i][j].stack >= 0)
955 DrawTile(w, i, j, False, FALSE);
956 }
957
958 static void
DrawTile(PanexWidget w,int i,int j,Boolean erase,int offset)959 DrawTile(PanexWidget w, int i, int j, Boolean erase, int offset)
960 {
961 int dx, dy;
962 GC tileGC, borderGC;
963
964 if (erase) {
965 tileGC = w->panex.inverseGC;
966 borderGC = w->panex.inverseGC;
967 } else if (offset) {
968 tileGC = w->panex.borderGC;
969 borderGC = w->panex.tileGC;
970 } else {
971 tileGC = w->panex.tileGC;
972 borderGC = w->panex.borderGC;
973 }
974 dx = i * w->panex.pos.x + w->panex.delta.x + w->panex.puzzleOffset.x;
975 dy = j * w->panex.pos.y + w->panex.delta.y + w->panex.puzzleOffset.y;
976 if (!erase) {
977 dx += offset;
978 dy += offset;
979 XFillRectangle(XtDisplay(w), XtWindow(w), tileGC,
980 dx, dy, w->panex.tileSize.x, w->panex.tileSize.y);
981 XDrawRectangle(XtDisplay(w), XtWindow(w), borderGC,
982 dx, dy, w->panex.tileSize.x, w->panex.tileSize.y);
983 DrawPyramid(w,
984 w->panex.tileOfPosition[i][j].stack, i, j,
985 w->panex.tileOfPosition[i][j].loc, offset);
986 } else { /* Draw Slots */
987 XFillRectangle(XtDisplay(w), XtWindow(w), tileGC,
988 dx + offset, dy + offset, w->panex.tileSize.x + 1, w->panex.tileSize.y + 1);
989 if (j == 0) {
990 if (i == 0) {
991 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
992 dx + w->panex.tileSize.x / 3, dy + w->panex.tileSize.y / 3 - 1,
993 w->panex.tileSize.x / 3, 2 * w->panex.tileSize.y / 3 + 3 + offset);
994 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
995 dx + w->panex.tileSize.x / 3 + offset, dy + w->panex.tileSize.y / 3 - 1,
996 2 * w->panex.tileSize.x / 3 + 2, w->panex.tileSize.y / 3);
997 } else if (i == MAXSTACKS - 1) {
998 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
999 dx + w->panex.tileSize.x / 3, dy + w->panex.tileSize.y / 3 - 1,
1000 w->panex.tileSize.x / 3, 2 * w->panex.tileSize.y / 3 + 3 + offset);
1001 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
1002 dx + offset, dy + w->panex.tileSize.y / 3 - 1,
1003 2 * w->panex.tileSize.x / 3 - 1, w->panex.tileSize.y / 3 + offset);
1004 } else {
1005 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
1006 dx + w->panex.tileSize.x / 3, dy + w->panex.tileSize.y / 3 - 1,
1007 w->panex.tileSize.x / 3, 2 * w->panex.tileSize.y / 3 + 3 + offset);
1008 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
1009 dx + offset, dy + w->panex.tileSize.y / 3 - 1,
1010 w->panex.tileSize.x + 1, w->panex.tileSize.y / 3);
1011 }
1012 } else if (j == w->panex.tiles)
1013 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
1014 dx + w->panex.tileSize.x / 3, dy,
1015 w->panex.tileSize.x / 3, 2 * w->panex.tileSize.y / 3 + 2);
1016 else
1017 XFillRectangle(XtDisplay(w), XtWindow(w), w->panex.puzzleGC,
1018 dx + w->panex.tileSize.x / 3, dy,
1019 w->panex.tileSize.x / 3, w->panex.tileSize.y + 1 + offset);
1020 }
1021 }
1022
1023 static void
DrawPyramid(PanexWidget w,int color,int i,int j,int size,int offset)1024 DrawPyramid(PanexWidget w, int color, int i, int j, int size, int offset)
1025 {
1026 XPoint trapazoidList[5];
1027 int k;
1028 GC pyramidGC;
1029
1030 for (k = 0; k <= 4; k++) {
1031 if (ABS(trapazoidUnit[k].x) == 3)
1032 trapazoidList[k].x = (size + 1) * SIGN(trapazoidUnit[k].x) *
1033 w->panex.tileSize.x / (w->panex.tiles + 1);
1034 else if (ABS(trapazoidUnit[k].x) == 2)
1035 trapazoidList[k].x = size * SIGN(trapazoidUnit[k].x) *
1036 w->panex.tileSize.x / (w->panex.tiles + 1);
1037 else
1038 trapazoidList[k].x = w->panex.tileSize.x /
1039 (2 * (w->panex.tiles + 1));
1040 trapazoidList[k].y = (w->panex.tileSize.y - 3) * trapazoidUnit[k].y;
1041 }
1042 k = w->panex.delta.x + i * w->panex.pos.x + w->panex.puzzleOffset.x +
1043 w->panex.tileSize.x / 2 + offset + 1;
1044 trapazoidList[0].x = trapazoidList[4].x / 2 + k;
1045 trapazoidList[0].y = j * w->panex.pos.y + w->panex.delta.y +
1046 w->panex.puzzleOffset.y + offset + 2;
1047 if (w->panex.mono || w->panex.depth < 2) {
1048 pyramidGC = (offset) ? w->panex.tileGC : w->panex.borderGC;
1049 } else {
1050 if ((w->panex.pyramidColor[color] == w->panex.borderColor) && offset)
1051 pyramidGC = w->panex.tileGC;
1052 else if ((w->panex.pyramidColor[color] == w->panex.tileColor) && !offset)
1053 pyramidGC = w->panex.borderGC;
1054 else
1055 pyramidGC = w->panex.pyramidGC[color];
1056
1057 }
1058 XFillPolygon(XtDisplay(w), XtWindow(w), pyramidGC,
1059 trapazoidList, 4, Convex, CoordModePrevious);
1060 if (w->panex.mono || w->panex.depth < 2) {
1061
1062 char buf[2];
1063
1064 (void) sprintf(buf, "%c", w->panex.pyramidName[color][0]);
1065 XDrawString(XtDisplay(w), XtWindow(w),
1066 (offset) ? w->panex.borderGC : w->panex.tileGC,
1067 k - w->panex.letterOffset.x, trapazoidList[0].y +
1068 w->panex.tileSize.y / 2 + w->panex.letterOffset.y, buf, 1);
1069 }
1070 }
1071
1072 #if 0
1073 /* Only applies to Panex */
1074 static int middlePositions[MAXSTACKS] =
1075 {-1, 0, 1};
1076
1077 Boolean
1078 CheckMiddle(PanexWidget w)
1079 {
1080 int stack, loc;
1081 PanexLoc i;
1082
1083 for (stack = 0; stack < MAXSTACKS; stack++)
1084 if ((i.stack = middlePositions[stack]) >= 0)
1085 for (loc = 1; loc <= w->panex.tiles; loc++) {
1086 i.loc = loc - 1;
1087 if (w->panex.tileOfPosition[stack][loc].stack != i.stack ||
1088 w->panex.tileOfPosition[stack][loc].loc != i.loc)
1089 return False;
1090 }
1091 return True;
1092 }
1093 #endif
1094
1095 Boolean
CheckSolved(PanexWidget w)1096 CheckSolved(PanexWidget w)
1097 {
1098 int stack, loc;
1099 PanexLoc i;
1100
1101 for (stack = 0; stack < MAXSTACKS; stack++)
1102 if ((i.stack = finishPositions[w->panex.mode][stack]) >= 0)
1103 for (loc = 1; loc <= w->panex.tiles; loc++) {
1104 i.loc = loc - 1;
1105 if (w->panex.tileOfPosition[stack][loc].stack != i.stack ||
1106 w->panex.tileOfPosition[stack][loc].loc != i.loc)
1107 return False;
1108 }
1109 return True;
1110 }
1111
1112 #ifdef DEBUG
1113 void
PrintStacks(PanexWidget w)1114 PrintStacks(PanexWidget w)
1115 {
1116 int stack, position;
1117
1118 (void) printf("top: where are the tiles in the stack\n");
1119 for (position = 0; position <= w->panex.tiles; position++)
1120 for (stack = 0; stack < MAXSTACKS; stack++) {
1121 printf("%d,%d", w->panex.tileOfPosition[stack][position].stack,
1122 w->panex.tileOfPosition[stack][position].loc);
1123 if (stack + 1 == MAXSTACKS)
1124 (void) printf("\n");
1125 else
1126 (void) printf(" | ");
1127 }
1128 }
1129
1130 void
PrintTiles(PanexWidget w)1131 PrintTiles(PanexWidget w)
1132 {
1133 int stack, position;
1134
1135 (void) printf("pot: which stack are the tiles in\n");
1136 for (position = 0; position < w->panex.tiles; position++)
1137 for (stack = 0; stack <= w->panex.mode; stack++) {
1138 printf("%d,%d", w->panex.positionOfTile[stack][position].stack,
1139 w->panex.positionOfTile[stack][position].loc);
1140 if (stack == w->panex.mode)
1141 (void) printf("\n");
1142 else
1143 (void) printf(" | ");
1144 }
1145 }
1146
1147 #endif
1148