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