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