1 /*-
2 # X-BASED PYRAMINX(tm)
3 #
4 # Pyraminx.c
5 #
6 ###
7 #
8 # Copyright (c) 1994 - 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 Pyraminx */
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 "PyraminxP.h"
42
43 #ifndef DATAFILE
44 #define DATAFILE "/usr/games/lib/pyraminx.data"
45 #endif
46
47 #define NOTDIR(x) ((x==CW)?CCW:CW)
48
49 typedef struct _CRD {
50 int column, row, diagonal;
51 } CRD;
52
53 static void InitializePyraminx(Widget request, Widget renew);
54 static void ExposePyraminx(Widget renew, XEvent * event, Region region);
55 static void ResizePyraminx(PyraminxWidget w);
56 static void DestroyPyraminx(Widget old);
57 static Boolean SetValuesPyraminx(Widget current, Widget request, Widget renew);
58 static void QuitPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
59 static void PracticePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
60 static void PracticePyraminxMaybe(PyraminxWidget w, XEvent * event, char **args, int nArgs);
61 static void RandomizePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
62 static void RandomizePyraminxMaybe(PyraminxWidget w, XEvent * event, char **args, int nArgs);
63 static void GetPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
64 static void WritePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
65 static void UndoPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
66 static void SolvePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
67 static void IncrementPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
68 static void DecrementPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
69 static void OrientizePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
70 static void Period2ModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
71 static void Period3ModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
72 static void BothModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
73 static void StickyModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
74 static void MovePyraminxTop(PyraminxWidget w, XEvent * event, char **args, int nArgs);
75 static void MovePyraminxTr(PyraminxWidget w, XEvent * event, char **args, int nArgs);
76 static void MovePyraminxLeft(PyraminxWidget w, XEvent * event, char **args, int nArgs);
77 static void MovePyraminxCw(PyraminxWidget w, XEvent * event, char **args, int nArgs);
78 static void MovePyraminxRight(PyraminxWidget w, XEvent * event, char **args, int nArgs);
79 static void MovePyraminxBl(PyraminxWidget w, XEvent * event, char **args, int nArgs);
80 static void MovePyraminxBottom(PyraminxWidget w, XEvent * event, char **args, int nArgs);
81 static void MovePyraminxCcw(PyraminxWidget w, XEvent * event, char **args, int nArgs);
82 static void MovePyraminxInput(PyraminxWidget w, int x, int y, int direction, int shift, int control);
83 static void SelectPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
84 static void ReleasePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs);
85
86 static void SetAllColors(PyraminxWidget w, Boolean init);
87 static void GetColor(PyraminxWidget w, int face, Boolean init);
88 static void MoveControlCb(PyraminxWidget w, int face, int direction, int style);
89 static void CheckPolyhedrons(PyraminxWidget w);
90 static void ResetPolyhedrons(PyraminxWidget w);
91 static void ResizePolyhedrons(PyraminxWidget w);
92 static Boolean SelectPolyhedrons(PyraminxWidget w, int x, int y, int *face, CRD * crd);
93 static void NarrowSelection(PyraminxWidget w, int style, int *face, CRD * crd, int *direction);
94 static Boolean PositionPolyhedrons(PyraminxWidget w, int x, int y, int style, int *face, CRD * crd, int *direction);
95 static void MoveNoPolyhedrons(PyraminxWidget w);
96 static void PracticePolyhedrons(PyraminxWidget w);
97 static void RandomizePolyhedrons(PyraminxWidget w);
98 static void MovePolyhedrons(PyraminxWidget w, int face, CRD crd, int direction, int style);
99 static void RotateFace(PyraminxWidget w, int view, int faceOnView, int direction);
100
101 /* CRD : Column, Row, Diagonal */
102 static void ReadCRD2(PyraminxWidget w, int view, int dir, int h, int orient);
103 static void ReadCRD3(PyraminxWidget w, int view, int faceOnView, int dir, int h, int len, int orient);
104 static void RotateCRD2(PyraminxWidget w, int rotate, int orient);
105 static void RotateCRD3(PyraminxWidget w, int faceOnView, int dir, int len, int orient);
106 static void ReverseCRD2(PyraminxWidget w, int orient);
107 static void ReverseCRD3(PyraminxWidget w, int len, int orient);
108 static void WriteCRD2(PyraminxWidget w, int view, int dir, int h, int orient);
109 static void WriteCRD3(PyraminxWidget w, int view, int faceOnView, int dir, int h, int len, int orient);
110 static void DrawFrame(PyraminxWidget w, GC gc);
111 static void DrawTriangle(PyraminxWidget w, int face, int position, int offset);
112 static void DrawOrientLine(PyraminxWidget w, int orient, int dx, int dy, int side, GC borderGC);
113 static int Crd(int dir, int I, int J, int side);
114 static int Length(PyraminxWidget w, int face, int dir, int h);
115 static int CheckMoveDir(PyraminxWidget w, CRD crd1, CRD crd2, int face, int *direction);
116 static CRD ToCRD(PyraminxWidget w, int face, int position);
117 static int ToPosition(PyraminxWidget w, CRD crd);
118 static int Sqrt(int i);
119
120 #ifdef DEBUG
121 static void PrintTetra(PyraminxWidget w);
122 static void PrintFace(PyraminxWidget w);
123 static void PrintRow2(PyraminxWidget w, int orient);
124 static void PrintRow3(PyraminxWidget w, int len, int orient);
125
126 #endif
127
128 static char defaultTranslationsPyraminx[] =
129 "<KeyPress>q: Quit()\n\
130 Ctrl<KeyPress>C: Quit()\n\
131 <KeyPress>KP_Divide: MoveCcw()\n\
132 <KeyPress>Up: MoveTop()\n\
133 <KeyPress>KP_8: MoveTop()\n\
134 <KeyPress>R8: MoveTop()\n\
135 <KeyPress>Prior: MoveTr()\n\
136 <KeyPress>KP_9: MoveTr()\n\
137 <KeyPress>R9: MoveTr()\n\
138 <KeyPress>Left: MoveLeft()\n\
139 <KeyPress>KP_4: MoveLeft()\n\
140 <KeyPress>R10: MoveLeft()\n\
141 <KeyPress>Begin: MoveCw()\n\
142 <KeyPress>KP_5: MoveCw()\n\
143 <KeyPress>R11: MoveCw()\n\
144 <KeyPress>Right: MoveRight()\n\
145 <KeyPress>KP_6: MoveRight()\n\
146 <KeyPress>R12: MoveRight()\n\
147 <KeyPress>End: MoveBl()\n\
148 <KeyPress>KP_1: MoveBl()\n\
149 <KeyPress>R13: MoveBl()\n\
150 <KeyPress>Down: MoveBottom()\n\
151 <KeyPress>KP_2: MoveBottom()\n\
152 <KeyPress>R14: MoveBottom()\n\
153 <Btn1Down>: Select()\n\
154 <Btn1Up>: Release()\n\
155 <KeyPress>p: Practice()\n\
156 <Btn2Down>(2+): Practice()\n\
157 <Btn2Down>: PracticeMaybe()\n\
158 <KeyPress>r: Randomize()\n\
159 <Btn3Down>(2+): Randomize()\n\
160 <Btn3Down>: RandomizeMaybe()\n\
161 <KeyPress>g: Get()\n\
162 <KeyPress>w: Write()\n\
163 <KeyPress>u: Undo()\n\
164 <KeyPress>s: Solve()\n\
165 <KeyPress>i: Increment()\n\
166 <KeyPress>d: Decrement()\n\
167 <KeyPress>o: Orientize()\n\
168 <KeyPress>2: Period2()\n\
169 <KeyPress>3: Period3()\n\
170 <KeyPress>b: Both()\n\
171 <KeyPress>y: Sticky()";
172
173 static XtActionsRec actionsListPyraminx[] =
174 {
175 {"Quit", (XtActionProc) QuitPyraminx},
176 {"MoveCcw", (XtActionProc) MovePyraminxCcw},
177 {"MoveTop", (XtActionProc) MovePyraminxTop},
178 {"MoveTr", (XtActionProc) MovePyraminxTr},
179 {"MoveLeft", (XtActionProc) MovePyraminxLeft},
180 {"MoveCw", (XtActionProc) MovePyraminxCw},
181 {"MoveRight", (XtActionProc) MovePyraminxRight},
182 {"MoveBl", (XtActionProc) MovePyraminxBl},
183 {"MoveBottom", (XtActionProc) MovePyraminxBottom},
184 {"Select", (XtActionProc) SelectPyraminx},
185 {"Release", (XtActionProc) ReleasePyraminx},
186 {"Practice", (XtActionProc) PracticePyraminx},
187 {"PracticeMaybe", (XtActionProc) PracticePyraminxMaybe},
188 {"Randomize", (XtActionProc) RandomizePyraminx},
189 {"RandomizeMaybe", (XtActionProc) RandomizePyraminxMaybe},
190 {"Get", (XtActionProc) GetPyraminx},
191 {"Write", (XtActionProc) WritePyraminx},
192 {"Undo", (XtActionProc) UndoPyraminx},
193 {"Solve", (XtActionProc) SolvePyraminx},
194 {"Increment", (XtActionProc) IncrementPyraminx},
195 {"Decrement", (XtActionProc) DecrementPyraminx},
196 {"Orientize", (XtActionProc) OrientizePyraminx},
197 {"Period2", (XtActionProc) Period2ModePyraminx},
198 {"Period3", (XtActionProc) Period3ModePyraminx},
199 {"Both", (XtActionProc) BothModePyraminx},
200 {"Sticky", (XtActionProc) StickyModePyraminx}
201 };
202
203 static XtResource resourcesPyraminx[] =
204 {
205 {XtNuserName, XtCUserName, XtRString, sizeof (String),
206 XtOffset(PyraminxWidget, pyraminx.username), XtRString, "nobody"},
207 /* Beware color values are swapped */
208 {XtNfaceColor0, XtCLabel, XtRString, sizeof (String),
209 XtOffset(PyraminxWidget, pyraminx.faceName[0]), XtRString, "Blue"},
210 {XtNfaceColor1, XtCLabel, XtRString, sizeof (String),
211 XtOffset(PyraminxWidget, pyraminx.faceName[1]), XtRString, "Red"},
212 {XtNfaceColor2, XtCLabel, XtRString, sizeof (String),
213 XtOffset(PyraminxWidget, pyraminx.faceName[2]), XtRString, "Yellow"},
214 {XtNfaceColor3, XtCLabel, XtRString, sizeof (String),
215 XtOffset(PyraminxWidget, pyraminx.faceName[3]), XtRString, "Green"},
216 {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
217 XtOffset(PyraminxWidget, pyraminx.foreground), XtRString,
218 XtDefaultForeground},
219 {XtNpieceBorder, XtCColor, XtRPixel, sizeof (Pixel),
220 XtOffset(PyraminxWidget, pyraminx.borderColor), XtRString,
221 XtDefaultForeground},
222 {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
223 XtOffset(PyraminxWidget, core.width), XtRString, "200"},
224 {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
225 XtOffset(PyraminxWidget, core.height), XtRString, "400"},
226 {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
227 XtOffset(PyraminxWidget, pyraminx.mono), XtRString, "FALSE"},
228 {XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
229 XtOffset(PyraminxWidget, pyraminx.reverse), XtRString, "FALSE"},
230 {XtNsize, XtCSize, XtRInt, sizeof (int),
231 XtOffset(PyraminxWidget, pyraminx.size), XtRString, "3"}, /*DEFAULTTETRAS */
232 {XtNsticky, XtCSticky, XtRBoolean, sizeof (Boolean),
233 XtOffset(PyraminxWidget, pyraminx.sticky), XtRString, "FALSE"},
234 {XtNmode, XtCMode, XtRInt, sizeof (int),
235 XtOffset(PyraminxWidget, pyraminx.mode), XtRString, "3"}, /*DEFAULTMODE */
236 {XtNorient, XtCOrient, XtRBoolean, sizeof (Boolean),
237 XtOffset(PyraminxWidget, pyraminx.orient), XtRString,
238 "FALSE"}, /*DEFAULTORIENT */
239 {XtNpractice, XtCPractice, XtRBoolean, sizeof (Boolean),
240 XtOffset(PyraminxWidget, pyraminx.practice), XtRString,
241 "FALSE"}, /*DEFAULTPRACTICE */
242 {XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
243 XtOffset(PyraminxWidget, pyraminx.started), XtRString, "FALSE"},
244 {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
245 XtOffset(PyraminxWidget, pyraminx.select), XtRCallback, NULL}
246 };
247
248 PyraminxClassRec pyraminxClassRec =
249 {
250 {
251 (WidgetClass) & widgetClassRec, /* superclass */
252 "Pyraminx", /* class name */
253 sizeof (PyraminxRec), /* widget size */
254 NULL, /* class initialize */
255 NULL, /* class part initialize */
256 FALSE, /* class inited */
257 (XtInitProc) InitializePyraminx, /* initialize */
258 NULL, /* initialize hook */
259 XtInheritRealize, /* realize */
260 actionsListPyraminx, /* actions */
261 XtNumber(actionsListPyraminx), /* num actions */
262 resourcesPyraminx, /* resources */
263 XtNumber(resourcesPyraminx), /* num resources */
264 NULLQUARK, /* xrm class */
265 TRUE, /* compress motion */
266 TRUE, /* compress exposure */
267 TRUE, /* compress enterleave */
268 TRUE, /* visible interest */
269 (XtWidgetProc) DestroyPyraminx, /* destroy */
270 (XtWidgetProc) ResizePyraminx, /* resize */
271 (XtExposeProc) ExposePyraminx, /* expose */
272 (XtSetValuesFunc) SetValuesPyraminx, /* set values */
273 NULL, /* set values hook */
274 XtInheritSetValuesAlmost, /* set values almost */
275 NULL, /* get values hook */
276 NULL, /* accept focus */
277 XtVersion, /* version */
278 NULL, /* callback private */
279 defaultTranslationsPyraminx, /* tm table */
280 NULL, /* query geometry */
281 NULL, /* display accelerator */
282 NULL /* extension */
283 },
284 {
285 0 /* ignore */
286 }
287 };
288
289 WidgetClass pyraminxWidgetClass = (WidgetClass) & pyraminxClassRec;
290
291 typedef struct _RowNextP3 {
292 int viewChanged, face, direction, reverse;
293 } RowNextP3;
294 static PyraminxLoc slideNextRowP2[MAXSIDES][3] =
295 {
296 {
297 {2, 0},
298 {1, 3},
299 {2, 3}},
300 {
301 {2, 0},
302 {0, 3},
303 {2, 3}}
304 };
305 static RowNextP3 slideNextRowP3[MAXSIDES][MAXORIENT] =
306 {
307 {
308 {TRUE, UP, TR, FALSE},
309 {TRUE, UP, TOP, FALSE},
310 {FALSE, UP, BOTTOM, TRUE},
311 {FALSE, UP, RIGHT, TRUE},
312 {TRUE, DOWN, RIGHT, TRUE},
313 {TRUE, DOWN, TR, TRUE}
314 },
315 {
316 {FALSE, DOWN, LEFT, TRUE},
317 {TRUE, UP, LEFT, TRUE},
318 {TRUE, UP, BL, TRUE},
319 {TRUE, DOWN, BL, FALSE},
320 {TRUE, DOWN, BOTTOM, FALSE},
321 {FALSE, DOWN, TOP, TRUE}
322 }
323 };
324 static int rotOrientRowP3[3][MAXORIENT] =
325 /* current orient, rotation */
326 {
327 {1, 5, 1, 5, 4, 2},
328 {2, 0, 2, 0, 5, 3},
329 {3, 1, 3, 1, 0, 4}
330 };
331
332 static XPoint triangleUnit[MAXSIDES][4] =
333 {
334 {
335 {0, 2},
336 {1, 0},
337 {-1, 1},
338 {0, -1}},
339 {
340 {1, 3},
341 {-1, 0},
342 {1, -1},
343 {0, 1}}
344 };
345 static XPoint triangleList[MAXSIDES][4], letterList[MAXSIDES], offsetList[MAXSIDES];
346
347 static void
InitializePyraminx(Widget request,Widget renew)348 InitializePyraminx(Widget request, Widget renew)
349 {
350 PyraminxWidget w = (PyraminxWidget) renew;
351 int face, orient, side;
352
353 for (face = 0; face < MAXFACES; face++)
354 w->pyraminx.tetraLoc[face] = NULL;
355 for (orient = 0; orient < 3; orient++)
356 for (side = 0; side < MAXSIDES; side++)
357 w->pyraminx.rowLoc[orient][side] = NULL;
358 for (side = 0; side < MAXSIDES; side++)
359 w->pyraminx.faceLoc[side] = NULL;
360 CheckPolyhedrons(w);
361 InitMoves();
362 ResetPolyhedrons(w);
363 (void) SRAND(getpid());
364 w->pyraminx.depth = DefaultDepthOfScreen(XtScreen(w));
365 SetAllColors(w, True);
366 ResizePyraminx(w);
367 }
368
369 static void
DestroyPyraminx(Widget old)370 DestroyPyraminx(Widget old)
371 {
372 PyraminxWidget w = (PyraminxWidget) old;
373 int face;
374
375 for (face = 0; face < MAXFACES; face++)
376 XtReleaseGC(old, w->pyraminx.faceGC[face]);
377 XtReleaseGC(old, w->pyraminx.borderGC);
378 XtReleaseGC(old, w->pyraminx.puzzleGC);
379 XtReleaseGC(old, w->pyraminx.inverseGC);
380 XtRemoveCallbacks(old, XtNselectCallback, w->pyraminx.select);
381 }
382
383 static void
ResizePyraminx(PyraminxWidget w)384 ResizePyraminx(PyraminxWidget w)
385 {
386 int tempLength;
387
388 w->pyraminx.delta = 4;
389 w->pyraminx.vertical = (w->core.height >= w->core.width);
390 if (w->pyraminx.vertical)
391 tempLength = MIN(w->core.height / 2, w->core.width);
392 else
393 tempLength = MIN(w->core.height, w->core.width / 2);
394 w->pyraminx.tetraLength = MAX((tempLength - w->pyraminx.delta + 1) /
395 w->pyraminx.size, 0);
396 w->pyraminx.faceLength = w->pyraminx.size * w->pyraminx.tetraLength;
397 w->pyraminx.viewLength = w->pyraminx.faceLength + w->pyraminx.delta + 3;
398 if (w->pyraminx.vertical) {
399 w->pyraminx.puzzleSize.x = w->pyraminx.viewLength - 1;
400 w->pyraminx.puzzleSize.y = 2 * w->pyraminx.viewLength -
401 w->pyraminx.delta - 2;
402 } else {
403 w->pyraminx.puzzleSize.x = 2 * w->pyraminx.viewLength -
404 w->pyraminx.delta - 2;
405 w->pyraminx.puzzleSize.y = w->pyraminx.viewLength - 1;
406 }
407 w->pyraminx.puzzleOffset.x = ((int) w->core.width -
408 w->pyraminx.puzzleSize.x) / 2;
409 w->pyraminx.puzzleOffset.y = ((int) w->core.height -
410 w->pyraminx.puzzleSize.y) / 2;
411 ResizePolyhedrons(w);
412 }
413
414 static void
ExposePyraminx(Widget renew,XEvent * event,Region region)415 ExposePyraminx(Widget renew, XEvent * event, Region region)
416 {
417 PyraminxWidget w = (PyraminxWidget) renew;
418
419 if (w->core.visible) {
420 if (w->pyraminx.reverse)
421 XFillRectangle(XtDisplay(w), XtWindow(w),
422 w->pyraminx.inverseGC, 0, 0, w->core.width, w->core.height);
423 DrawFrame(w, w->pyraminx.puzzleGC);
424 DrawAllPolyhedrons(w);
425 }
426 }
427
428 static Boolean
SetValuesPyraminx(Widget current,Widget request,Widget renew)429 SetValuesPyraminx(Widget current, Widget request, Widget renew)
430 {
431 PyraminxWidget c = (PyraminxWidget) current, w = (PyraminxWidget) renew;
432 Boolean redraw = False, setColors = False;
433 int face;
434
435 CheckPolyhedrons(w);
436 for (face = 0; face < MAXFACES; face++) {
437 if (strcmp(w->pyraminx.faceName[face], c->pyraminx.faceName[face])) {
438 setColors = True;
439 break;
440 }
441 }
442 if (w->core.background_pixel != c->core.background_pixel ||
443 w->pyraminx.foreground != c->pyraminx.foreground ||
444 w->pyraminx.borderColor != c->pyraminx.borderColor ||
445 w->pyraminx.reverse != c->pyraminx.reverse ||
446 w->pyraminx.mono != c->pyraminx.mono ||
447 setColors) {
448 SetAllColors(w, False);
449 redraw = True;
450 }
451 if (w->pyraminx.orient != c->pyraminx.orient) {
452 ResetPolyhedrons(w);
453 redraw = True;
454 } else if (w->pyraminx.practice != c->pyraminx.practice) {
455 ResetPolyhedrons(w);
456 redraw = True;
457 }
458 if (w->pyraminx.size != c->pyraminx.size ||
459 w->pyraminx.mode != c->pyraminx.mode ||
460 w->pyraminx.sticky != c->pyraminx.sticky) {
461 ResetPolyhedrons(w);
462 ResizePyraminx(w);
463 redraw = True;
464 }
465 if (w->pyraminx.tetraLength != c->pyraminx.tetraLength) {
466 ResizePyraminx(w);
467 redraw = True;
468 }
469 return (redraw);
470 }
471
472 static void
QuitPyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)473 QuitPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
474 {
475 XtCloseDisplay(XtDisplay(w));
476 exit(0);
477 }
478
479 static void
SelectPyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)480 SelectPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
481 {
482 int control;
483 CRD crd;
484
485 if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
486 &(w->pyraminx.currentFace), &crd)) {
487 control = (int) (event->xkey.state & ControlMask);
488 w->pyraminx.currentPosition = ToPosition(w, crd);
489 if (control || w->pyraminx.practice || !CheckSolved(w))
490 DrawTriangle(w, w->pyraminx.currentFace, w->pyraminx.currentPosition,
491 TRUE);
492 } else
493 w->pyraminx.currentFace = -1;
494 }
495
496 static void
ReleasePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)497 ReleasePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
498 {
499 int shift, control, style, face, count = -1, direction = 0;
500 CRD crd;
501 pyraminxCallbackStruct cb;
502
503 if (w->pyraminx.currentFace == -1)
504 return;
505 DrawTriangle(w, w->pyraminx.currentFace, w->pyraminx.currentPosition,
506 FALSE);
507 shift = (int) (event->xbutton.state & (ShiftMask | LockMask));
508 control = (int) (event->xkey.state & ControlMask);
509 if (!control && !w->pyraminx.practice && CheckSolved(w))
510 MoveNoPolyhedrons(w);
511 else if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
512 &face, &crd)) {
513 control = (control) ? 1 : 0;
514 if (w->pyraminx.mode != BOTH) {
515 if (control && shift)
516 style = (w->pyraminx.mode == PERIOD3) ? PERIOD2 : PERIOD3;
517 else
518 style = (w->pyraminx.mode == PERIOD2) ? PERIOD2 : PERIOD3;
519 } else
520 style = (shift) ? PERIOD3 : PERIOD2;
521 if (face == w->pyraminx.currentFace)
522 count = CheckMoveDir(w, ToCRD(w, face, w->pyraminx.currentPosition),
523 crd, face, &direction);
524 if (count == 1) {
525 NarrowSelection(w, style, &face, &crd, &direction);
526 MovePyraminx(w, face, w->pyraminx.currentPosition, direction, style,
527 control);
528 if (!control && CheckSolved(w)) {
529 cb.reason = PYRAMINX_SOLVED;
530 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
531 }
532 } else if (count == 2) {
533 cb.reason = PYRAMINX_AMBIGUOUS;
534 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
535 } else if (count == 0)
536 MoveNoPolyhedrons(w);
537 }
538 }
539
540 static void
PracticePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)541 PracticePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
542 {
543 PracticePolyhedrons(w);
544 }
545
546 static void
PracticePyraminxMaybe(PyraminxWidget w,XEvent * event,char ** args,int nArgs)547 PracticePyraminxMaybe(PyraminxWidget w, XEvent * event, char **args, int nArgs)
548 {
549 if (!w->pyraminx.started)
550 PracticePolyhedrons(w);
551 }
552
553 static void
RandomizePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)554 RandomizePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
555 {
556 RandomizePolyhedrons(w);
557 }
558
559 static void
RandomizePyraminxMaybe(PyraminxWidget w,XEvent * event,char ** args,int nArgs)560 RandomizePyraminxMaybe(PyraminxWidget w, XEvent * event, char **args, int nArgs)
561 {
562 if (!w->pyraminx.started)
563 RandomizePolyhedrons(w);
564 }
565
566 static void
GetPyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)567 GetPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
568 {
569 FILE *fp;
570 char c;
571 int i, size, mode, sticky, orient, practice, moves;
572 pyraminxCallbackStruct cb;
573
574 if ((fp = fopen(DATAFILE, "r")) == NULL)
575 (void) printf("Can not read %s for a get.\n", DATAFILE);
576 else {
577 FlushMoves(w);
578 while ((c = getc(fp)) != EOF && c != SYMBOL);
579 (void) fscanf(fp, "%d", &size);
580 if (size >= MINTETRAS) {
581 for (i = w->pyraminx.size; i < size; i++) {
582 cb.reason = PYRAMINX_INC;
583 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
584 }
585 for (i = w->pyraminx.size; i > size; i--) {
586 cb.reason = PYRAMINX_DEC;
587 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
588 }
589 } else
590 (void) printf("%s corrupted: size %d should be between %d and MAXINT\n",
591 DATAFILE, size, MINTETRAS);
592 while ((c = getc(fp)) != EOF && c != SYMBOL);
593 (void) fscanf(fp, "%d", &mode);
594 if (mode >= PERIOD2 && mode <= BOTH)
595 switch (mode) {
596 case PERIOD2:
597 cb.reason = PYRAMINX_PERIOD2;
598 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
599 break;
600 case PERIOD3:
601 cb.reason = PYRAMINX_PERIOD3;
602 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
603 break;
604 case BOTH:
605 cb.reason = PYRAMINX_BOTH;
606 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
607 } else
608 (void) printf("%s corrupted: mode %d should be between %d and %d\n",
609 DATAFILE, mode, PERIOD2, BOTH);
610 while ((c = getc(fp)) != EOF && c != SYMBOL);
611 (void) fscanf(fp, "%d", &sticky);
612 if (w->pyraminx.sticky != (Boolean) sticky) {
613 cb.reason = PYRAMINX_STICKY;
614 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
615 }
616 while ((c = getc(fp)) != EOF && c != SYMBOL);
617 (void) fscanf(fp, "%d", &orient);
618 if (w->pyraminx.orient != (Boolean) orient) {
619 cb.reason = PYRAMINX_ORIENT;
620 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
621 }
622 while ((c = getc(fp)) != EOF && c != SYMBOL);
623 (void) fscanf(fp, "%d", &practice);
624 if (w->pyraminx.practice != (Boolean) practice) {
625 cb.reason = PYRAMINX_PRACTICE;
626 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
627 }
628 while ((c = getc(fp)) != EOF && c != SYMBOL);
629 (void) fscanf(fp, "%d", &moves);
630 ScanStartPosition(fp, w);
631 cb.reason = PYRAMINX_RESTORE;
632 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
633 SetStartPosition(w);
634 ScanMoves(fp, w, moves);
635 (void) fclose(fp);
636 (void) printf("%s: size %d, mode %d, sticky %d, orient %d",
637 DATAFILE, size, mode, sticky, orient);
638 (void) printf(", practice %d, moves %d.\n", practice, moves);
639 }
640 }
641
642 static void
WritePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)643 WritePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
644 {
645 FILE *fp;
646
647 if ((fp = fopen(DATAFILE, "w")) == NULL)
648 (void) printf("Can not write to %s.\n", DATAFILE);
649 else {
650 (void) fprintf(fp, "size%c %d\n", SYMBOL, w->pyraminx.size);
651 (void) fprintf(fp, "mode%c %d\n", SYMBOL, w->pyraminx.mode);
652 (void) fprintf(fp, "sticky%c %d\n", SYMBOL, (w->pyraminx.sticky) ? 1 : 0);
653 (void) fprintf(fp, "orient%c %d\n", SYMBOL, (w->pyraminx.orient) ? 1 : 0);
654 (void) fprintf(fp, "practice%c %d\n", SYMBOL,
655 (w->pyraminx.practice) ? 1 : 0);
656 (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
657 PrintStartPosition(fp, w);
658 PrintMoves(fp);
659 (void) fclose(fp);
660 (void) printf("Saved to %s.\n", DATAFILE);
661 }
662 }
663
664 static void
UndoPyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)665 UndoPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
666 {
667 if (MadeMoves()) {
668 int face, position, direction, style, control;
669
670 GetMove(&face, &position, &direction, &style, &control);
671 direction = (direction < MAXORIENT) ? (direction + MAXORIENT / 2) %
672 MAXORIENT : 3 * MAXORIENT - direction;
673 if (control)
674 MoveControlCb(w, face, direction, style);
675 else {
676 pyraminxCallbackStruct cb;
677
678 MovePolyhedrons(w, face, ToCRD(w, face, position), direction, style);
679 cb.reason = PYRAMINX_UNDO;
680 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
681 }
682 }
683 }
684
685 static void
SolvePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)686 SolvePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
687 {
688 #if 0
689 SolvePolyhedrons(w); /* Sorry, this is not implemented */
690 #endif
691 }
692
693 static void
IncrementPyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)694 IncrementPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
695 {
696 pyraminxCallbackStruct cb;
697
698 cb.reason = PYRAMINX_INC;
699 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
700 }
701
702 static void
DecrementPyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)703 DecrementPyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
704 {
705 pyraminxCallbackStruct cb;
706
707 if (w->pyraminx.size <= MINTETRAS)
708 return;
709 cb.reason = PYRAMINX_DEC;
710 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
711 }
712
713 static void
OrientizePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)714 OrientizePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
715 {
716 pyraminxCallbackStruct cb;
717
718 cb.reason = PYRAMINX_ORIENT;
719 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
720 }
721
722 static void
Period2ModePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)723 Period2ModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
724 {
725 pyraminxCallbackStruct cb;
726
727 cb.reason = PYRAMINX_PERIOD2;
728 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
729 }
730
731 static void
Period3ModePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)732 Period3ModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
733 {
734 pyraminxCallbackStruct cb;
735
736 cb.reason = PYRAMINX_PERIOD3;
737 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
738 }
739
740 static void
BothModePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)741 BothModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
742 {
743 pyraminxCallbackStruct cb;
744
745 cb.reason = PYRAMINX_BOTH;
746 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
747 }
748
749 static void
StickyModePyraminx(PyraminxWidget w,XEvent * event,char ** args,int nArgs)750 StickyModePyraminx(PyraminxWidget w, XEvent * event, char **args, int nArgs)
751 {
752 pyraminxCallbackStruct cb;
753
754 cb.reason = PYRAMINX_STICKY;
755 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
756 }
757
758 static void
MovePyraminxCcw(PyraminxWidget w,XEvent * event,char ** args,int nArgs)759 MovePyraminxCcw(PyraminxWidget w, XEvent * event, char **args, int nArgs)
760 {
761 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, CCW,
762 (int) (event->xbutton.state & (ShiftMask | LockMask)),
763 (int) (event->xbutton.state & ControlMask));
764 }
765
766 static void
MovePyraminxTop(PyraminxWidget w,XEvent * event,char ** args,int nArgs)767 MovePyraminxTop(PyraminxWidget w, XEvent * event, char **args, int nArgs)
768 {
769 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, TOP,
770 (int) (event->xkey.state & (ShiftMask | LockMask)),
771 (int) (event->xkey.state & ControlMask));
772 }
773
774 static void
MovePyraminxTr(PyraminxWidget w,XEvent * event,char ** args,int nArgs)775 MovePyraminxTr(PyraminxWidget w, XEvent * event, char **args, int nArgs)
776 {
777 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, TR,
778 (int) (event->xkey.state & (ShiftMask | LockMask)),
779 (int) (event->xkey.state & ControlMask));
780 }
781
782 static void
MovePyraminxLeft(PyraminxWidget w,XEvent * event,char ** args,int nArgs)783 MovePyraminxLeft(PyraminxWidget w, XEvent * event, char **args, int nArgs)
784 {
785 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, LEFT,
786 (int) (event->xkey.state & (ShiftMask | LockMask)),
787 (int) (event->xkey.state & ControlMask));
788 }
789
790 static void
MovePyraminxCw(PyraminxWidget w,XEvent * event,char ** args,int nArgs)791 MovePyraminxCw(PyraminxWidget w, XEvent * event, char **args, int nArgs)
792 {
793 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, CW,
794 (int) (event->xkey.state & (ShiftMask | LockMask)),
795 (int) (event->xkey.state & ControlMask));
796 }
797
798 static void
MovePyraminxRight(PyraminxWidget w,XEvent * event,char ** args,int nArgs)799 MovePyraminxRight(PyraminxWidget w, XEvent * event, char **args, int nArgs)
800 {
801 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, RIGHT,
802 (int) (event->xkey.state & (ShiftMask | LockMask)),
803 (int) (event->xkey.state & ControlMask));
804 }
805
806 static void
MovePyraminxBl(PyraminxWidget w,XEvent * event,char ** args,int nArgs)807 MovePyraminxBl(PyraminxWidget w, XEvent * event, char **args, int nArgs)
808 {
809 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, BL,
810 (int) (event->xkey.state & (ShiftMask | LockMask)),
811 (int) (event->xkey.state & ControlMask));
812 }
813
814 static void
MovePyraminxBottom(PyraminxWidget w,XEvent * event,char ** args,int nArgs)815 MovePyraminxBottom(PyraminxWidget w, XEvent * event, char **args, int nArgs)
816 {
817 MovePyraminxInput(w, event->xbutton.x, event->xbutton.y, BOTTOM,
818 (int) (event->xkey.state & (ShiftMask | LockMask)),
819 (int) (event->xkey.state & ControlMask));
820 }
821
822 static void
MovePyraminxInput(PyraminxWidget w,int x,int y,int direction,int shift,int control)823 MovePyraminxInput(PyraminxWidget w, int x, int y, int direction, int shift, int control)
824 {
825 int style, face;
826 CRD crd;
827
828 if (w->pyraminx.mode != BOTH) {
829 if (control && shift)
830 style = (w->pyraminx.mode == PERIOD3) ? PERIOD2 : PERIOD3;
831 else
832 style = (w->pyraminx.mode == PERIOD2) ? PERIOD2 : PERIOD3;
833 } else
834 style = (shift) ? PERIOD3 : PERIOD2;
835 if (!w->pyraminx.practice && !control && CheckSolved(w)) {
836 MoveNoPolyhedrons(w);
837 return;
838 }
839 if (!PositionPolyhedrons(w, x, y, style, &face, &crd, &direction))
840 return;
841 control = (control) ? 1 : 0;
842 MovePyraminx(w, face, ToPosition(w, crd), direction, style, control);
843 if (!control && CheckSolved(w)) {
844 pyraminxCallbackStruct cb;
845
846 cb.reason = PYRAMINX_SOLVED;
847 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
848 }
849 }
850
851 void
MovePyraminx(PyraminxWidget w,int face,int position,int direction,int style,int control)852 MovePyraminx(PyraminxWidget w, int face, int position, int direction, int style, int control)
853 {
854 if (control)
855 MoveControlCb(w, face, direction, style);
856 else {
857 pyraminxCallbackStruct cb;
858
859 MovePolyhedrons(w, face, ToCRD(w, face, position), direction, style);
860 cb.reason = PYRAMINX_MOVED;
861 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
862 }
863 PutMove(face, position, direction, style, control);
864 }
865
866 static void
SetAllColors(PyraminxWidget w,Boolean init)867 SetAllColors(PyraminxWidget w, Boolean init)
868 {
869 XGCValues values;
870 XtGCMask valueMask;
871 int face;
872
873 valueMask = GCForeground | GCBackground;
874
875 if (w->pyraminx.reverse) {
876 values.background = w->core.background_pixel;
877 values.foreground = w->pyraminx.foreground;
878 } else {
879 values.foreground = w->core.background_pixel;
880 values.background = w->pyraminx.foreground;
881 }
882 if (!init)
883 XtReleaseGC((Widget) w, w->pyraminx.inverseGC);
884 w->pyraminx.inverseGC = XtGetGC((Widget) w, valueMask, &values);
885 if (w->pyraminx.reverse) {
886 values.background = w->pyraminx.foreground;
887 values.foreground = w->core.background_pixel;
888 } else {
889 values.foreground = w->pyraminx.foreground;
890 values.background = w->core.background_pixel;
891 }
892 if (!init)
893 XtReleaseGC((Widget) w, w->pyraminx.puzzleGC);
894 w->pyraminx.puzzleGC = XtGetGC((Widget) w, valueMask, &values);
895 if (w->pyraminx.depth < 2 || w->pyraminx.mono) {
896 if (w->pyraminx.reverse) {
897 values.background = w->pyraminx.foreground;
898 values.foreground = w->core.background_pixel;
899 } else {
900 values.foreground = w->pyraminx.foreground;
901 values.background = w->core.background_pixel;
902 }
903 } else {
904 values.foreground = w->pyraminx.borderColor;
905 values.background = w->core.background_pixel;
906 }
907 if (!init)
908 XtReleaseGC((Widget) w, w->pyraminx.borderGC);
909 w->pyraminx.borderGC = XtGetGC((Widget) w, valueMask, &values);
910 for (face = 0; face < MAXFACES; face++)
911 GetColor(w, face, init);
912 }
913
914 static void
GetColor(PyraminxWidget w,int face,Boolean init)915 GetColor(PyraminxWidget w, int face, Boolean init)
916 {
917 XGCValues values;
918 XtGCMask valueMask;
919 XColor colorCell, rgb;
920
921 valueMask = GCForeground | GCBackground;
922 if (w->pyraminx.reverse) {
923 values.background = w->pyraminx.foreground;
924 } else {
925 values.background = w->core.background_pixel;
926 }
927 if (w->pyraminx.depth > 1 && !w->pyraminx.mono) {
928 if (XAllocNamedColor(XtDisplay(w),
929 DefaultColormap(XtDisplay(w), XtWindow(w)),
930 w->pyraminx.faceName[face], &colorCell, &rgb)) {
931 values.foreground = w->pyraminx.faceColor[face] = colorCell.pixel;
932 if (!init)
933 XtReleaseGC((Widget) w, w->pyraminx.faceGC[face]);
934 w->pyraminx.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
935 return;
936 } else {
937 char buf[121];
938
939 (void) sprintf(buf, "Color name \"%s\" is not defined",
940 w->pyraminx.faceName[face]);
941 XtWarning(buf);
942 }
943 }
944 if (w->pyraminx.reverse) {
945 values.background = w->pyraminx.foreground;
946 values.foreground = w->core.background_pixel;
947 } else {
948 values.background = w->core.background_pixel;
949 values.foreground = w->pyraminx.foreground;
950 }
951 if (!init)
952 XtReleaseGC((Widget) w, w->pyraminx.faceGC[face]);
953 w->pyraminx.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
954 }
955
956 static void
MoveControlCb(PyraminxWidget w,int face,int direction,int style)957 MoveControlCb(PyraminxWidget w, int face, int direction, int style)
958 {
959 pyraminxCallbackStruct cb;
960 int i, faceOnView;
961 CRD crd;
962
963 faceOnView = face % MAXSIDES;
964 if (w->pyraminx.sticky) {
965 if (style == PERIOD2)
966 for (i = 0; i < 3; i++) {
967 if (direction == TR || direction == BL) {
968 crd.column = 0;
969 crd.row = 3 * i / 2;
970 crd.diagonal = crd.row + i % 2;
971 MovePolyhedrons(w, face, crd, direction, style);
972 } else {
973 crd.column = 3 * i / 2;
974 crd.row = 3 * i / 2;
975 crd.diagonal = crd.row + crd.column;
976 MovePolyhedrons(w, face, crd, direction, style);
977 }
978 cb.reason = PYRAMINX_CONTROL;
979 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
980 } else /* (style == PERIOD3) */
981 for (i = 0; i < 2; i++) {
982 if (direction == TR || direction == BL) {
983 crd.column = 1 + faceOnView;
984 crd.row = 1 + faceOnView;
985 crd.diagonal = crd.row + crd.column + i;
986 MovePolyhedrons(w, face, crd, direction, style);
987 } else {
988 crd.column = i + 2 * faceOnView;
989 crd.row = i + 2 * faceOnView;
990 crd.diagonal = crd.row + crd.column + faceOnView;
991 MovePolyhedrons(w, face, crd, direction, style);
992 }
993 cb.reason = PYRAMINX_CONTROL;
994 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
995 }
996 } else {
997 for (i = 0; i < w->pyraminx.size; i++) {
998 if (direction == TR || direction == BL) {
999 if (style == PERIOD2) {
1000 crd.column = 0;
1001 crd.row = i;
1002 crd.diagonal = crd.row;
1003 MovePolyhedrons(w, face, crd, direction, style);
1004 } else {
1005 crd.column = faceOnView * (w->pyraminx.size - 1);
1006 crd.row = i;
1007 crd.diagonal = crd.column + crd.row + faceOnView;
1008 MovePolyhedrons(w, face, crd, direction, style);
1009 }
1010 } else {
1011 crd.column = i;
1012 crd.row = w->pyraminx.size - 1 - i;
1013 crd.diagonal = crd.column + crd.row + faceOnView;
1014 MovePolyhedrons(w, face, crd, direction, style);
1015 }
1016 cb.reason = PYRAMINX_CONTROL;
1017 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1018 }
1019 }
1020 }
1021
1022 static void
CheckPolyhedrons(PyraminxWidget w)1023 CheckPolyhedrons(PyraminxWidget w)
1024 {
1025 if (w->pyraminx.size < MINTETRAS) {
1026 char buf[121];
1027
1028 (void) sprintf(buf,
1029 "Number of Tetras on edge out of bounds, use %d..MAXINT",
1030 MINTETRAS);
1031 XtWarning(buf);
1032 w->pyraminx.size = DEFAULTTETRAS;
1033 }
1034 if (w->pyraminx.mode < PERIOD2 || w->pyraminx.mode > BOTH) {
1035 XtWarning("Mode is in error, use 2 for Period2, 3 for Period3, 4 for Both");
1036 w->pyraminx.mode = DEFAULTMODE;
1037 }
1038 }
1039
1040 static void
ResetPolyhedrons(PyraminxWidget w)1041 ResetPolyhedrons(PyraminxWidget w)
1042 {
1043 int face, position, orient, side;
1044
1045 w->pyraminx.sizeSize = w->pyraminx.size * w->pyraminx.size;
1046 for (face = 0; face < MAXFACES; face++) {
1047 if (w->pyraminx.tetraLoc[face])
1048 (void) free((void *) w->pyraminx.tetraLoc[face]);
1049 if (!(w->pyraminx.tetraLoc[face] = (PyraminxLoc *)
1050 malloc(sizeof (PyraminxLoc) * w->pyraminx.sizeSize)))
1051 XtError("Not enough memory, exiting.");
1052 if (startLoc[face])
1053 (void) free((void *) startLoc[face]);
1054 if (!(startLoc[face] = (PyraminxLoc *)
1055 malloc(sizeof (PyraminxLoc) * w->pyraminx.sizeSize)))
1056 XtError("Not enough memory, exiting.");
1057 }
1058 for (orient = 0; orient < 3; orient++)
1059 for (side = 0; side < MAXSIDES; side++) {
1060 if (w->pyraminx.rowLoc[orient][side])
1061 (void) free((void *) w->pyraminx.rowLoc[orient][side]);
1062 if (!(w->pyraminx.rowLoc[orient][side] = (PyraminxLoc *)
1063 malloc(sizeof (PyraminxLoc) * w->pyraminx.size)))
1064 XtError("Not enough memory, exiting.");
1065 }
1066 for (side = 0; side < MAXSIDES; side++) {
1067 if (w->pyraminx.faceLoc)
1068 (void) free((void *) w->pyraminx.faceLoc[side]);
1069 if (!(w->pyraminx.faceLoc[side] = (PyraminxLoc *)
1070 malloc(sizeof (PyraminxLoc) * w->pyraminx.sizeSize)))
1071 XtError("Not enough memory, exiting.");
1072 }
1073 for (face = 0; face < MAXFACES; face++)
1074 for (position = 0; position < w->pyraminx.sizeSize; position++) {
1075 w->pyraminx.tetraLoc[face][position].face = face;
1076 w->pyraminx.tetraLoc[face][position].rotation = TOP;
1077 }
1078 FlushMoves(w);
1079 w->pyraminx.started = False;
1080 }
1081
1082 static void
ResizePolyhedrons(PyraminxWidget w)1083 ResizePolyhedrons(PyraminxWidget w)
1084 {
1085 int i, j;
1086
1087 w->pyraminx.tetraLength = w->pyraminx.faceLength / w->pyraminx.size -
1088 w->pyraminx.delta - 1;
1089 for (i = 0; i <= 3; i++)
1090 for (j = 0; j < MAXSIDES; j++) {
1091 triangleList[j][i].x = triangleUnit[j][i].x *
1092 w->pyraminx.tetraLength;
1093 triangleList[j][i].y = triangleUnit[j][i].y *
1094 w->pyraminx.tetraLength;
1095 }
1096 offsetList[DOWN].x = 0;
1097 offsetList[UP].x = w->pyraminx.tetraLength + 2;
1098 offsetList[DOWN].y = 0;
1099 offsetList[UP].y = w->pyraminx.tetraLength + 2;
1100 letterList[DOWN].x = w->pyraminx.tetraLength / 4 - 3;
1101 letterList[UP].x = 3 * w->pyraminx.tetraLength / 4;
1102 letterList[DOWN].y = w->pyraminx.tetraLength / 4 + 5;
1103 letterList[UP].y = 3 * w->pyraminx.tetraLength / 4 + 5;
1104 w->pyraminx.sideOffset = 3 * w->pyraminx.size / 4;
1105 w->pyraminx.orientLineLength = w->pyraminx.tetraLength / 4;
1106 w->pyraminx.orientDiagLength = MAX(w->pyraminx.orientLineLength - 3, 0);
1107 }
1108
1109 static Boolean
SelectPolyhedrons(PyraminxWidget w,int x,int y,int * face,CRD * crd)1110 SelectPolyhedrons(PyraminxWidget w, int x, int y, int *face, CRD * crd)
1111 {
1112 int offset, modI, modJ, side, view;
1113
1114 x -= w->pyraminx.puzzleOffset.x;
1115 y -= w->pyraminx.puzzleOffset.y;
1116 if (w->pyraminx.vertical && y > w->pyraminx.viewLength - 1) {
1117 y -= (w->pyraminx.viewLength - 1);
1118 view = DOWN;
1119 } else if (!w->pyraminx.vertical && x > w->pyraminx.viewLength - 1) {
1120 x -= (w->pyraminx.viewLength - 1);
1121 view = DOWN;
1122 } else
1123 view = UP;
1124 if (x <= 0 || y <= 0 ||
1125 x >= w->pyraminx.faceLength + w->pyraminx.delta ||
1126 y >= w->pyraminx.faceLength + w->pyraminx.delta)
1127 return False;
1128 else if (x + y > w->pyraminx.faceLength)
1129 offset = 2 * w->pyraminx.delta + 1;
1130 else
1131 offset = w->pyraminx.delta;
1132 crd->column = (x - offset) / (w->pyraminx.tetraLength + w->pyraminx.delta);
1133 crd->row = (y - offset) / (w->pyraminx.tetraLength + w->pyraminx.delta);
1134 modI = (x - offset) % (w->pyraminx.tetraLength + w->pyraminx.delta);
1135 modJ = (y - offset) % (w->pyraminx.tetraLength + w->pyraminx.delta);
1136 side = (modI + modJ > w->pyraminx.tetraLength + 1);
1137 if (!w->pyraminx.vertical && view == DOWN) {
1138 crd->row = w->pyraminx.size - crd->row - 1;
1139 crd->column = w->pyraminx.size - crd->column - 1;
1140 side = !side;
1141 }
1142 crd->diagonal = crd->row + crd->column + side;
1143 *face = view * MAXSIDES + (crd->diagonal >= w->pyraminx.size);
1144 return True;
1145 }
1146
1147 static void
NarrowSelection(PyraminxWidget w,int style,int * face,CRD * crd,int * direction)1148 NarrowSelection(PyraminxWidget w, int style, int *face, CRD * crd, int *direction)
1149 {
1150 if (!w->pyraminx.vertical && *face >= MAXSIDES && *direction < MAXORIENT)
1151 *direction = (*direction + MAXORIENT / 2) % MAXORIENT;
1152 if (style == PERIOD2) {
1153 if (*direction == CW)
1154 *direction = TR;
1155 else if (*direction == CCW)
1156 *direction = BL;
1157 } else { /* style == PERIOD3 */
1158 if (*direction == CW || *direction == CCW) {
1159 crd->diagonal = w->pyraminx.size - (crd->diagonal < w->pyraminx.size);
1160 *direction = ((*direction == CW && crd->diagonal == w->pyraminx.size) ||
1161 (*direction == CCW && crd->diagonal != w->pyraminx.size))
1162 ? TR : BL;
1163 *face = !(*face % 2) + 2 * (*face / 2);
1164 crd->row = w->pyraminx.size - 1;
1165 crd->column = 0;
1166 }
1167 }
1168 }
1169
1170 static Boolean
PositionPolyhedrons(PyraminxWidget w,int x,int y,int style,int * face,CRD * crd,int * direction)1171 PositionPolyhedrons(PyraminxWidget w, int x, int y, int style, int *face, CRD * crd, int *direction)
1172 {
1173 if (!SelectPolyhedrons(w, x, y, face, crd))
1174 return False;
1175 NarrowSelection(w, style, face, crd, direction);
1176 return True;
1177 }
1178
1179 static void
MoveNoPolyhedrons(PyraminxWidget w)1180 MoveNoPolyhedrons(PyraminxWidget w)
1181 {
1182 pyraminxCallbackStruct cb;
1183
1184 cb.reason = PYRAMINX_ILLEGAL;
1185 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1186 }
1187
1188 static void
PracticePolyhedrons(PyraminxWidget w)1189 PracticePolyhedrons(PyraminxWidget w)
1190 {
1191 pyraminxCallbackStruct cb;
1192
1193 cb.reason = PYRAMINX_PRACTICE;
1194 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1195 }
1196
1197 static void
RandomizePolyhedrons(PyraminxWidget w)1198 RandomizePolyhedrons(PyraminxWidget w)
1199 {
1200 pyraminxCallbackStruct cb;
1201 int randomDirection, face, position, style;
1202 int big = w->pyraminx.sizeSize * 3 + NRAND(2);
1203
1204 if (big > 1000)
1205 big = 1000;
1206 if (w->pyraminx.practice)
1207 PracticePolyhedrons(w);
1208 if (w->pyraminx.sticky)
1209 big /= 3;
1210 cb.reason = PYRAMINX_RESET;
1211 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1212
1213 #ifdef DEBUG
1214 big = 3;
1215 #endif
1216
1217 while (big--) {
1218 face = NRAND(MAXFACES);
1219 if (w->pyraminx.mode == BOTH)
1220 style = NRAND(MAXMODES - 1) + PERIOD2;
1221 else
1222 style = w->pyraminx.mode;
1223 if (w->pyraminx.sticky) {
1224 if (style == PERIOD2) {
1225 if (NRAND(3) == 2) {
1226 position = (NRAND(2)) ? 9 : 6;
1227 randomDirection = (NRAND(2)) ? TR : BL;
1228 } else {
1229 position = (NRAND(2)) ? 6 : 0;
1230 if (NRAND(2))
1231 randomDirection = (NRAND(2)) ? LEFT : RIGHT;
1232 else
1233 randomDirection = (NRAND(2)) ? TOP : BOTTOM;
1234 }
1235 } else { /* style == PERIOD3 */
1236 position = 6;
1237 randomDirection = NRAND(6);
1238 }
1239 } else { /* (!w->pyraminx.sticky) */
1240 randomDirection = NRAND(MAXORIENT);
1241 position = NRAND(w->pyraminx.sizeSize);
1242 if (w->pyraminx.mode == BOTH)
1243 style = NRAND(BOTH);
1244 else
1245 style = w->pyraminx.mode;
1246 }
1247 MovePyraminx(w, face, position, randomDirection, style, FALSE);
1248 cb.reason = PYRAMINX_MOVED;
1249 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1250 }
1251 FlushMoves(w);
1252 cb.reason = PYRAMINX_RANDOMIZE;
1253 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1254 if (CheckSolved(w)) {
1255 cb.reason = PYRAMINX_SOLVED;
1256 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1257 }
1258 }
1259
1260 static void
MovePolyhedrons(PyraminxWidget w,int face,CRD crd,int direction,int style)1261 MovePolyhedrons(PyraminxWidget w, int face, CRD crd, int direction, int style)
1262 {
1263 int view, side;
1264 int newSide, newView, rotate, reverse, h, k, newH, faceOnView,
1265 len;
1266 int newFace, newDirection, bound, l = 0;
1267
1268 view = face / MAXSIDES;
1269 side = crd.diagonal - crd.column - crd.row;
1270 if (style == PERIOD2) {
1271 /* Period 2 Slide rows */
1272 h = Crd(direction, crd.column, crd.row, side);
1273 if (w->pyraminx.sticky && (h % 4 == 1 || h % 4 == 2)) {
1274 bound = TRUE;
1275 l = 0;
1276 if (h % 4 == 2)
1277 h = h - 1;
1278 } else
1279 bound = FALSE;
1280 do {
1281 ReadCRD2(w, view, direction, h, 0);
1282 for (k = 1; k <= 2; k++) {
1283 rotate = slideNextRowP2[side][direction % 3].rotation;
1284 if (direction == TR || direction == BL) {
1285 newView = view;
1286 newSide = !side;
1287 newH = 2 * w->pyraminx.size - 1 - h;
1288 reverse = FALSE;
1289 } else if (!rotate) {
1290 newView = !view;
1291 newSide = side;
1292 newH = h;
1293 reverse = FALSE;
1294 } else { /* rotate == 3 */
1295 newView = !view;
1296 newSide = !side;
1297 newH = w->pyraminx.size - 1 - h;
1298 reverse = TRUE;
1299 }
1300 if (k != 2)
1301 ReadCRD2(w, newView, direction, newH, k);
1302 RotateCRD2(w, rotate, k - 1);
1303 if (reverse == TRUE)
1304 ReverseCRD2(w, k - 1);
1305 WriteCRD2(w, newView, direction, newH, k - 1);
1306 view = newView;
1307 h = newH;
1308 side = newSide;
1309 }
1310 l++;
1311 h++;
1312 } while (bound && l < 2);
1313 } else { /* style == PERIOD3 */
1314 faceOnView = (crd.diagonal >= w->pyraminx.size);
1315 h = Crd(direction, crd.column, crd.row, side);
1316 bound = FALSE;
1317 if (direction == TR || direction == BL) {
1318 if (h == w->pyraminx.size)
1319 RotateFace(w, view, DOWN, (direction == TR) ? CCW : CW);
1320 else if (h == w->pyraminx.size - 1)
1321 RotateFace(w, view, UP, (direction == TR) ? CW : CCW);
1322 else if (w->pyraminx.sticky)
1323 bound = TRUE;
1324 } else if (!crd.column && !faceOnView &&
1325 (direction == TOP || direction == BOTTOM))
1326 RotateFace(w, !view, DOWN,
1327 (direction == TOP || direction == LEFT) ? CCW : CW);
1328 else if (crd.column == w->pyraminx.size - 1 && faceOnView &&
1329 (direction == TOP || direction == BOTTOM))
1330 RotateFace(w, !view, UP,
1331 (direction == BOTTOM || direction == RIGHT) ? CCW : CW);
1332 else if (!crd.row && !faceOnView &&
1333 (direction == RIGHT || direction == LEFT))
1334 RotateFace(w, !view, UP,
1335 (direction == BOTTOM || direction == RIGHT) ? CCW : CW);
1336 else if (crd.row == w->pyraminx.size - 1 && faceOnView &&
1337 (direction == RIGHT || direction == LEFT))
1338 RotateFace(w, !view, DOWN,
1339 (direction == TOP || direction == LEFT) ? CCW : CW);
1340 else if (w->pyraminx.sticky)
1341 bound = TRUE;
1342 /* Slide rows */
1343 if (bound == TRUE) {
1344 l = 0;
1345 if (direction == TR || direction == BL)
1346 h = (faceOnView == UP) ? 0 : w->pyraminx.size + 1;
1347 else
1348 h = (faceOnView == UP) ? 1 : 0;
1349 }
1350 do {
1351 len = Length(w, faceOnView, direction, h);
1352 ReadCRD3(w, view, faceOnView, direction, h, len, 0);
1353 for (k = 1; k <= 3; k++) {
1354 newView = (slideNextRowP3[faceOnView][direction].viewChanged)
1355 ? !view : view;
1356 newFace = !slideNextRowP3[faceOnView][direction].face;
1357 newDirection = slideNextRowP3[faceOnView][direction].direction;
1358 reverse = slideNextRowP3[faceOnView][direction].reverse;
1359 newH = w->pyraminx.size - 1 - h;
1360 if (!faceOnView) {
1361 if (direction == TOP)
1362 newH = w->pyraminx.size + h;
1363 else if (direction == TR)
1364 newH = h;
1365 else
1366 newH = w->pyraminx.size - 1 - h;
1367 } else {
1368 if (direction == TR || direction == RIGHT)
1369 newH = 2 * w->pyraminx.size - 1 - h;
1370 else if (direction == BOTTOM)
1371 newH = h;
1372 else if (direction == BL)
1373 newH = h - w->pyraminx.size;
1374 else
1375 newH = w->pyraminx.size - 1 - h;
1376 }
1377 if (k != 3)
1378 ReadCRD3(w, newView, newFace, newDirection, newH, len, k);
1379 RotateCRD3(w, faceOnView, direction, len, k - 1);
1380 if (reverse == TRUE)
1381 ReverseCRD3(w, len, k - 1);
1382 WriteCRD3(w, newView, newFace, newDirection, newH, len, k - 1);
1383 view = newView;
1384 faceOnView = newFace;
1385 direction = newDirection;
1386 h = newH;
1387 }
1388 h++;
1389 l++;
1390 } while (bound && l < w->pyraminx.size - 1);
1391 }
1392 }
1393
1394 static void
RotateFace(PyraminxWidget w,int view,int faceOnView,int direction)1395 RotateFace(PyraminxWidget w, int view, int faceOnView, int direction)
1396 {
1397 int g, h, side, face, position;
1398 CRD crd;
1399
1400 /* Read Face */
1401 for (g = 0; g < w->pyraminx.size; g++)
1402 for (h = 0; h < w->pyraminx.size - g; h++)
1403 for (side = 0; side < MAXSIDES; side++)
1404 if (g + h + side < w->pyraminx.size) {
1405 if (faceOnView == DOWN) {
1406 crd.column = h;
1407 crd.row = g;
1408 crd.diagonal = h + g + side;
1409 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1410 position = ToPosition(w, crd);
1411 w->pyraminx.faceLoc[side][h + g * w->pyraminx.size] =
1412 w->pyraminx.tetraLoc[face][position];
1413 } else { /* faceOnView == UP */
1414 crd.column = w->pyraminx.size - 1 - h;
1415 crd.row = w->pyraminx.size - 1 - g;
1416 crd.diagonal = crd.column + crd.row + !side;
1417 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1418 position = ToPosition(w, crd);
1419 w->pyraminx.faceLoc[side][h + g * w->pyraminx.size] =
1420 w->pyraminx.tetraLoc[face][position];
1421 }
1422 }
1423 /* Write Face */
1424 if (faceOnView == DOWN) {
1425 for (g = 0; g < w->pyraminx.size; g++)
1426 for (h = 0; h < w->pyraminx.size - g; h++)
1427 for (side = 0; side < MAXSIDES; side++)
1428 if (g + h + side < w->pyraminx.size) {
1429 crd.column = h;
1430 crd.row = g;
1431 crd.diagonal = h + g + side;
1432 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1433 position = ToPosition(w, crd);
1434 if (direction == CCW)
1435 w->pyraminx.tetraLoc[face][position] =
1436 w->pyraminx.faceLoc[side][w->pyraminx.size - 1 - g - h - side +
1437 h * w->pyraminx.size];
1438 else /* direction == CW */
1439 w->pyraminx.tetraLoc[face][position] =
1440 w->pyraminx.faceLoc[side][g +
1441 (w->pyraminx.size - 1 - g - h - side) * w->pyraminx.size];
1442 w->pyraminx.tetraLoc[face][position].rotation =
1443 (direction == CW) ?
1444 (w->pyraminx.tetraLoc[face][position].rotation + 2) %
1445 MAXORIENT :
1446 (w->pyraminx.tetraLoc[face][position].rotation + 4) %
1447 MAXORIENT;
1448 DrawTriangle(w, face, position, FALSE);
1449 }
1450 } else { /* faceOnView == UP */
1451 for (g = w->pyraminx.size - 1; g >= 0; g--)
1452 for (h = w->pyraminx.size - 1; h >= w->pyraminx.size - 1 - g; h--)
1453 for (side = 1; side >= 0; side--)
1454 if (g + h + side >= w->pyraminx.size) {
1455 crd.column = h;
1456 crd.row = g;
1457 crd.diagonal = h + g + side;
1458 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1459 position = ToPosition(w, crd);
1460 if (direction == CCW)
1461 w->pyraminx.tetraLoc[face][position] =
1462 w->pyraminx.faceLoc[!side][g + h - w->pyraminx.size + 1 - !side
1463 + (w->pyraminx.size - 1 - h) * w->pyraminx.size];
1464 else /* (direction == CW) */
1465 w->pyraminx.tetraLoc[face][position] =
1466 w->pyraminx.faceLoc[!side][w->pyraminx.size - 1 - g +
1467 (g + h - w->pyraminx.size + 1 - !side) * w->pyraminx.size];
1468 w->pyraminx.tetraLoc[face][position].rotation =
1469 (direction == CW) ?
1470 (w->pyraminx.tetraLoc[face][position].rotation + 2) %
1471 MAXORIENT :
1472 (w->pyraminx.tetraLoc[face][position].rotation + 4) %
1473 MAXORIENT;
1474 DrawTriangle(w, face, position, FALSE);
1475 }
1476 }
1477 }
1478
1479 static void
ReadCRD2(PyraminxWidget w,int view,int dir,int h,int orient)1480 ReadCRD2(PyraminxWidget w, int view, int dir, int h, int orient)
1481 {
1482 int g, i, j, side, faceOnView, s, face, position;
1483 CRD crd;
1484
1485 if (dir == TOP || dir == BOTTOM)
1486 for (g = 0; g < w->pyraminx.size; g++)
1487 for (side = 0; side < MAXSIDES; side++) {
1488 crd.column = h;
1489 crd.row = g;
1490 crd.diagonal = h + g + side;
1491 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1492 position = ToPosition(w, crd);
1493 w->pyraminx.rowLoc[orient][side][g] =
1494 w->pyraminx.tetraLoc[face][position];
1495 } else if (dir == RIGHT || dir == LEFT)
1496 for (g = 0; g < w->pyraminx.size; g++)
1497 for (side = 0; side < MAXSIDES; side++) {
1498 crd.column = g;
1499 crd.row = h;
1500 crd.diagonal = h + g + side;
1501 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1502 position = ToPosition(w, crd);
1503 w->pyraminx.rowLoc[orient][side][g] =
1504 w->pyraminx.tetraLoc[face][position];
1505 } else { /* dir == TR || dir == BL */
1506 faceOnView = (h < w->pyraminx.size);
1507 i = (faceOnView == UP) ? w->pyraminx.size - 1 : 0;
1508 j = h % w->pyraminx.size;
1509 for (g = 0; g < w->pyraminx.size; g++) {
1510 for (side = 0; side < MAXSIDES; side++) {
1511 s = (side == UP) ? !faceOnView : faceOnView;
1512 crd.column = i;
1513 crd.row = j;
1514 crd.diagonal = i + j + s;
1515 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1516 position = ToPosition(w, crd);
1517 w->pyraminx.rowLoc[orient][side][g] =
1518 w->pyraminx.tetraLoc[face][position];
1519 if (!side) {
1520 if (faceOnView == UP) {
1521 if (j == w->pyraminx.size - 1)
1522 view = !view;
1523 j = (j + 1) % w->pyraminx.size;
1524 } else { /* faceOnView == DOWN */
1525 if (!j)
1526 view = !view;
1527 j = (j - 1 + w->pyraminx.size) % w->pyraminx.size;
1528 }
1529 }
1530 }
1531 i = (faceOnView == UP) ? i - 1 : i + 1;
1532 }
1533 }
1534 }
1535
1536 static void
ReadCRD3(PyraminxWidget w,int view,int faceOnView,int dir,int h,int len,int orient)1537 ReadCRD3(PyraminxWidget w, int view, int faceOnView, int dir, int h, int len, int orient)
1538 {
1539 int g, i, j, side, s, face, position;
1540 CRD crd;
1541
1542 if (dir == TOP || dir == BOTTOM) {
1543 for (g = 0; g <= len; g++)
1544 for (side = 0; side < MAXSIDES; side++)
1545 if (!side || g < len) {
1546 crd.column = h;
1547 crd.row = (faceOnView == UP) ? g : w->pyraminx.size - 1 - g;
1548 crd.diagonal = h + crd.row + ((faceOnView == UP) ? side : !side);
1549 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1550 position = ToPosition(w, crd);
1551 w->pyraminx.rowLoc[orient][side][g] =
1552 w->pyraminx.tetraLoc[face][position];
1553 }
1554 } else if (dir == RIGHT || dir == LEFT) {
1555 for (g = 0; g <= len; g++)
1556 for (side = 0; side < MAXSIDES; side++)
1557 if (!side || g < len) {
1558 crd.column = (faceOnView == UP) ? g : w->pyraminx.size - 1 - g;
1559 crd.row = h;
1560 crd.diagonal = h + crd.column + ((faceOnView == UP) ? side : !side);
1561 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1562 position = ToPosition(w, crd);
1563 w->pyraminx.rowLoc[orient][side][g] =
1564 w->pyraminx.tetraLoc[face][position];
1565 }
1566 } else { /* dir == TR || dir == BL */
1567 i = (faceOnView == DOWN) ? w->pyraminx.size - 1 : 0;
1568 j = h % w->pyraminx.size;
1569 for (g = 0; g <= len; g++) {
1570 for (side = 0; side < MAXSIDES; side++) {
1571 if (!side || g < len) {
1572 s = (side == UP) ? faceOnView : !faceOnView;
1573 crd.column = i;
1574 crd.row = j;
1575 crd.diagonal = i + j + s;
1576 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1577 position = ToPosition(w, crd);
1578 w->pyraminx.rowLoc[orient][side][g] =
1579 w->pyraminx.tetraLoc[face][position];
1580 if (!side)
1581 j = (faceOnView == DOWN) ? j + 1 : j - 1;
1582 }
1583 }
1584 i = (faceOnView == DOWN) ? i - 1 : i + 1;
1585 }
1586 }
1587 }
1588
1589 static void
RotateCRD2(PyraminxWidget w,int rotate,int orient)1590 RotateCRD2(PyraminxWidget w, int rotate, int orient)
1591 {
1592 int g, side;
1593
1594 for (g = 0; g < w->pyraminx.size; g++)
1595 for (side = 0; side < MAXSIDES; side++)
1596 w->pyraminx.rowLoc[orient][side][g].rotation =
1597 (w->pyraminx.rowLoc[orient][side][g].rotation + rotate) % MAXORIENT;
1598 }
1599
1600 static void
RotateCRD3(PyraminxWidget w,int faceOnView,int dir,int len,int orient)1601 RotateCRD3(PyraminxWidget w, int faceOnView, int dir, int len, int orient)
1602 {
1603 int g, side, direction, tetraOrient;
1604
1605 for (g = 0; g <= len; g++)
1606 for (side = 0; side < MAXSIDES; side++)
1607 if (!side || g < len) {
1608 direction = (faceOnView == DOWN) ? (dir + 3) % MAXORIENT : dir;
1609 tetraOrient = w->pyraminx.rowLoc[orient][side][g].rotation;
1610 w->pyraminx.rowLoc[orient][side][g].rotation =
1611 (tetraOrient >= 3) ?
1612 (rotOrientRowP3[tetraOrient - 3][direction] + 3) % MAXORIENT :
1613 rotOrientRowP3[tetraOrient][direction];
1614 }
1615 }
1616
1617 static void
ReverseCRD2(PyraminxWidget w,int orient)1618 ReverseCRD2(PyraminxWidget w, int orient)
1619 {
1620 PyraminxLoc temp;
1621 int g;
1622
1623 for (g = 0; g < w->pyraminx.size; g++) {
1624 temp = w->pyraminx.rowLoc[orient][g % 2][g / 2];
1625 w->pyraminx.rowLoc[orient][g % 2][g / 2] =
1626 w->pyraminx.rowLoc[orient][!(g % 2)][w->pyraminx.size - 1 - g / 2];
1627 w->pyraminx.rowLoc[orient][!(g % 2)][w->pyraminx.size - 1 - g / 2] =
1628 temp;
1629 }
1630 }
1631
1632 static void
ReverseCRD3(PyraminxWidget w,int len,int orient)1633 ReverseCRD3(PyraminxWidget w, int len, int orient)
1634 {
1635 PyraminxLoc temp;
1636 int g;
1637
1638 for (g = 0; g < len; g++) {
1639 temp = w->pyraminx.rowLoc[orient][g % 2][len - ((g + 1) / 2)];
1640 w->pyraminx.rowLoc[orient][g % 2][len - ((g + 1) / 2)] =
1641 w->pyraminx.rowLoc[orient][g % 2][g / 2];
1642 w->pyraminx.rowLoc[orient][g % 2][g / 2] = temp;
1643 }
1644 }
1645
1646 static void
WriteCRD2(PyraminxWidget w,int view,int dir,int h,int orient)1647 WriteCRD2(PyraminxWidget w, int view, int dir, int h, int orient)
1648 {
1649 int g, side, i, j, s, faceOnView, face, position;
1650 CRD crd;
1651
1652 if (dir == TOP || dir == BOTTOM) {
1653 for (g = 0; g < w->pyraminx.size; g++)
1654 for (side = 0; side < MAXSIDES; side++) {
1655 crd.column = h;
1656 crd.row = g;
1657 crd.diagonal = h + g + side;
1658 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1659 position = ToPosition(w, crd);
1660 w->pyraminx.tetraLoc[face][position] =
1661 w->pyraminx.rowLoc[orient][side][g];
1662 DrawTriangle(w,
1663 view * MAXSIDES + (crd.diagonal >= w->pyraminx.size),
1664 ToPosition(w, crd), FALSE);
1665 }
1666 } else if (dir == RIGHT || dir == LEFT) {
1667 for (g = 0; g < w->pyraminx.size; g++)
1668 for (side = 0; side < MAXSIDES; side++) {
1669 crd.column = g;
1670 crd.row = h;
1671 crd.diagonal = h + g + side;
1672 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1673 position = ToPosition(w, crd);
1674 w->pyraminx.tetraLoc[face][position] =
1675 w->pyraminx.rowLoc[orient][side][g];
1676 DrawTriangle(w, face, position, FALSE);
1677 }
1678 } else { /* dir == TR || dir == BL */
1679 faceOnView = (h < w->pyraminx.size);
1680 i = (faceOnView == UP) ? w->pyraminx.size - 1 : 0;
1681 j = h % w->pyraminx.size;
1682 for (g = 0; g < w->pyraminx.size; g++) {
1683 for (side = 0; side < MAXSIDES; side++) {
1684 s = (side == UP) ? !faceOnView : faceOnView;
1685 crd.column = i;
1686 crd.row = j;
1687 crd.diagonal = i + j + s;
1688 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1689 position = ToPosition(w, crd);
1690 w->pyraminx.tetraLoc[face][position] =
1691 w->pyraminx.rowLoc[orient][side][g];
1692 DrawTriangle(w, face, position, FALSE);
1693 if (!side) {
1694 if (faceOnView == UP) {
1695 if (j == w->pyraminx.size - 1) {
1696 view = !view;
1697 j = 0;
1698 } else
1699 ++j;
1700 } else { /* FACE == DOWN */
1701 if (!j) {
1702 view = !view;
1703 j = w->pyraminx.size - 1;
1704 } else
1705 --j;
1706 }
1707 }
1708 }
1709 if (faceOnView == UP)
1710 --i;
1711 else /* faceOnView == DOWN */
1712 ++i;
1713 }
1714 }
1715 }
1716
1717 static void
WriteCRD3(PyraminxWidget w,int view,int faceOnView,int dir,int h,int len,int orient)1718 WriteCRD3(PyraminxWidget w, int view, int faceOnView, int dir, int h, int len, int orient)
1719 {
1720 int g, side, i, j, k, s, face, position;
1721 CRD crd;
1722
1723 if (dir == TOP || dir == BOTTOM) {
1724 for (k = 0; k <= len; k++)
1725 for (side = 0; side < MAXSIDES; side++)
1726 if (!side || k < len) {
1727 g = (faceOnView == DOWN) ? w->pyraminx.size - 1 - k : k;
1728 s = (faceOnView == DOWN) ? !side : side;
1729 crd.column = h;
1730 crd.row = g;
1731 crd.diagonal = h + g + s;
1732 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1733 position = ToPosition(w, crd);
1734 w->pyraminx.tetraLoc[face][position] =
1735 w->pyraminx.rowLoc[orient][side][k];
1736 DrawTriangle(w, face, position, FALSE);
1737 }
1738 } else if (dir == RIGHT || dir == LEFT) {
1739 for (k = 0; k <= len; k++)
1740 for (side = 0; side < MAXSIDES; side++)
1741 if (!side || k < len) {
1742 g = (faceOnView == DOWN) ? w->pyraminx.size - 1 - k : k;
1743 s = (faceOnView == DOWN) ? !side : side;
1744 crd.column = g;
1745 crd.row = h;
1746 crd.diagonal = h + g + s;
1747 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1748 position = ToPosition(w, crd);
1749 w->pyraminx.tetraLoc[face][position] =
1750 w->pyraminx.rowLoc[orient][side][k];
1751 DrawTriangle(w, face, position, FALSE);
1752 }
1753 } else { /* dir == TR || dir == BL */
1754 faceOnView = (h < w->pyraminx.size);
1755 i = (faceOnView == UP) ? w->pyraminx.size - 1 : 0;
1756 j = h % w->pyraminx.size;
1757 for (k = 0; k <= len; k++) {
1758 for (side = 0; side < MAXSIDES; side++)
1759 if (!side || k < len) {
1760 s = (side == UP) ? !faceOnView : faceOnView;
1761 crd.column = i;
1762 crd.row = j;
1763 crd.diagonal = i + j + s;
1764 face = view * MAXSIDES + (crd.diagonal >= w->pyraminx.size);
1765 position = ToPosition(w, crd);
1766 w->pyraminx.tetraLoc[face][position] =
1767 w->pyraminx.rowLoc[orient][side][k];
1768 DrawTriangle(w, face, position, FALSE);
1769 if (!side) {
1770 if (faceOnView == UP) {
1771 if (j == w->pyraminx.size - 1) {
1772 view = !view;
1773 j = 0;
1774 } else
1775 ++j;
1776 } else { /* FACE == DOWN */
1777 if (!j) {
1778 view = !view;
1779 j = w->pyraminx.size - 1;
1780 } else
1781 --j;
1782 }
1783 }
1784 }
1785 if (faceOnView == UP)
1786 --i;
1787 else /* faceOnView == DOWN */
1788 ++i;
1789 }
1790 }
1791 }
1792
1793 static void
DrawFrame(PyraminxWidget w,GC gc)1794 DrawFrame(PyraminxWidget w, GC gc)
1795 {
1796 int startx, starty, lengthx, lengthy, longlength;
1797
1798 startx = 1 + w->pyraminx.puzzleOffset.x;
1799 starty = 1 + w->pyraminx.puzzleOffset.y;
1800 lengthx = w->pyraminx.viewLength - w->pyraminx.delta +
1801 w->pyraminx.puzzleOffset.x;
1802 lengthy = w->pyraminx.viewLength - w->pyraminx.delta +
1803 w->pyraminx.puzzleOffset.y;
1804 XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, starty, lengthx, starty);
1805 XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, starty, startx, lengthy);
1806 XDrawLine(XtDisplay(w), XtWindow(w), gc, lengthx, starty, lengthx, lengthy);
1807 XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, lengthy, lengthx, lengthy);
1808 XDrawLine(XtDisplay(w), XtWindow(w), gc, startx, lengthy, lengthx, starty);
1809 if (w->pyraminx.vertical) {
1810 longlength = 2 * w->pyraminx.viewLength - 2 * w->pyraminx.delta - 1 +
1811 w->pyraminx.puzzleOffset.y;
1812 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1813 startx, lengthy, startx, longlength);
1814 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1815 lengthx, lengthy, lengthx, longlength);
1816 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1817 startx, longlength, lengthx, longlength);
1818 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1819 startx, longlength, lengthx, lengthy);
1820 } else {
1821 longlength = 2 * w->pyraminx.viewLength - 2 * w->pyraminx.delta - 1 +
1822 w->pyraminx.puzzleOffset.x;
1823 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1824 lengthx, starty, longlength, starty);
1825 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1826 lengthx, lengthy, longlength, lengthy);
1827 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1828 longlength, starty, longlength, lengthy);
1829 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1830 longlength, starty, lengthx, lengthy);
1831 }
1832 }
1833
1834 void
DrawAllPolyhedrons(PyraminxWidget w)1835 DrawAllPolyhedrons(PyraminxWidget w)
1836 {
1837 int face, position;
1838
1839 for (face = 0; face < MAXFACES; face++)
1840 for (position = 0; position < w->pyraminx.sizeSize; position++)
1841 DrawTriangle(w, face, position, FALSE);
1842 }
1843
1844
1845 static void
DrawTriangle(PyraminxWidget w,int face,int position,int offset)1846 DrawTriangle(PyraminxWidget w, int face, int position, int offset)
1847 {
1848 GC faceGC, borderGC;
1849 int dx, dy, faceOnView, orient, side, view;
1850 CRD crd;
1851
1852 crd = ToCRD(w, face, position);
1853 view = face / MAXSIDES;
1854 side = crd.diagonal - crd.column - crd.row;
1855 if (!w->pyraminx.vertical && view == DOWN) {
1856 dx = (w->pyraminx.size - crd.column - 1) *
1857 (w->pyraminx.tetraLength + w->pyraminx.delta) + w->pyraminx.delta;
1858 dy = (w->pyraminx.size - crd.row - 1) *
1859 (w->pyraminx.tetraLength + w->pyraminx.delta) + w->pyraminx.delta;
1860 faceOnView = !side;
1861 orient = (w->pyraminx.tetraLoc[face][position].rotation +
1862 MAXORIENT / 2) % MAXORIENT;
1863 if (2 * w->pyraminx.size - crd.column - crd.row - 2 + faceOnView >=
1864 w->pyraminx.size) {
1865 dx += w->pyraminx.sideOffset;
1866 dy += w->pyraminx.sideOffset;
1867 }
1868 } else {
1869 dx = crd.column * (w->pyraminx.tetraLength + w->pyraminx.delta) +
1870 w->pyraminx.delta;
1871 dy = crd.row * (w->pyraminx.tetraLength + w->pyraminx.delta) +
1872 w->pyraminx.delta;
1873 faceOnView = side;
1874 orient = w->pyraminx.tetraLoc[face][position].rotation;
1875 if (crd.column + crd.row + faceOnView >= w->pyraminx.size) {
1876 dx += w->pyraminx.sideOffset;
1877 dy += w->pyraminx.sideOffset;
1878 }
1879 }
1880 dx += w->pyraminx.puzzleOffset.x;
1881 dy += w->pyraminx.puzzleOffset.y;
1882 if (view == DOWN) {
1883 if (w->pyraminx.vertical)
1884 dy += w->pyraminx.viewLength - w->pyraminx.delta - 1;
1885 else
1886 dx += w->pyraminx.viewLength - w->pyraminx.delta - 1;
1887 }
1888 triangleList[faceOnView][0].x = offsetList[!faceOnView].x + dx;
1889 triangleList[faceOnView][0].y = offsetList[!faceOnView].y + dy;
1890 if (offset) {
1891 borderGC = w->pyraminx.faceGC[w->pyraminx.tetraLoc[face][position].face];
1892 if (w->pyraminx.depth < 2 || w->pyraminx.mono) {
1893 faceGC = w->pyraminx.inverseGC;
1894 } else {
1895 faceGC = w->pyraminx.borderGC;
1896 }
1897 } else {
1898 faceGC = w->pyraminx.faceGC[w->pyraminx.tetraLoc[face][position].face];
1899 borderGC = w->pyraminx.borderGC;
1900 }
1901
1902 XFillPolygon(XtDisplay(w), XtWindow(w), faceGC,
1903 triangleList[faceOnView], 3, Convex, CoordModePrevious);
1904 XDrawLines(XtDisplay(w), XtWindow(w), borderGC,
1905 triangleList[faceOnView], 4, CoordModePrevious);
1906 if (w->pyraminx.depth < 2 || w->pyraminx.mono) {
1907 int letterX, letterY;
1908 char buf[2];
1909
1910 (void) sprintf(buf, "%c",
1911 w->pyraminx.faceName[w->pyraminx.tetraLoc[face][position].face][0]);
1912 letterX = dx + letterList[!faceOnView].x;
1913 letterY = dy + letterList[!faceOnView].y;
1914 if (offset) {
1915 borderGC = w->pyraminx.borderGC;
1916 } else {
1917 borderGC = w->pyraminx.inverseGC;
1918 }
1919 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
1920 letterX, letterY, buf, 1);
1921 }
1922 if (w->pyraminx.orient)
1923 DrawOrientLine(w, orient, dx, dy, !faceOnView, borderGC);
1924 }
1925
1926 static void
DrawOrientLine(PyraminxWidget w,int orient,int dx,int dy,int side,GC borderGC)1927 DrawOrientLine(PyraminxWidget w, int orient, int dx, int dy, int side, GC borderGC)
1928 {
1929 int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
1930 int temp1 = w->pyraminx.tetraLength / 2 + 1;
1931 int temp2 = w->pyraminx.tetraLength + 1;
1932 int fix = (w->pyraminx.size == 1) ? 1 : 0;
1933
1934 switch (orient) {
1935 case TOP:
1936 x2 = x1 = dx + temp1 + 2;
1937 y1 = (side == UP) ? dy + temp1 + 1 : dy;
1938 y2 = y1 + w->pyraminx.orientLineLength;
1939 break;
1940 case TR:
1941 x1 = (side == UP) ? dx + temp2 + 1 : dx + temp1;
1942 x2 = x1 - w->pyraminx.orientDiagLength;
1943 y1 = (side == UP) ? dy + temp1 + 1 : dy;
1944 y2 = y1 + w->pyraminx.orientDiagLength;
1945 break;
1946 case RIGHT:
1947 x1 = (side == UP) ? dx + temp2 + 1 : dx + temp1 - fix - 1;
1948 x2 = x1 - w->pyraminx.orientLineLength;
1949 y2 = y1 = dy + temp1 - 1;
1950 break;
1951 case BOTTOM:
1952 x2 = x1 = dx + temp1 - 1;
1953 y1 = (side == UP) ? dy + temp2 + 1 : dy + temp1 - fix - 1;
1954 y2 = y1 - w->pyraminx.orientLineLength;
1955 break;
1956 case BL:
1957 x1 = (side == UP) ? dx + temp1 : dx;
1958 x2 = x1 + w->pyraminx.orientDiagLength;
1959 y1 = (side == UP) ? dy + temp2 + 1 : dy + temp1;
1960 y2 = y1 - w->pyraminx.orientDiagLength;
1961 break;
1962 case LEFT:
1963 x1 = (side == UP) ? dx + temp1 + 1 : dx;
1964 x2 = x1 + w->pyraminx.orientLineLength;
1965 y2 = y1 = dy + temp1 + 2;
1966 break;
1967 default:
1968 (void) printf("DrawOrientLine: orient %d\n", orient);
1969 }
1970 XDrawLine(XtDisplay(w), XtWindow(w), borderGC, x1, y1, x2, y2);
1971 }
1972
1973 Boolean
CheckSolved(PyraminxWidget w)1974 CheckSolved(PyraminxWidget w)
1975 {
1976 int face, position;
1977 PyraminxLoc test;
1978
1979 for (face = 0; face < MAXFACES; face++)
1980 for (position = 0; position < w->pyraminx.sizeSize; position++) {
1981 if (!position) {
1982 test.face = w->pyraminx.tetraLoc[face][position].face;
1983 test.rotation = w->pyraminx.tetraLoc[face][position].rotation;
1984 } else if (test.face != /* MAXSIDES * view + face */
1985 w->pyraminx.tetraLoc[face][position].face ||
1986 (w->pyraminx.orient && test.rotation !=
1987 w->pyraminx.tetraLoc[face][position].rotation))
1988 return False;
1989 }
1990 return True;
1991 }
1992
1993 static int
Crd(int dir,int I,int J,int side)1994 Crd(int dir, int I, int J, int side)
1995 {
1996 if (dir == TOP || dir == BOTTOM)
1997 return (I);
1998 else if (dir == RIGHT || dir == LEFT)
1999 return (J);
2000 else /* dir == TR || dir == BL */
2001 return (I + J + side);
2002 }
2003
2004 static int
Length(PyraminxWidget w,int face,int dir,int h)2005 Length(PyraminxWidget w, int face, int dir, int h)
2006 {
2007 if (dir == TR || dir == BL)
2008 return ((face) ? 2 * w->pyraminx.size - 1 - h : h);
2009 else
2010 return ((face) ? h : w->pyraminx.size - 1 - h);
2011 }
2012
2013 static int
CheckMoveDir(PyraminxWidget w,CRD crd1,CRD crd2,int face,int * direction)2014 CheckMoveDir(PyraminxWidget w, CRD crd1, CRD crd2, int face, int *direction)
2015 {
2016 int which = -1, count = 0;
2017 int i, *p1, *p2;
2018
2019 p1 = &(crd1.column);
2020 p2 = &(crd2.column);
2021 for (i = 0; i < 3; i++, p1++, p2++)
2022 if (*p1 == *p2) {
2023 which = i;
2024 count++;
2025 }
2026 if (count == 1)
2027 switch (which) {
2028 case 0: /* COLUMN */
2029 *direction = (crd2.row > crd1.row) ? BOTTOM : TOP;
2030 break;
2031 case 1: /* ROW */
2032 *direction = (crd2.column > crd1.column) ? RIGHT : LEFT;
2033 break;
2034 case 2: /* DIAGONAL */
2035 *direction = (crd2.column > crd1.column) ? TR : BL;
2036 break;
2037 }
2038 if (!w->pyraminx.vertical && face >= MAXSIDES && *direction > LEFT)
2039 *direction = (*direction + MAXSIDES) % MAXFACES;
2040 return count;
2041 }
2042
2043 static CRD
ToCRD(PyraminxWidget w,int face,int position)2044 ToCRD(PyraminxWidget w, int face, int position)
2045 {
2046 CRD crd;
2047 int diag, diag2;
2048
2049 diag = Sqrt(position);
2050 diag2 = diag * diag;
2051 /* Passing diagonal so there is no sqrt calculation again */
2052 if (face % 2) {
2053 crd.diagonal = 2 * w->pyraminx.size - 1 - diag;
2054 crd.column = w->pyraminx.size - 1 - (position - diag2) / 2;
2055 crd.row = w->pyraminx.size - 1 - (diag2 + 2 * diag - position) / 2;
2056 } else {
2057 crd.diagonal = diag;
2058 crd.column = (position - diag2) / 2;
2059 crd.row = (diag2 + 2 * diag - position) / 2;
2060 }
2061 return crd;
2062 }
2063
2064 static int
ToPosition(PyraminxWidget w,CRD crd)2065 ToPosition(PyraminxWidget w, CRD crd)
2066 {
2067 int diag;
2068
2069 if (crd.diagonal < w->pyraminx.size)
2070 return (crd.diagonal * crd.diagonal + crd.diagonal + crd.column - crd.row);
2071 diag = 2 * w->pyraminx.size - 1 - crd.diagonal;
2072 return (diag * diag + diag + crd.row - crd.column);
2073 }
2074
2075 /* This is fast for small i, a -1 is returned for negative i. */
2076 static int
Sqrt(int i)2077 Sqrt(int i)
2078 {
2079 int j = 0;
2080
2081 while (j * j <= i)
2082 j++;
2083 return (j - 1);
2084 }
2085
2086 #ifdef DEBUG
2087
2088 static void
PrintTetra(PyraminxWidget w)2089 PrintTetra(PyraminxWidget w)
2090 {
2091 int face, position, square;
2092
2093 for (face = 0; face < MAXSIDES; face++) {
2094 square = 1;
2095 for (position = 0; position < w->pyraminx.sizeSize; position++) {
2096 (void) printf("%d %d ",
2097 w->pyraminx.tetraLoc[face][position].face,
2098 w->pyraminx.tetraLoc[face][position].rotation);
2099 if (position == square * square - 1) {
2100 (void) printf("\n");
2101 ++square;
2102 }
2103 }
2104 (void) printf("\n");
2105 }
2106 (void) printf("\n");
2107 }
2108
2109 static void
PrintFace(PyraminxWidget w)2110 PrintFace(PyraminxWidget w)
2111 {
2112 int g, h, side;
2113
2114 for (g = 0; g < w->pyraminx.size; g++) {
2115 for (h = 0; h < w->pyraminx.size - g; h++)
2116 for (side = 0; side < MAXSIDES; side++)
2117 if (!side || h < w->pyraminx.size - g - 1)
2118 (void) printf("%d %d ", w->pyraminx.faceLoc[side][h +
2119 g * w->pyraminx.size].face,
2120 w->pyraminx.faceLoc[side][h + g * w->pyraminx.size].rotation);
2121 (void) printf("\n");
2122 }
2123 (void) printf("\n");
2124
2125 #if 0
2126 int position;
2127 int square = 1;
2128
2129 for (position = 0; position < w->pyraminx.sizeSize; position++) {
2130 (void) printf("%d %d ", w->pyraminx.faceLoc[position].face,
2131 w->pyraminx.faceLoc[position].rotation);
2132 if (position == square * square - 1) {
2133 (void) printf("\n");
2134 ++square;
2135 }
2136 }
2137 (void) printf("\n");
2138 #endif
2139 }
2140
2141 static void
PrintRow2(PyraminxWidget w,int orient)2142 PrintRow2(PyraminxWidget w, int orient)
2143 {
2144 int g, side;
2145
2146 (void) printf("Row %d:\n", orient);
2147 for (g = 0; g < w->pyraminx.size; g++)
2148 for (side = 0; side < MAXSIDES; side++)
2149 (void) printf("%d %d ", w->pyraminx.rowLoc[orient][side][g].face,
2150 w->pyraminx.rowLoc[orient][side][g].rotation);
2151 (void) printf("\n");
2152 }
2153
2154 static void
PrintRow3(PyraminxWidget w,int len,int orient)2155 PrintRow3(PyraminxWidget w, int len, int orient)
2156 {
2157 int g, side;
2158
2159 (void) printf("Row %d:\n", orient);
2160 for (g = 0; g <= len; g++)
2161 for (side = 0; side < MAXSIDES; side++)
2162 if (!side || g < len)
2163 (void) printf("%d %d ", w->pyraminx.rowLoc[orient][side][g].face,
2164 w->pyraminx.rowLoc[orient][side][g].rotation);
2165 (void) printf("\n");
2166 }
2167
2168 #endif
2169