1 /*-
2 # X-BASED DINOSAUR CUBE
3 #
4 #  Dino.c
5 #
6 ###
7 #
8 #  Copyright (c) 1995 - 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 Dino */
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 "DinoP.h"
42 #include "Dino2dP.h"
43 #include "Dino3dP.h"
44 
45 #ifndef DATAFILE
46 #define DATAFILE "/usr/games/lib/dino.data"
47 #endif
48 
49 static void InitializeDino(Widget request, Widget renew);
50 static void DestroyDino(Widget old);
51 static Boolean SetValuesDino(Widget current, Widget request, Widget renew);
52 
53 static void SetAllColors(DinoWidget w, Boolean init);
54 static void GetColor(DinoWidget w, int face, Boolean init);
55 static void MoveControlCb(DinoWidget w, int face, int position, int direction, int style);
56 static void CheckPolyhedrons(DinoWidget w);
57 static void ResetPolyhedrons(DinoWidget w);
58 static Boolean SelectPolyhedrons(DinoWidget w, int x, int y, int *face, int *position);
59 static Boolean NarrowSelection(DinoWidget w, int *face, int *direction);
60 static Boolean PositionPolyhedrons(DinoWidget w, int x, int y, int *face, int *position, int *direction);
61 static int  GetStyle(DinoWidget w, int shift, int control, int alt);
62 static void MoveNoPolyhedrons(DinoWidget w);
63 static void PracticePolyhedrons(DinoWidget w);
64 static void RandomizePolyhedrons(DinoWidget w);
65 static void MovePolyhedrons(DinoWidget w, int face, int position, int direction, int style);
66 static void MoveInsideCorners(DinoWidget w, int face, int corner, int direction);
67 static void MoveOutsideCorners(DinoWidget w, int face, int corner, int direction);
68 static void MoveEdges(DinoWidget w, int face, int corner, int direction);
69 static void MoveFaces(DinoWidget w, int f, int d, int rotate);
70 static void ReadDiagonal(DinoWidget w, int face, int corner, int h);
71 static void WriteDiagonal(DinoWidget w, int face, int corner, int rotate, int h);
72 static void ReadFace(DinoWidget w, int face, int h);
73 static void WriteFace(DinoWidget w, int face, int rotate, int h);
74 static void RotateFace(DinoWidget w, int face, int direction);
75 static void DrawTriangle(DinoWidget w, int face, int position, int offset);
76 static int  CheckMoveDir(int position1, int position2, int *direction);
77 
78 DinoClassRec dinoClassRec =
79 {
80 	{
81 		(WidgetClass) & widgetClassRec,		/* superclass */
82 		"Dino",		/* class name */
83 		sizeof (DinoRec),	/* widget size */
84 		NULL,		/* class initialize */
85 		NULL,		/* class part initialize */
86 		FALSE,		/* class inited */
87 		(XtInitProc) InitializeDino,	/* initialize */
88 		NULL,		/* initialize hook */
89 		XtInheritRealize,	/* realize */
90 		NULL,		/* actions */
91 		0,		/* num actions */
92 		NULL,		/* resources */
93 		0,		/* num resources */
94 		NULLQUARK,	/* xrm class */
95 		TRUE,		/* compress motion */
96 		TRUE,		/* compress exposure */
97 		TRUE,		/* compress enterleave */
98 		TRUE,		/* visible interest */
99 		(XtWidgetProc) DestroyDino,	/* destroy */
100 		NULL,		/* resize */
101 		NULL,		/* expose */
102 		(XtSetValuesFunc) SetValuesDino,	/* set values */
103 		NULL,		/* set values hook */
104 		XtInheritSetValuesAlmost,	/* set values almost */
105 		NULL,		/* get values hook */
106 		NULL,		/* accept focus */
107 		XtVersion,	/* version */
108 		NULL,		/* callback private */
109 		NULL,		/* tm table */
110 		NULL,		/* query geometry */
111 		NULL,		/* display accelerator */
112 		NULL		/* extension */
113 	},
114 	{
115 		0		/* ignore */
116 	}
117 };
118 
119 WidgetClass dinoWidgetClass = (WidgetClass) & dinoClassRec;
120 
121 static DinoLoc slideCorner[MAXFACES][MAXORIENT][MAXORIENT / 2] =
122 {
123 	{
124 		{
125 			{3, TR, 0},
126 			{5, BR, 0}},
127 		{
128 			{3, TL, 1},
129 			{2, TR, 0}},
130 		{
131 			{2, TL, 1},
132 			{1, TR, 0}},
133 		{
134 			{5, BL, 1},
135 			{1, TL, 1}}
136 	},
137 	{
138 		{
139 			{2, TL, 0},
140 			{0, BL, 0}},
141 		{
142 			{2, BL, 0},
143 			{4, TL, 0}},
144 		{
145 			{4, BL, 0},
146 			{5, TL, 0}},
147 		{
148 			{0, TL, 0},
149 			{5, BL, 0}}
150 	},
151 	{
152 		{
153 			{3, TL, 0},
154 			{0, BR, 0}},
155 		{
156 			{3, BL, 0},
157 			{4, TR, 0}},
158 		{
159 			{4, TL, 1},
160 			{1, BR, 1}},
161 		{
162 			{0, BL, 1},
163 			{1, TR, 1}}
164 	},
165 	{
166 		{
167 			{5, BR, 1},
168 			{0, TR, 1}},
169 		{
170 			{5, TR, 1},
171 			{4, BR, 1}},
172 		{
173 			{4, TR, 1},
174 			{2, BR, 1}},
175 		{
176 			{0, BR, 1},
177 			{2, TR, 1}}
178 	},
179 	{
180 		{
181 			{3, BL, 1},
182 			{2, BR, 0}},
183 		{
184 			{3, BR, 0},
185 			{5, TR, 0}},
186 		{
187 			{5, TL, 1},
188 			{1, BL, 1}},
189 		{
190 			{2, BL, 1},
191 			{1, BR, 0}}
192 	},
193 	{
194 		{
195 			{3, BR, 1},
196 			{4, BR, 0}},
197 		{
198 			{3, TR, 1},
199 			{0, TR, 0}},
200 		{
201 			{0, TL, 1},
202 			{1, TL, 0}},
203 		{
204 			{4, BL, 1},
205 			{1, BL, 0}}
206 	}
207 };
208 
209 static int  oppFace[MAXFACES] =
210 {4, 3, 5, 1, 0, 2};
211 
212 static DinoCornerLoc oppCorner[MAXFACES][MAXORIENT] =
213 {
214 	{
215 		{4, 3},
216 		{4, 2},
217 		{4, 1},
218 		{4, 0}},
219 	{
220 		{3, 1},
221 		{3, 0},
222 		{3, 3},
223 		{3, 2}},
224 	{
225 		{5, 3},
226 		{5, 2},
227 		{5, 1},
228 		{5, 0}},
229 	{
230 		{1, 1},
231 		{1, 0},
232 		{1, 3},
233 		{1, 2}},
234 	{
235 		{0, 3},
236 		{0, 2},
237 		{0, 1},
238 		{0, 0}},
239 	{
240 		{2, 3},
241 		{2, 2},
242 		{2, 1},
243 		{2, 0}}
244 };
245 
246 /* static int slideNextFace2[MAXFACES] = {4, 3, 5, 1, 0, 2}; */
247 
248 static DinoCornerLoc slideNextFace[MAXFACES][MAXORIENT] =
249 {
250 	{
251 		{5, STRT},
252 		{3, CW},
253 		{2, STRT},
254 		{1, CCW}},
255 	{
256 		{0, CW},
257 		{2, STRT},
258 		{4, CCW},
259 		{5, HALF}},
260 	{
261 		{0, STRT},
262 		{3, STRT},
263 		{4, STRT},
264 		{1, STRT}},
265 	{
266 		{0, CCW},
267 		{5, HALF},
268 		{4, CW},
269 		{2, STRT}},
270 	{
271 		{2, STRT},
272 		{3, CCW},
273 		{5, STRT},
274 		{1, CW}},
275 	{
276 		{4, STRT},
277 		{3, HALF},
278 		{0, STRT},
279 		{1, HALF}}
280 };
281 
282 static int  faceToRotate2[MAXFACES][MAXORIENT][2] =
283 {
284 	{
285 		{3, 5},
286 		{2, 3},
287 		{1, 2},
288 		{1, 5}},
289 	{
290 		{0, 2},
291 		{2, 4},
292 		{4, 5},
293 		{0, 5}},
294 	{
295 		{3, 0},
296 		{4, 3},
297 		{1, 4},
298 		{0, 1}},
299 	{
300 		{0, 5},
301 		{4, 5},
302 		{2, 4},
303 		{0, 2}},
304 	{
305 		{2, 3},
306 		{3, 5},
307 		{1, 5},
308 		{1, 2}},
309 	{
310 		{4, 3},
311 		{3, 0},
312 		{0, 1},
313 		{1, 4}}
314 };
315 
316 static int  faceToRotate[MAXFACES][MAXORIENT] =
317 {
318 	{3, 2, 1, 5},
319 	{2, 4, 5, 0},
320 	{3, 4, 1, 0},
321 	{5, 4, 2, 0},
322 	{3, 5, 1, 2},
323 	{3, 0, 1, 4}
324 };
325 
326 static void
InitializeDino(Widget request,Widget renew)327 InitializeDino(Widget request, Widget renew)
328 {
329 	DinoWidget  w = (DinoWidget) renew;
330 
331 	CheckPolyhedrons(w);
332 	InitMoves();
333 	ResetPolyhedrons(w);
334 	(void) SRAND(getpid());
335 	w->dino.depth = DefaultDepthOfScreen(XtScreen(w));
336 	SetAllColors(w, True);
337 }
338 
339 static void
DestroyDino(Widget old)340 DestroyDino(Widget old)
341 {
342 	DinoWidget  w = (DinoWidget) old;
343 	int         face;
344 
345 	for (face = 0; face < MAXFACES; face++)
346 		XtReleaseGC(old, w->dino.faceGC[face]);
347 	XtReleaseGC(old, w->dino.borderGC);
348 	XtReleaseGC(old, w->dino.puzzleGC);
349 	XtReleaseGC(old, w->dino.inverseGC);
350 	XtRemoveCallbacks(old, XtNselectCallback, w->dino.select);
351 }
352 
353 static      Boolean
SetValuesDino(Widget current,Widget request,Widget renew)354 SetValuesDino(Widget current, Widget request, Widget renew)
355 {
356 	DinoWidget  c = (DinoWidget) current, w = (DinoWidget) renew;
357 	Boolean     redraw = False, setColors = False;
358 	int         face;
359 
360 	for (face = 0; face < MAXFACES; face++) {
361 		if (strcmp(w->dino.faceName[face], c->dino.faceName[face])) {
362 			setColors = True;
363 			break;
364 		}
365 	}
366 	if (w->core.background_pixel != c->core.background_pixel ||
367 	    w->dino.foreground != c->dino.foreground ||
368 	    w->dino.borderColor != c->dino.borderColor ||
369 	    w->dino.reverse != c->dino.reverse ||
370 	    w->dino.mono != c->dino.mono ||
371 	    setColors) {
372 		SetAllColors(w, False);
373 		redraw = True;
374 	}
375 	if (w->dino.orient != c->dino.orient) {
376 		ResetPolyhedrons(w);
377 		redraw = TRUE;
378 	} else if (w->dino.practice != c->dino.practice) {
379 		ResetPolyhedrons(w);
380 		redraw = TRUE;
381 	}
382 	if (w->dino.mode != c->dino.mode) {
383 		ResetPolyhedrons(w);
384 		redraw = TRUE;
385 	}
386 	if (w->dino.currentDirection == DINO_RESTORE) {
387 		SetStartPosition(w);
388 		w->dino.currentDirection = DINO_IGNORE;
389 	} else if (w->dino.currentDirection != DINO_IGNORE) {
390 		MovePolyhedrons(w, w->dino.currentFace, w->dino.currentPosition,
391 				w->dino.currentDirection, w->dino.style);
392 		w->dino.currentDirection = DINO_IGNORE;
393 	}
394 	return redraw;
395 }
396 
397 void
QuitDino(DinoWidget w,XEvent * event,char ** args,int nArgs)398 QuitDino(DinoWidget w, XEvent * event, char **args, int nArgs)
399 {
400 	XtCloseDisplay(XtDisplay(w));
401 	exit(0);
402 }
403 
404 void
SelectDino(DinoWidget w,XEvent * event,char ** args,int nArgs)405 SelectDino(DinoWidget w, XEvent * event, char **args, int nArgs)
406 {
407 	int         control;
408 
409 	if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
410 		       &(w->dino.currentFace), &(w->dino.currentPosition))) {
411 		control = (int) (event->xkey.state & ControlMask);
412 		if (control || w->dino.practice || !CheckSolved(w))
413 			DrawTriangle(w, w->dino.currentFace, w->dino.currentPosition,
414 				     TRUE);
415 	} else {
416 		w->dino.currentFace = DINO_IGNORE;
417 		w->dino.currentDirection = DINO_IGNORE;
418 	}
419 }
420 
421 void
ReleaseDino(DinoWidget w,XEvent * event,char ** args,int nArgs)422 ReleaseDino(DinoWidget w, XEvent * event, char **args, int nArgs)
423 {
424 	int         shift, control, alt, style, face, position, count = -1,
425 	            direction = 0;
426 	dinoCallbackStruct cb;
427 
428 	if (w->dino.currentFace == DINO_IGNORE)
429 		return;
430 	DrawTriangle(w, w->dino.currentFace, w->dino.currentPosition, FALSE);
431 	shift = (int) (event->xbutton.state & (ShiftMask | LockMask));
432 	control = (int) (event->xkey.state & ControlMask);
433 	alt = (int) (event->xkey.state &
434 		     (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask));
435 	style = GetStyle(w, shift, control, alt);
436 	if (!control && !w->dino.practice && CheckSolved(w))
437 		MoveNoPolyhedrons(w);
438 	else if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
439 		  &face, &position) && position != w->dino.currentPosition) {
440 		control = (control) ? 1 : 0;
441 		if (face == w->dino.currentFace)
442 			count = CheckMoveDir(w->dino.currentPosition, position, &direction);
443 		if (count == 1) {
444 			MoveDino(w, face, w->dino.currentPosition, direction, style, control);
445 			if (!control && CheckSolved(w)) {
446 				cb.reason = DINO_SOLVED;
447 				XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
448 			}
449 		} else if (count == 0)
450 			MoveNoPolyhedrons(w);
451 	}
452 	w->dino.currentFace = DINO_IGNORE;
453 	w->dino.currentDirection = DINO_IGNORE;
454 }
455 
456 void
PracticeDino(DinoWidget w,XEvent * event,char ** args,int nArgs)457 PracticeDino(DinoWidget w, XEvent * event, char **args, int nArgs)
458 {
459 	PracticePolyhedrons(w);
460 }
461 
462 void
PracticeDinoMaybe(DinoWidget w,XEvent * event,char ** args,int nArgs)463 PracticeDinoMaybe(DinoWidget w, XEvent * event, char **args, int nArgs)
464 {
465 	if (!w->dino.started)
466 		PracticePolyhedrons(w);
467 }
468 
469 void
RandomizeDino(DinoWidget w,XEvent * event,char ** args,int nArgs)470 RandomizeDino(DinoWidget w, XEvent * event, char **args, int nArgs)
471 {
472 	RandomizePolyhedrons(w);
473 }
474 
475 void
RandomizeDinoMaybe(DinoWidget w,XEvent * event,char ** args,int nArgs)476 RandomizeDinoMaybe(DinoWidget w, XEvent * event, char **args, int nArgs)
477 {
478 	if (!w->dino.started)
479 		RandomizePolyhedrons(w);
480 }
481 
482 void
GetDino(DinoWidget w,XEvent * event,char ** args,int nArgs)483 GetDino(DinoWidget w, XEvent * event, char **args, int nArgs)
484 {
485 	FILE       *fp;
486 	char        c;
487 	int         mode, orient, practice, moves;
488 	dinoCallbackStruct cb;
489 
490 	if ((fp = fopen(DATAFILE, "r")) == NULL)
491 		(void) printf("Can not read %s for get.\n", DATAFILE);
492 	else {
493 		FlushMoves(w);
494 		while ((c = getc(fp)) != EOF && c != SYMBOL);
495 		(void) fscanf(fp, "%d", &mode);
496 		if (mode >= PERIOD2 && mode <= BOTH)
497 			switch (mode) {
498 				case PERIOD2:
499 					cb.reason = DINO_PERIOD2;
500 					XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
501 					break;
502 				case PERIOD3:
503 					cb.reason = DINO_PERIOD3;
504 					XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
505 					break;
506 				case BOTH:
507 					cb.reason = DINO_BOTH;
508 					XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
509 		} else
510 			(void) printf("%s corrupted: mode %d should be between %d and %d\n",
511 				      DATAFILE, mode, PERIOD2, BOTH);
512 		while ((c = getc(fp)) != EOF && c != SYMBOL);
513 		(void) fscanf(fp, "%d", &orient);
514 		if (w->dino.orient != (Boolean) orient) {
515 			cb.reason = DINO_ORIENT;
516 			XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
517 		}
518 		while ((c = getc(fp)) != EOF && c != SYMBOL);
519 		(void) fscanf(fp, "%d", &practice);
520 		if (w->dino.practice != (Boolean) practice) {
521 			cb.reason = DINO_PRACTICE;
522 			XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
523 		}
524 		while ((c = getc(fp)) != EOF && c != SYMBOL);
525 		(void) fscanf(fp, "%d", &moves);
526 		ScanStartPosition(fp, w);
527 		cb.reason = DINO_RESTORE;
528 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
529 		ScanMoves(fp, w, moves);
530 		(void) fclose(fp);
531 		(void) printf("%s: mode %d, orient %d, practice %d, moves %d.\n",
532 			      DATAFILE, mode, orient, practice, moves);
533 	}
534 }
535 
536 void
WriteDino(DinoWidget w,XEvent * event,char ** args,int nArgs)537 WriteDino(DinoWidget w, XEvent * event, char **args, int nArgs)
538 {
539 	FILE       *fp;
540 
541 	if ((fp = fopen(DATAFILE, "w")) == NULL)
542 		(void) printf("Can not write to %s.\n", DATAFILE);
543 	else {
544 		(void) fprintf(fp, "mode%c %d\n", SYMBOL, w->dino.mode);
545 		(void) fprintf(fp, "orient%c %d\n", SYMBOL, (w->dino.orient) ? 1 : 0);
546 		(void) fprintf(fp, "practice%c %d\n", SYMBOL, (w->dino.practice) ? 1 : 0);
547 		(void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
548 		PrintStartPosition(fp, w);
549 		PrintMoves(fp);
550 		(void) fclose(fp);
551 		(void) printf("Saved to %s.\n", DATAFILE);
552 	}
553 }
554 
555 void
UndoDino(DinoWidget w,XEvent * event,char ** args,int nArgs)556 UndoDino(DinoWidget w, XEvent * event, char **args, int nArgs)
557 {
558 	if (MadeMoves()) {
559 		int         face, position, direction, style, control;
560 
561 		GetMove(&face, &position, &direction, &style, &control);
562 		direction = (direction < MAXORIENT) ? (direction + MAXORIENT / 2) %
563 			MAXORIENT : 5 * MAXORIENT - direction;
564 		if (control)
565 			MoveControlCb(w, face, position, direction, style);
566 		else {
567 			dinoCallbackStruct cb;
568 
569 			MovePolyhedrons(w, face, position, direction, style);
570 			cb.reason = DINO_UNDO;
571 			cb.face = face;
572 			cb.position = position;
573 			cb.direction = direction;
574 			cb.style = style;
575 			XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
576 		}
577 	}
578 }
579 
580 void
SolveDino(DinoWidget w,XEvent * event,char ** args,int nArgs)581 SolveDino(DinoWidget w, XEvent * event, char **args, int nArgs)
582 {
583 #if 0
584 	SolvePolyhedrons(w);	/* Sorry, this is not implemented */
585 #endif
586 }
587 
588 void
OrientizeDino(DinoWidget w,XEvent * event,char ** args,int nArgs)589 OrientizeDino(DinoWidget w, XEvent * event, char **args, int nArgs)
590 {
591 	dinoCallbackStruct cb;
592 
593 	cb.reason = DINO_ORIENT;
594 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
595 }
596 
597 void
Period2ModeDino(DinoWidget w,XEvent * event,char ** args,int nArgs)598 Period2ModeDino(DinoWidget w, XEvent * event, char **args, int nArgs)
599 {
600 	dinoCallbackStruct cb;
601 
602 	cb.reason = DINO_PERIOD2;
603 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
604 }
605 
606 void
Period3ModeDino(DinoWidget w,XEvent * event,char ** args,int nArgs)607 Period3ModeDino(DinoWidget w, XEvent * event, char **args, int nArgs)
608 {
609 	dinoCallbackStruct cb;
610 
611 	cb.reason = DINO_PERIOD3;
612 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
613 }
614 
615 void
BothModeDino(DinoWidget w,XEvent * event,char ** args,int nArgs)616 BothModeDino(DinoWidget w, XEvent * event, char **args, int nArgs)
617 {
618 	dinoCallbackStruct cb;
619 
620 	cb.reason = DINO_BOTH;
621 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
622 }
623 
624 void
MoveDinoInput(DinoWidget w,int x,int y,int direction,int shift,int control,int alt)625 MoveDinoInput(DinoWidget w, int x, int y, int direction, int shift, int control, int alt)
626 {
627 	int         face, position, style;
628 
629 	if (!w->dino.practice && !control && CheckSolved(w)) {
630 		MoveNoPolyhedrons(w);
631 		return;
632 	}
633 	if (!PositionPolyhedrons(w, x, y, &face, &position, &direction))
634 		return;
635 	if (direction >= 2 * MAXORIENT) {
636 		if (control)
637 			style = FACE;
638 		else
639 			return;
640 	} else
641 		style = GetStyle(w, shift, control, alt);
642 	control = (control) ? 1 : 0;
643 	MoveDino(w, face, position, direction, style, control);
644 	if (!control && CheckSolved(w)) {
645 		dinoCallbackStruct cb;
646 
647 		cb.reason = DINO_SOLVED;
648 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
649 	}
650 }
651 
652 void
MoveDino(DinoWidget w,int face,int position,int direction,int style,int control)653 MoveDino(DinoWidget w, int face, int position, int direction, int style, int control)
654 {
655 	if (control)
656 		MoveControlCb(w, face, position, direction, style);
657 	else {
658 		dinoCallbackStruct cb;
659 
660 		MovePolyhedrons(w, face, position, direction, style);
661 		cb.reason = DINO_MOVED;
662 		cb.face = face;
663 		cb.position = position;
664 		cb.direction = direction;
665 		cb.style = style;
666 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
667 	}
668 	PutMove(face, position, direction, style, control);
669 }
670 
671 static void
SetAllColors(DinoWidget w,Boolean init)672 SetAllColors(DinoWidget w, Boolean init)
673 {
674 	XGCValues   values;
675 	XtGCMask    valueMask;
676 	int         face;
677 
678 	valueMask = GCForeground | GCBackground;
679 
680 	if (w->dino.reverse) {
681 		values.background = w->core.background_pixel;
682 		values.foreground = w->dino.foreground;
683 	} else {
684 		values.foreground = w->core.background_pixel;
685 		values.background = w->dino.foreground;
686 	}
687 	if (!init)
688 		XtReleaseGC((Widget) w, w->dino.inverseGC);
689 	w->dino.inverseGC = XtGetGC((Widget) w, valueMask, &values);
690 	if (w->dino.reverse) {
691 		values.background = w->dino.foreground;
692 		values.foreground = w->core.background_pixel;
693 	} else {
694 		values.foreground = w->dino.foreground;
695 		values.background = w->core.background_pixel;
696 	}
697 	if (!init)
698 		XtReleaseGC((Widget) w, w->dino.puzzleGC);
699 	w->dino.puzzleGC = XtGetGC((Widget) w, valueMask, &values);
700 	if (w->dino.depth < 2 || w->dino.mono) {
701 		if (w->dino.reverse) {
702 			values.background = w->dino.foreground;
703 			values.foreground = w->core.background_pixel;
704 		} else {
705 			values.foreground = w->dino.foreground;
706 			values.background = w->core.background_pixel;
707 		}
708 	} else {
709 		values.foreground = w->dino.borderColor;
710 		values.background = w->core.background_pixel;
711 	}
712 	if (!init)
713 		XtReleaseGC((Widget) w, w->dino.borderGC);
714 	w->dino.borderGC = XtGetGC((Widget) w, valueMask, &values);
715 	for (face = 0; face < MAXFACES; face++)
716 		GetColor(w, face, init);
717 }
718 
719 static void
GetColor(DinoWidget w,int face,Boolean init)720 GetColor(DinoWidget w, int face, Boolean init)
721 {
722 	XGCValues   values;
723 	XtGCMask    valueMask;
724 	XColor      colorCell, rgb;
725 
726 	valueMask = GCForeground | GCBackground;
727 	if (w->dino.reverse) {
728 		values.background = w->dino.foreground;
729 	} else {
730 		values.background = w->core.background_pixel;
731 	}
732 	if (w->dino.depth > 1 && !w->dino.mono) {
733 		if (XAllocNamedColor(XtDisplay(w),
734 				  DefaultColormap(XtDisplay(w), XtWindow(w)),
735 				 w->dino.faceName[face], &colorCell, &rgb)) {
736 			values.foreground = w->dino.faceColor[face] = colorCell.pixel;
737 			if (!init)
738 				XtReleaseGC((Widget) w, w->dino.faceGC[face]);
739 			w->dino.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
740 			return;
741 		} else {
742 			char        buf[121];
743 
744 			(void) sprintf(buf, "Color name \"%s\" is not defined",
745 				       w->dino.faceName[face]);
746 			XtWarning(buf);
747 		}
748 	}
749 	if (w->dino.reverse) {
750 		values.background = w->dino.foreground;
751 		values.foreground = w->core.background_pixel;
752 	} else {
753 		values.background = w->core.background_pixel;
754 		values.foreground = w->dino.foreground;
755 	}
756 	if (!init)
757 		XtReleaseGC((Widget) w, w->dino.faceGC[face]);
758 	w->dino.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
759 }
760 
761 static void
MoveControlCb(DinoWidget w,int face,int position,int direction,int style)762 MoveControlCb(DinoWidget w, int face, int position, int direction, int style)
763 {
764 	dinoCallbackStruct cb;
765 	int         newFace, newSide, newDirection, corner, newCorner;
766 
767 	MovePolyhedrons(w, face, position, direction, style);
768 	cb.reason = DINO_CONTROL;
769 	cb.face = face;
770 	cb.position = position;
771 	cb.direction = direction;
772 	cb.style = style;
773 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
774 	if (style == CORNER) {
775 		newSide = (position + 2) % MAXORIENT;
776 		MovePolyhedrons(w, face, newSide, direction, MIDDLE);
777 		cb.face = face;
778 		cb.position = newSide;
779 		cb.direction = direction;
780 		cb.style = MIDDLE;
781 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
782 		corner = (position - !((position + direction) % 2) + MAXORIENT) % MAXORIENT;
783 		newFace = oppCorner[face][corner].face;
784 		newCorner = oppCorner[face][corner].rotation;
785 		newDirection = 2 * ((direction / 2 + (face != 1 && face != 3)) % 2) +
786 			!(newCorner % 2);
787 		newSide = newCorner;
788 		MovePolyhedrons(w, newFace, newSide, newDirection, CORNER);
789 		cb.face = newFace;
790 		cb.position = newSide;
791 		cb.direction = newDirection;
792 		cb.style = CORNER;
793 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
794 	} else if (style == MIDDLE) {
795 		newSide = (position + 2) % MAXORIENT;
796 		MovePolyhedrons(w, face, newSide, direction, CORNER);
797 		cb.face = face;
798 		cb.position = newSide;
799 		cb.direction = direction;
800 		cb.style = CORNER;
801 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
802 		corner = (position - !((position + direction) % 2) + MAXORIENT) % MAXORIENT;
803 		newCorner = oppCorner[face][corner].rotation;
804 		newFace = oppCorner[face][corner].face;
805 		if (newFace != 1 && newFace != 3)
806 			newDirection = (direction + 2) % MAXORIENT;
807 		else
808 			newDirection = direction;
809 		newDirection = 2 * (newDirection / 2) + !(newDirection % 2);
810 		newSide = (newCorner + 2) % MAXORIENT;
811 		MovePolyhedrons(w, newFace, newSide, newDirection, CORNER);
812 		cb.face = newFace;
813 		cb.position = newSide;
814 		cb.direction = newDirection;
815 		cb.style = CORNER;
816 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
817 	} else if (style == EDGE) {
818 		newSide = (position + 2) % MAXORIENT;
819 		MovePolyhedrons(w, face, newSide, direction, EDGE);
820 		cb.face = face;
821 		cb.position = newSide;
822 		cb.direction = direction;
823 		cb.style = EDGE;
824 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
825 	}
826 }
827 
828 static void
CheckPolyhedrons(DinoWidget w)829 CheckPolyhedrons(DinoWidget w)
830 {
831 	if (w->dino.mode < PERIOD2 || w->dino.mode > BOTH) {
832 		XtWarning("Mode is in error, use 2 for Period2, 3 for Period3, 4 for Both");
833 		w->dino.mode = DEFAULTMODE;
834 	}
835 }
836 
837 static void
ResetPolyhedrons(DinoWidget w)838 ResetPolyhedrons(DinoWidget w)
839 {
840 	int         face, position;
841 
842 	for (face = 0; face < MAXFACES; face++)
843 		for (position = 0; position < MAXORIENT; position++) {
844 			w->dino.cubeLoc[face][position].face = face;
845 			w->dino.cubeLoc[face][position].rotation = STRT - MAXORIENT;
846 		}
847 	FlushMoves(w);
848 	w->dino.started = False;
849 }
850 
851 static      Boolean
SelectPolyhedrons(DinoWidget w,int x,int y,int * face,int * position)852 SelectPolyhedrons(DinoWidget w, int x, int y, int *face, int *position)
853 {
854 	if (w->dino.dim == 2)
855 		return SelectPolyhedrons2D((Dino2DWidget) w, x, y,
856 					   face, position);
857 	else if (w->dino.dim == 3)
858 		return SelectPolyhedrons3D((Dino3DWidget) w, x, y,
859 					   face, position);
860 	return False;
861 }
862 
863 static      Boolean
NarrowSelection(DinoWidget w,int * face,int * direction)864 NarrowSelection(DinoWidget w, int *face, int *direction)
865 {
866 	if (w->dino.dim == 2)
867 		return NarrowSelection2D((Dino2DWidget) w, face, direction);
868 	else if (w->dino.dim == 3)
869 		return NarrowSelection3D((Dino3DWidget) w, face, direction);
870 	return False;
871 }
872 
873 static      Boolean
PositionPolyhedrons(DinoWidget w,int x,int y,int * face,int * position,int * direction)874 PositionPolyhedrons(DinoWidget w, int x, int y, int *face, int *position, int *direction)
875 {
876 	if (!SelectPolyhedrons(w, x, y, face, position))
877 		return False;
878 	return NarrowSelection(w, face, direction);
879 }
880 
881 static int
GetStyle(DinoWidget w,int shift,int control,int alt)882 GetStyle(DinoWidget w, int shift, int control, int alt)
883 {
884 	if (w->dino.mode != BOTH) {
885 		if (control && shift) {
886 			if (w->dino.mode == PERIOD3)
887 				return EDGE;
888 			else if (alt)
889 				return MIDDLE;
890 			else
891 				return CORNER;
892 		} else if (w->dino.mode == PERIOD2)
893 			return EDGE;
894 		else if (alt)
895 			return MIDDLE;
896 		else
897 			return CORNER;
898 	} else {
899 		if (shift)
900 			return EDGE;
901 		else {
902 			if (alt)
903 				return MIDDLE;
904 			else
905 				return CORNER;
906 		}
907 	}
908 }
909 static void
MoveNoPolyhedrons(DinoWidget w)910 MoveNoPolyhedrons(DinoWidget w)
911 {
912 	dinoCallbackStruct cb;
913 
914 	cb.reason = DINO_ILLEGAL;
915 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
916 }
917 
918 static void
PracticePolyhedrons(DinoWidget w)919 PracticePolyhedrons(DinoWidget w)
920 {
921 	dinoCallbackStruct cb;
922 
923 	cb.reason = DINO_PRACTICE;
924 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
925 }
926 
927 static void
RandomizePolyhedrons(DinoWidget w)928 RandomizePolyhedrons(DinoWidget w)
929 {
930 	dinoCallbackStruct cb;
931 	int         face, position, direction, style;
932 	int         big = MAXORIENT * 3 + NRAND(2);
933 
934 	if (w->dino.practice)
935 		PracticePolyhedrons(w);
936 	cb.reason = DINO_RESET;
937 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
938 
939 #ifdef DEBUG
940 	big = 3;
941 #endif
942 
943 	while (big--) {
944 		face = NRAND(MAXFACES);
945 		position = NRAND(MAXORIENT);
946 		direction = ((NRAND(2)) ? position + 1 : position + 3) % MAXORIENT;
947 		if (w->dino.mode == PERIOD2)
948 			style = EDGE;
949 		else if (w->dino.mode == BOTH)
950 			style = NRAND(3);
951 		else
952 			style = NRAND(2);
953 		MoveDino(w, face, position, direction, style, FALSE);
954 	}
955 	FlushMoves(w);
956 	cb.reason = DINO_RANDOMIZE;
957 	XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
958 	if (CheckSolved(w)) {
959 		cb.reason = DINO_SOLVED;
960 		XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
961 	}
962 }
963 
964 static void
MovePolyhedrons(DinoWidget w,int face,int position,int direction,int style)965 MovePolyhedrons(DinoWidget w, int face, int position, int direction, int style)
966 {
967 	int         corner, newCorner;
968 
969 	corner = (position - !((position + direction) % 2) + MAXORIENT) % MAXORIENT;
970 	if (style == CORNER) {
971 		MoveInsideCorners(w, face, corner, direction);
972 	} else if (style == MIDDLE) {
973 		MoveOutsideCorners(w, face, corner, direction);
974 		newCorner = oppCorner[face][corner].rotation;
975 		face = oppCorner[face][corner].face;
976 		if (((face != 1 && face != 3) + corner) % 2)
977 			direction = (direction + 1) % MAXORIENT;
978 		else
979 			direction = (direction + 3) % MAXORIENT;
980 		corner = newCorner;
981 		MoveOutsideCorners(w, face, corner, direction);
982 	} else if (style == EDGE) {
983 		MoveEdges(w, face, corner, direction);
984 		MoveFaces(w, face, corner,
985 			((face == 2 || face == 5) ? CCW : HALF) % MAXORIENT);
986 	} else {
987 		int         k, newFace, rotate, newDirection;
988 
989 		RotateFace(w, faceToRotate[face][direction % MAXORIENT], CW);
990 		RotateFace(w, faceToRotate[face][(direction + 2) % MAXORIENT], CCW);
991 		ReadFace((DinoWidget) w, face, 0);
992 		for (k = 1; k <= MAXORIENT; k++) {
993 			newFace = slideNextFace[face][direction % MAXORIENT].face;
994 			rotate = slideNextFace[face][direction % MAXORIENT].rotation;
995 			newDirection = (rotate + direction) % MAXORIENT;
996 			if (k != MAXORIENT)
997 				ReadFace((DinoWidget) w, newFace, k);
998 			WriteFace(w, newFace, rotate, k - 1);
999 			face = newFace;
1000 			direction = newDirection;
1001 		}
1002 	}
1003 }
1004 
1005 static void
MoveInsideCorners(DinoWidget w,int face,int corner,int direction)1006 MoveInsideCorners(DinoWidget w, int face, int corner, int direction)
1007 {
1008 	int         newFace, newCorner, newDirection, dir, k;
1009 
1010 	ReadDiagonal((DinoWidget) w, face, corner, 0);
1011 	for (k = 1; k <= MAXROTATE; k++) {
1012 		dir = direction / 2;
1013 		newFace = slideCorner[face][corner][dir].face;
1014 		newCorner = slideCorner[face][corner][dir].side;
1015 		newDirection = 2 * slideCorner[face][corner][dir].dir + !(newCorner % 2);
1016 		if (k != MAXROTATE)
1017 			ReadDiagonal((DinoWidget) w, newFace, newCorner, k);
1018 		WriteDiagonal(w, newFace, newCorner,
1019 		  (newDirection - direction + MAXORIENT) % MAXORIENT, k - 1);
1020 		face = newFace;
1021 		corner = newCorner;
1022 		direction = newDirection;
1023 	}
1024 }
1025 
1026 static void
MoveOutsideCorners(DinoWidget w,int face,int corner,int direction)1027 MoveOutsideCorners(DinoWidget w, int face, int corner, int direction)
1028 {
1029 	int         newFace, newCorner, newDirection, dir, k;
1030 
1031 	ReadDiagonal((DinoWidget) w, face, corner, 0);
1032 	for (k = 1; k <= MAXROTATE; k++) {
1033 		corner = (corner + 2) % MAXORIENT;
1034 		dir = direction / 2;
1035 		newFace = slideCorner[face][corner][dir].face;
1036 		newCorner = (slideCorner[face][corner][dir].side + 2) % MAXORIENT;
1037 		newDirection = 2 * slideCorner[face][corner][dir].dir + !(newCorner % 2);
1038 		if (k != MAXROTATE)
1039 			ReadDiagonal((DinoWidget) w, newFace, newCorner, k);
1040 		WriteDiagonal(w, newFace, newCorner,
1041 		  (newDirection - direction + MAXORIENT) % MAXORIENT, k - 1);
1042 		face = newFace;
1043 		corner = newCorner;
1044 		direction = newDirection;
1045 	}
1046 }
1047 
1048 static void
MoveEdges(DinoWidget w,int face,int corner,int direction)1049 MoveEdges(DinoWidget w, int face, int corner, int direction)
1050 {
1051 	int         k, newFace, rotate, newCorner, newDirection;
1052 
1053 	ReadDiagonal((DinoWidget) w, face, corner, 0);
1054 	for (k = 1; k <= 2; k++) {
1055 		newFace = oppFace[face];
1056 		/*rotate = (((face == 1 || face == 3) ? 1 : 3) + 3 * direction) %
1057 		   MAXORIENT; */
1058 		newCorner = ((((face == 1 || face == 3) + corner) % 2) ?
1059 			     (corner + 3) : (corner + 1)) % MAXORIENT;
1060 		rotate = (newCorner - corner + MAXORIENT) % MAXORIENT;
1061 		newDirection = (rotate + direction) % MAXORIENT;
1062 		if (k != 2)
1063 			ReadDiagonal((DinoWidget) w, newFace, newCorner, k);
1064 		WriteDiagonal(w, newFace, newCorner, rotate, k - 1);
1065 		face = newFace;
1066 		corner = newCorner;
1067 		direction = newDirection;
1068 	}
1069 }
1070 
1071 static void
MoveFaces(DinoWidget w,int f,int d,int rotate)1072 MoveFaces(DinoWidget w, int f, int d, int rotate)
1073 {
1074 	int         k, face, newFace;
1075 
1076 	face = faceToRotate2[f][d][0],
1077 		ReadFace((DinoWidget) w, face, 0);
1078 	for (k = 1; k <= 2; k++) {
1079 		newFace = faceToRotate2[f][d][k % 2],
1080 			rotate = MAXORIENT - rotate;
1081 		if (k != 2)
1082 			ReadFace((DinoWidget) w, newFace, k);
1083 		WriteFace(w, newFace, rotate, k - 1);
1084 		face = newFace;
1085 	}
1086 }
1087 
1088 static void
ReadDiagonal(DinoWidget w,int face,int corner,int h)1089 ReadDiagonal(DinoWidget w, int face, int corner, int h)
1090 {
1091 	w->dino.spindleLoc[h][0] = w->dino.cubeLoc[face][corner];
1092 	w->dino.spindleLoc[h][1] = w->dino.cubeLoc[face][(corner + 1) % MAXORIENT];
1093 }
1094 
1095 static void
WriteDiagonal(DinoWidget w,int face,int corner,int rotate,int h)1096 WriteDiagonal(DinoWidget w, int face, int corner, int rotate, int h)
1097 {
1098 	w->dino.spindleLoc[h][0].rotation =
1099 		(w->dino.spindleLoc[h][0].rotation + rotate) % MAXORIENT;
1100 	w->dino.spindleLoc[h][1].rotation =
1101 		(w->dino.spindleLoc[h][1].rotation + rotate) % MAXORIENT;
1102 	w->dino.cubeLoc[face][corner] = w->dino.spindleLoc[h][0];
1103 	DrawTriangle(w, face, corner, FALSE);
1104 	w->dino.cubeLoc[face][(corner + 1) % MAXORIENT] = w->dino.spindleLoc[h][1];
1105 	DrawTriangle(w, face, (corner + 1) % MAXORIENT, FALSE);
1106 }
1107 
1108 static void
ReadFace(DinoWidget w,int face,int h)1109 ReadFace(DinoWidget w, int face, int h)
1110 {
1111 	int         side;
1112 
1113 	for (side = 0; side < MAXORIENT; side++)
1114 		w->dino.rowLoc[h][side] = w->dino.cubeLoc[face][side];
1115 }
1116 
1117 static void
WriteFace(DinoWidget w,int face,int rotate,int h)1118 WriteFace(DinoWidget w, int face, int rotate, int h)
1119 {
1120 	int         side, newSide;
1121 
1122 	for (side = 0; side < MAXORIENT; side++) {
1123 		newSide = (side + rotate) % MAXORIENT;
1124 		w->dino.cubeLoc[face][newSide] = w->dino.rowLoc[h][side];
1125 		w->dino.cubeLoc[face][newSide].rotation =
1126 			(w->dino.cubeLoc[face][newSide].rotation + rotate) % MAXORIENT;
1127 		DrawTriangle(w, face, (side + rotate) % MAXORIENT, FALSE);
1128 	}
1129 }
1130 
1131 static void
RotateFace(DinoWidget w,int face,int direction)1132 RotateFace(DinoWidget w, int face, int direction)
1133 {
1134 	int         side;
1135 
1136 	/* Read Face */
1137 	for (side = 0; side < MAXORIENT; side++)
1138 		w->dino.faceLoc[side] = w->dino.cubeLoc[face][side];
1139 	/* Write Face */
1140 	for (side = 0; side < MAXORIENT; side++) {
1141 		w->dino.cubeLoc[face][side] = (direction == CW) ?
1142 			w->dino.faceLoc[(side + MAXORIENT - 1) % MAXORIENT] :
1143 			w->dino.faceLoc[(side + 1) % MAXORIENT];
1144 		w->dino.cubeLoc[face][side].rotation =
1145 			(w->dino.cubeLoc[face][side].rotation + direction) % MAXORIENT;
1146 		DrawTriangle(w, face, side, FALSE);
1147 	}
1148 }
1149 
1150 void
DrawAllPolyhedrons(DinoWidget w)1151 DrawAllPolyhedrons(DinoWidget w)
1152 {
1153 	int         face, position;
1154 
1155 	for (face = 0; face < MAXFACES; face++)
1156 		for (position = 0; position < MAXORIENT; position++)
1157 			DrawTriangle(w, face, position, FALSE);
1158 }
1159 
1160 static void
DrawTriangle(DinoWidget w,int face,int position,int offset)1161 DrawTriangle(DinoWidget w, int face, int position, int offset)
1162 {
1163 	if (w->dino.dim == 2)
1164 		DrawTriangle2D((Dino2DWidget) w, face, position, offset);
1165 	else if (w->dino.dim == 3)
1166 		DrawTriangle3D((Dino3DWidget) w, face, position, offset);
1167 }
1168 
1169 Boolean
CheckSolved(DinoWidget w)1170 CheckSolved(DinoWidget w)
1171 {
1172 	int         face, position;
1173 	DinoCornerLoc test;
1174 
1175 	for (face = 0; face < MAXFACES; face++)
1176 		for (position = 0; position < MAXORIENT; position++) {
1177 			if (!position) {
1178 				test.face = w->dino.cubeLoc[face][position].face;
1179 				test.rotation = w->dino.cubeLoc[face][position].rotation;
1180 			} else if (test.face !=		/*face */
1181 				   w->dino.cubeLoc[face][position].face ||
1182 				   (w->dino.orient && test.rotation !=	/*STRT - MAXORIENT */
1183 				    w->dino.cubeLoc[face][position].rotation))
1184 				return False;
1185 		}
1186 	return True;
1187 }
1188 
1189 static int
CheckMoveDir(int position1,int position2,int * direction)1190 CheckMoveDir(int position1, int position2, int *direction)
1191 {
1192 	if (!((position1 - position2 + MAXORIENT) % 2))
1193 		return FALSE;
1194 	switch (position1) {
1195 		case 0:
1196 			*direction = (position2 == 1) ? 1 : 2;
1197 			break;
1198 		case 1:
1199 			*direction = (position2 == 2) ? 2 : 3;
1200 			break;
1201 		case 2:
1202 			*direction = (position2 == 3) ? 3 : 0;
1203 			break;
1204 		case 3:
1205 			*direction = (position2 == 0) ? 0 : 1;
1206 			break;
1207 		default:
1208 			return FALSE;
1209 	}
1210 	return TRUE;
1211 }
1212 
1213 #ifdef DEBUG
1214 
1215 void
PrintCube(DinoWidget w)1216 PrintCube(DinoWidget w)
1217 {
1218 	int         face, position;
1219 
1220 	for (face = 0; face < MAXFACES; face++) {
1221 		for (position = 0; position < MAXORIENT; position++)
1222 			(void) printf("%d %d  ", w->dino.cubeLoc[face][position].face,
1223 				   w->dino.cubeLoc[face][position].rotation);
1224 		(void) printf("\n");
1225 	}
1226 	(void) printf("\n");
1227 }
1228 
1229 #endif
1230