1
2 /*-
3 # X-BASED RUBIK'S CUBE(tm)
4 #
5 # Rubik.c
6 #
7 ###
8 #
9 # Copyright (c) 1994 - 99 David Albert Bagley, bagleyd@tux.org
10 #
11 # All Rights Reserved
12 #
13 # Permission to use, copy, modify, and distribute this software and
14 # its documentation for any purpose and without fee is hereby granted,
15 # provided that the above copyright notice appear in all copies and
16 # that both that copyright notice and this permission notice appear in
17 # supporting documentation, and that the name of the author not be
18 # used in advertising or publicity pertaining to distribution of the
19 # software without specific, written prior permission.
20 #
21 # This program is distributed in the hope that it will be "playable",
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 #
25 */
26
27 /* Methods file for Rubik */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #ifdef VMS
32 #include <unixlib.h>
33 #else
34 #if HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #endif
38 #include <X11/IntrinsicP.h>
39 #include <X11/Intrinsic.h>
40 #include <X11/StringDefs.h>
41 #include <X11/CoreP.h>
42 #include "RubikP.h"
43 #include "Rubik2dP.h"
44 #include "Rubik3dP.h"
45
46 #ifndef DATAFILE
47 #define DATAFILE "/usr/games/lib/rubik.data"
48 #endif
49
50 static void InitializeRubik(Widget request, Widget renew);
51 static void DestroyRubik(Widget old);
52 static Boolean SetValuesRubik(Widget current, Widget request, Widget renew);
53
54 static Bool checkFaceSquare(RubikWidget w, int face);
55 static void SetAllColors(RubikWidget w, Boolean init);
56 static void GetColor(RubikWidget w, int face, Boolean init);
57 static void MoveControlCb(RubikWidget w, int face, int direction);
58 static void CheckPolyhedrons(RubikWidget w);
59 static Boolean SelectPolyhedrons(RubikWidget w,
60 int x, int y, int *face, int *position);
61 static Boolean NarrowSelection(RubikWidget w,
62 int *face, int *position, int *direction);
63 static Boolean PositionPolyhedrons(RubikWidget w,
64 int x, int y, int *face, int *position, int *direction);
65 static void MoveNoPolyhedrons(RubikWidget w);
66 static void PracticePolyhedrons(RubikWidget w);
67 static void RandomizePolyhedrons(RubikWidget w);
68 static void MovePolyhedrons(RubikWidget w,
69 int face, int position, int direction);
70
71 /* rc : row or column */
72 static void ReadRC(RubikWidget w, int face, int dir, int h, int orient, int size);
73 static void RotateRC(RubikWidget w, int rotate, int orient, int size);
74 static void ReverseRC(RubikWidget w, int orient, int size);
75 static void WriteRC(RubikWidget w, int face, int dir, int h, int orient, int size);
76 static void RotateFace(RubikWidget w, int face, int direction);
77 static void DrawSquare(RubikWidget w, int face, int position, int offset);
78 static int CheckMoveDir(RubikWidget w, int face,
79 int position1, int position2, int *direction);
80
81 RubikClassRec rubikClassRec =
82 {
83 {
84 (WidgetClass) & widgetClassRec, /* superclass */
85 "Rubik", /* class name */
86 sizeof (RubikRec), /* widget size */
87 NULL, /* class initialize */
88 NULL, /* class part initialize */
89 FALSE, /* class inited */
90 (XtInitProc) InitializeRubik, /* initialize */
91 NULL, /* initialize hook */
92 XtInheritRealize, /* realize */
93 NULL, /* actions */
94 0, /* num actions */
95 NULL, /* resources */
96 0, /* num resources */
97 NULLQUARK, /* xrm class */
98 TRUE, /* compress motion */
99 TRUE, /* compress exposure */
100 TRUE, /* compress enterleave */
101 TRUE, /* visible interest */
102 (XtWidgetProc) DestroyRubik, /* destroy */
103 NULL, /* resize */
104 NULL, /* expose */
105 (XtSetValuesFunc) SetValuesRubik, /* set values */
106 NULL, /* set values hook */
107 XtInheritSetValuesAlmost, /* set values almost */
108 NULL, /* get values hook */
109 NULL, /* accept focus */
110 XtVersion, /* version */
111 NULL, /* callback private */
112 NULL, /* tm table */
113 NULL, /* query geometry */
114 NULL, /* display accelerator */
115 NULL /* extension */
116 },
117 {
118 0 /* ignore */
119 }
120 };
121
122 WidgetClass rubikWidgetClass = (WidgetClass) & rubikClassRec;
123
124 static RubikLoc slideNextRow[MAXFACES][MAXORIENT] =
125 {
126 {
127 {5, TOP},
128 {3, RIGHT},
129 {2, TOP},
130 {1, LEFT}},
131 {
132 {0, RIGHT},
133 {2, TOP},
134 {4, LEFT},
135 {5, BOTTOM}},
136 {
137 {0, TOP},
138 {3, TOP},
139 {4, TOP},
140 {1, TOP}},
141 {
142 {0, LEFT},
143 {5, BOTTOM},
144 {4, RIGHT},
145 {2, TOP}},
146 {
147 {2, TOP},
148 {3, LEFT},
149 {5, TOP},
150 {1, RIGHT}},
151 {
152 {4, TOP},
153 {3, BOTTOM},
154 {0, TOP},
155 {1, BOTTOM}}
156 };
157 static int rowToRotate[MAXFACES][MAXORIENT] =
158 {
159 {3, 2, 1, 5},
160 {2, 4, 5, 0},
161 {3, 4, 1, 0},
162 {5, 4, 2, 0},
163 {3, 5, 1, 2},
164 {3, 0, 1, 4}
165 };
166
167 void
faceSizes(RubikWidget w,int face,int * sizeOfRow,int * sizeOfColumn)168 faceSizes(RubikWidget w, int face, int *sizeOfRow, int *sizeOfColumn)
169 {
170 switch (face) {
171 case 0: /* TOP */
172 case 4: /* BOTTOM */
173 *sizeOfRow = w->rubik.sizex;
174 *sizeOfColumn = w->rubik.sizez;
175 break;
176 case 1: /* LEFT */
177 case 3: /* RIGHT */
178 *sizeOfRow = w->rubik.sizez;
179 *sizeOfColumn = w->rubik.sizey;
180 break;
181 case 2: /* FRONT */
182 case 5: /* BACK */
183 *sizeOfRow = w->rubik.sizex;
184 *sizeOfColumn = w->rubik.sizey;
185 break;
186 default:
187 (void) printf("faceSizes: face %d\n", face);
188 }
189 }
190
191 int
sizeFace(RubikWidget w,int face)192 sizeFace(RubikWidget w, int face)
193 {
194 int sizeOfRow, sizeOfColumn;
195
196 faceSizes(w, face, &sizeOfRow, &sizeOfColumn);
197 return (sizeOfRow * sizeOfColumn);
198 }
199
200 int
sizeRow(RubikWidget w,int face)201 sizeRow(RubikWidget w, int face)
202 {
203 int sizeOfRow, sizeOfColumn;
204
205 faceSizes(w, face, &sizeOfRow, &sizeOfColumn);
206 return sizeOfRow;
207 }
208
209 static void
InitializeRubik(Widget request,Widget renew)210 InitializeRubik(Widget request, Widget renew)
211 {
212 RubikWidget w = (RubikWidget) renew;
213 int face, orient;
214
215 for (face = 0; face < MAXFACES; face++)
216 w->rubik.cubeLoc[face] = NULL;
217 for (orient = 0; orient < MAXORIENT; orient++)
218 w->rubik.rowLoc[orient] = NULL;
219 CheckPolyhedrons(w);
220 InitMoves();
221 ResetPolyhedrons(w);
222 (void) SRAND(getpid());
223 w->rubik.depth = DefaultDepthOfScreen(XtScreen(w));
224 SetAllColors(w, True);
225 }
226
227 static void
DestroyRubik(Widget old)228 DestroyRubik(Widget old)
229 {
230 RubikWidget w = (RubikWidget) old;
231 int face;
232
233 for (face = 0; face < MAXFACES; face++)
234 XtReleaseGC(old, w->rubik.faceGC[face]);
235 XtReleaseGC(old, w->rubik.borderGC);
236 XtReleaseGC(old, w->rubik.puzzleGC);
237 XtReleaseGC(old, w->rubik.inverseGC);
238 XtRemoveCallbacks(old, XtNselectCallback, w->rubik.select);
239 }
240
241 static Boolean
SetValuesRubik(Widget current,Widget request,Widget renew)242 SetValuesRubik(Widget current, Widget request, Widget renew)
243 {
244 RubikWidget c = (RubikWidget) current, w = (RubikWidget) renew;
245 Boolean redraw = False, setColors = False;
246 int face;
247
248 CheckPolyhedrons(w);
249 for (face = 0; face < MAXFACES; face++) {
250 if (strcmp(w->rubik.faceName[face], c->rubik.faceName[face])) {
251 setColors = True;
252 break;
253 }
254 }
255 if (w->core.background_pixel != c->core.background_pixel ||
256 w->rubik.foreground != c->rubik.foreground ||
257 w->rubik.borderColor != c->rubik.borderColor ||
258 w->rubik.reverse != c->rubik.reverse ||
259 w->rubik.mono != c->rubik.mono ||
260 setColors) {
261 SetAllColors(w, False);
262 redraw = True;
263 }
264 if (w->rubik.orient != c->rubik.orient) {
265 ResetPolyhedrons(w);
266 redraw = True;
267 } else if (w->rubik.practice != c->rubik.practice) {
268 ResetPolyhedrons(w);
269 redraw = True;
270 }
271 if (w->rubik.currentDirection == RUBIK_RESTORE) {
272 SetStartPosition(w);
273 w->rubik.currentDirection = RUBIK_IGNORE;
274 } else if (w->rubik.currentDirection != RUBIK_IGNORE) {
275 MovePolyhedrons(w, w->rubik.currentFace, w->rubik.currentPosition,
276 w->rubik.currentDirection);
277 w->rubik.currentDirection = RUBIK_IGNORE;
278 }
279 return redraw;
280 }
281
282 void
QuitRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)283 QuitRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
284 {
285 XtCloseDisplay(XtDisplay(w));
286 exit(0);
287 }
288
289 void
SelectRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)290 SelectRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
291 {
292 int control;
293
294 if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
295 &(w->rubik.currentFace), &(w->rubik.currentPosition))) {
296 control = (int) (event->xkey.state & ControlMask);
297 if (control || w->rubik.practice || !CheckSolved(w))
298 DrawSquare(w, w->rubik.currentFace, w->rubik.currentPosition,
299 TRUE);
300 } else {
301 w->rubik.currentFace = RUBIK_IGNORE;
302 w->rubik.currentDirection = RUBIK_IGNORE;
303 }
304 }
305
306 void
ReleaseRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)307 ReleaseRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
308 {
309 int control, face, position, count = -1, direction = 0;
310 rubikCallbackStruct cb;
311
312 if (w->rubik.currentFace == RUBIK_IGNORE)
313 return;
314 DrawSquare(w, w->rubik.currentFace, w->rubik.currentPosition, FALSE);
315 control = (int) (event->xkey.state & ControlMask);
316 if (!control && !w->rubik.practice && CheckSolved(w))
317 MoveNoPolyhedrons(w);
318 else if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
319 &face, &position)) {
320 control = (control) ? 1 : 0;
321 if (face == w->rubik.currentFace)
322 count = CheckMoveDir(w, face, w->rubik.currentPosition, position, &direction);
323 if (count == 1) {
324 MoveRubik(w, face, w->rubik.currentPosition, direction, control);
325 if (!control && CheckSolved(w)) {
326 cb.reason = RUBIK_SOLVED;
327 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
328 }
329 } else if (count == 0)
330 MoveNoPolyhedrons(w);
331 }
332 }
333
334 void
PracticeRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)335 PracticeRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
336 {
337 PracticePolyhedrons(w);
338 }
339
340 void
PracticeRubikMaybe(RubikWidget w,XEvent * event,char ** args,int nArgs)341 PracticeRubikMaybe(RubikWidget w, XEvent * event, char **args, int nArgs)
342 {
343 if (!w->rubik.started)
344 PracticePolyhedrons(w);
345 }
346
347 void
RandomizeRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)348 RandomizeRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
349 {
350 RandomizePolyhedrons(w);
351 }
352
353 void
RandomizeRubikMaybe(RubikWidget w,XEvent * event,char ** args,int nArgs)354 RandomizeRubikMaybe(RubikWidget w, XEvent * event, char **args, int nArgs)
355 {
356 if (!w->rubik.started)
357 RandomizePolyhedrons(w);
358 }
359
360 void
GetRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)361 GetRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
362 {
363 FILE *fp;
364 char c;
365 int i, sizex, sizey, sizez, orient, practice, moves;
366 rubikCallbackStruct cb;
367
368 if ((fp = fopen(DATAFILE, "r")) == NULL)
369 (void) printf("Can not read %s for get.\n", DATAFILE);
370 else {
371 FlushMoves(w);
372 while ((c = getc(fp)) != EOF && c != SYMBOL);
373 (void) fscanf(fp, "%d", &sizex);
374 if (sizex >= MINCUBES) {
375 for (i = w->rubik.sizex; i < sizex; i++) {
376 cb.reason = RUBIK_INCX;
377 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
378 }
379 for (i = w->rubik.sizex; i > sizex; i--) {
380 cb.reason = RUBIK_DECX;
381 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
382 }
383 } else
384 (void) printf("%s corrupted: sizex %d should be between %d and MAXINT\n",
385 DATAFILE, sizex, MINCUBES);
386 while ((c = getc(fp)) != EOF && c != SYMBOL);
387 (void) fscanf(fp, "%d", &sizey);
388 if (sizey >= MINCUBES) {
389 for (i = w->rubik.sizey; i < sizey; i++) {
390 cb.reason = RUBIK_INCY;
391 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
392 }
393 for (i = w->rubik.sizey; i > sizey; i--) {
394 cb.reason = RUBIK_DECY;
395 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
396 }
397 } else
398 (void) printf("%s corrupted: sizey %d should be between %d and MAXINT\n",
399 DATAFILE, sizey, MINCUBES);
400 while ((c = getc(fp)) != EOF && c != SYMBOL);
401 (void) fscanf(fp, "%d", &sizez);
402 if (sizez >= MINCUBES) {
403 for (i = w->rubik.sizez; i < sizez; i++) {
404 cb.reason = RUBIK_INCZ;
405 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
406 }
407 for (i = w->rubik.sizez; i > sizez; i--) {
408 cb.reason = RUBIK_DECZ;
409 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
410 }
411 } else
412 (void) printf("%s corrupted: sizez %d should be between %d and MAXINT\n",
413 DATAFILE, sizez, MINCUBES);
414 while ((c = getc(fp)) != EOF && c != SYMBOL);
415 (void) fscanf(fp, "%d", &orient);
416 if (w->rubik.orient != (Boolean) orient) {
417 cb.reason = RUBIK_ORIENT;
418 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
419 }
420 while ((c = getc(fp)) != EOF && c != SYMBOL);
421 (void) fscanf(fp, "%d", &practice);
422 if (w->rubik.practice != (Boolean) practice) {
423 cb.reason = RUBIK_PRACTICE;
424 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
425 }
426 while ((c = getc(fp)) != EOF && c != SYMBOL);
427 (void) fscanf(fp, "%d", &moves);
428 ScanStartPosition(fp, w);
429 cb.reason = RUBIK_RESTORE;
430 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
431 ScanMoves(fp, w, moves);
432 (void) fclose(fp);
433 (void) printf("%s: sizex %d, sizey %d, sizez %d, orient %d, practice %d, moves %d.\n",
434 DATAFILE, sizex, sizey, sizez, orient, practice, moves);
435 }
436 }
437
438 void
WriteRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)439 WriteRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
440 {
441 FILE *fp;
442
443 if ((fp = fopen(DATAFILE, "w")) == NULL)
444 (void) printf("Can not write to %s.\n", DATAFILE);
445 else {
446 (void) fprintf(fp, "sizex%c %d\n", SYMBOL, w->rubik.sizex);
447 (void) fprintf(fp, "sizey%c %d\n", SYMBOL, w->rubik.sizey);
448 (void) fprintf(fp, "sizez%c %d\n", SYMBOL, w->rubik.sizez);
449 (void) fprintf(fp, "orient%c %d\n", SYMBOL, (w->rubik.orient) ? 1 : 0);
450 (void) fprintf(fp, "practice%c %d\n", SYMBOL, (w->rubik.practice) ? 1 : 0);
451 (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
452 PrintStartPosition(fp, w);
453 PrintMoves(fp);
454 (void) fclose(fp);
455 (void) printf("Saved to %s.\n", DATAFILE);
456 }
457 }
458
459 void
UndoRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)460 UndoRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
461 {
462 if (MadeMoves()) {
463 int face, position, direction, control;
464
465 GetMove(&face, &position, &direction, &control);
466 direction = (direction < MAXORIENT) ? (direction + MAXORIENT / 2) %
467 MAXORIENT : 3 * MAXORIENT - direction;
468 if (control)
469 MoveControlCb(w, face, direction);
470 else {
471 rubikCallbackStruct cb;
472
473 MovePolyhedrons(w, face, position, direction);
474 cb.reason = RUBIK_UNDO;
475 cb.face = face;
476 cb.position = position;
477 cb.direction = direction;
478 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
479 }
480 }
481 }
482
483 void
SolveRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)484 SolveRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
485 {
486 if ((w->rubik.sizex == 2 && w->rubik.sizey == 2 && w->rubik.sizez == 2) ||
487 (w->rubik.sizex == 3 && w->rubik.sizey == 3 && w->rubik.sizez == 3 && !w->rubik.orient))
488 SolvePolyhedrons(w);
489 }
490
491 void
DecrementRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)492 DecrementRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
493 {
494 rubikCallbackStruct cb;
495
496 if (w->rubik.sizex > MINCUBES) {
497 cb.reason = RUBIK_DECX;
498 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
499 }
500 if (w->rubik.sizey > MINCUBES) {
501 cb.reason = RUBIK_DECY;
502 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
503 }
504 if (w->rubik.sizez > MINCUBES) {
505 cb.reason = RUBIK_DECZ;
506 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
507 }
508 }
509
510 void
IncrementRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)511 IncrementRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
512 {
513 rubikCallbackStruct cb;
514
515 cb.reason = RUBIK_INCX;
516 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
517 cb.reason = RUBIK_INCY;
518 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
519 cb.reason = RUBIK_INCZ;
520 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
521 }
522
523 void
IncrementXRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)524 IncrementXRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
525 {
526 rubikCallbackStruct cb;
527
528 if (event->xbutton.state & (ShiftMask | LockMask)) {
529 if (w->rubik.sizex <= MINCUBES)
530 return;
531 cb.reason = RUBIK_DECX;
532 } else
533 cb.reason = RUBIK_INCX;
534 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
535 }
536
537 void
IncrementYRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)538 IncrementYRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
539 {
540 rubikCallbackStruct cb;
541
542 if (event->xbutton.state & (ShiftMask | LockMask)) {
543 if (w->rubik.sizey <= MINCUBES)
544 return;
545 cb.reason = RUBIK_DECY;
546 } else
547 cb.reason = RUBIK_INCY;
548 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
549 }
550
551 void
IncrementZRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)552 IncrementZRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
553 {
554 rubikCallbackStruct cb;
555
556 if (event->xbutton.state & (ShiftMask | LockMask)) {
557 if (w->rubik.sizez <= MINCUBES)
558 return;
559 cb.reason = RUBIK_DECZ;
560 } else
561 cb.reason = RUBIK_INCZ;
562 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
563 }
564
565 void
OrientizeRubik(RubikWidget w,XEvent * event,char ** args,int nArgs)566 OrientizeRubik(RubikWidget w, XEvent * event, char **args, int nArgs)
567 {
568 rubikCallbackStruct cb;
569
570 cb.reason = RUBIK_ORIENT;
571 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
572 }
573
574 void
MoveRubikCcw(RubikWidget w,XEvent * event,char ** args,int nArgs)575 MoveRubikCcw(RubikWidget w, XEvent * event, char **args, int nArgs)
576 {
577 MoveRubikInput(w, event->xbutton.x, event->xbutton.y, CCW,
578 (int) (event->xbutton.state & ControlMask));
579 }
580
581 void
MoveRubikCw(RubikWidget w,XEvent * event,char ** args,int nArgs)582 MoveRubikCw(RubikWidget w, XEvent * event, char **args, int nArgs)
583 {
584 MoveRubikInput(w, event->xbutton.x, event->xbutton.y, CW,
585 (int) (event->xkey.state & ControlMask));
586 }
587
588 void
MoveRubikInput(RubikWidget w,int x,int y,int direction,int control)589 MoveRubikInput(RubikWidget w, int x, int y, int direction, int control)
590 {
591 int face, position;
592
593 if (!w->rubik.practice && !control && CheckSolved(w)) {
594 MoveNoPolyhedrons(w);
595 return;
596 }
597 if (!PositionPolyhedrons(w, x, y, &face, &position, &direction))
598 return;
599 control = (control) ? 1 : 0;
600 MoveRubik(w, face, position, direction, control);
601 if (!control && CheckSolved(w)) {
602 rubikCallbackStruct cb;
603
604 cb.reason = RUBIK_SOLVED;
605 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
606 }
607 }
608
609 void
MoveRubik(RubikWidget w,int face,int position,int direction,int control)610 MoveRubik(RubikWidget w, int face, int position, int direction, int control)
611 {
612 if (control)
613 MoveControlCb(w, face, direction);
614 else {
615 rubikCallbackStruct cb;
616
617 MovePolyhedrons(w, face, position, direction);
618 cb.reason = RUBIK_MOVED;
619 cb.face = face;
620 cb.position = position;
621 cb.direction = direction;
622 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
623 }
624 PutMove(face, position, direction, control);
625 }
626
627 static Bool
checkFaceSquare(RubikWidget w,int face)628 checkFaceSquare(RubikWidget w, int face)
629 {
630 int sizeOfRow, sizeOfColumn;
631
632 faceSizes(w, face, &sizeOfRow, &sizeOfColumn);
633 return (sizeOfRow == sizeOfColumn);
634 /* Cubes can be made square with a 4x2 face where 90 degree turns
635 * should be permitted but that is kind of complicated for me.
636 * This can be done in 2 ways where the side of the cubies are
637 * the same size and one where one side (the side with half the
638 * number of cubies) is twice the size of the other. The first is
639 * complicated because faces of cubies can go under other faces.
640 * The second way is similar to "banded cubes" where scotch tape
641 * restricts the moves of some cubes. Here you have to keep track
642 * of the restrictions and show banded cubies graphically as one
643 * cube.
644 */
645 }
646
647 static void
SetAllColors(RubikWidget w,Boolean init)648 SetAllColors(RubikWidget w, Boolean init)
649 {
650 XGCValues values;
651 XtGCMask valueMask;
652 int face;
653
654 valueMask = GCForeground | GCBackground;
655
656 if (w->rubik.reverse) {
657 values.background = w->core.background_pixel;
658 values.foreground = w->rubik.foreground;
659 } else {
660 values.foreground = w->core.background_pixel;
661 values.background = w->rubik.foreground;
662 }
663 if (!init)
664 XtReleaseGC((Widget) w, w->rubik.inverseGC);
665 w->rubik.inverseGC = XtGetGC((Widget) w, valueMask, &values);
666 if (w->rubik.reverse) {
667 values.background = w->rubik.foreground;
668 values.foreground = w->core.background_pixel;
669 } else {
670 values.foreground = w->rubik.foreground;
671 values.background = w->core.background_pixel;
672 }
673 if (!init)
674 XtReleaseGC((Widget) w, w->rubik.puzzleGC);
675 w->rubik.puzzleGC = XtGetGC((Widget) w, valueMask, &values);
676 if (w->rubik.depth < 2 || w->rubik.mono) {
677 if (w->rubik.reverse) {
678 values.background = w->rubik.foreground;
679 values.foreground = w->core.background_pixel;
680 } else {
681 values.foreground = w->rubik.foreground;
682 values.background = w->core.background_pixel;
683 }
684 } else {
685 values.foreground = w->rubik.borderColor;
686 values.background = w->core.background_pixel;
687 }
688 if (!init)
689 XtReleaseGC((Widget) w, w->rubik.borderGC);
690 w->rubik.borderGC = XtGetGC((Widget) w, valueMask, &values);
691 for (face = 0; face < MAXFACES; face++)
692 GetColor(w, face, init);
693 }
694
695 static void
GetColor(RubikWidget w,int face,Boolean init)696 GetColor(RubikWidget w, int face, Boolean init)
697 {
698 XGCValues values;
699 XtGCMask valueMask;
700 XColor colorCell, rgb;
701
702 valueMask = GCForeground | GCBackground;
703 if (w->rubik.reverse) {
704 values.background = w->rubik.foreground;
705 } else {
706 values.background = w->core.background_pixel;
707 }
708 if (w->rubik.depth > 1 && !w->rubik.mono) {
709 if (XAllocNamedColor(XtDisplay(w),
710 DefaultColormap(XtDisplay(w), XtWindow(w)),
711 w->rubik.faceName[face], &colorCell, &rgb)) {
712 values.foreground = w->rubik.faceColor[face] = colorCell.pixel;
713 if (!init)
714 XtReleaseGC((Widget) w, w->rubik.faceGC[face]);
715 w->rubik.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
716 return;
717 } else {
718 char buf[121];
719
720 (void) sprintf(buf, "Color name \"%s\" is not defined",
721 w->rubik.faceName[face]);
722 XtWarning(buf);
723 }
724 }
725 if (w->rubik.reverse) {
726 values.background = w->rubik.foreground;
727 values.foreground = w->core.background_pixel;
728 } else {
729 values.background = w->core.background_pixel;
730 values.foreground = w->rubik.foreground;
731 }
732 if (!init)
733 XtReleaseGC((Widget) w, w->rubik.faceGC[face]);
734 w->rubik.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
735 }
736
737 static void
MoveControlCb(RubikWidget w,int face,int direction)738 MoveControlCb(RubikWidget w, int face, int direction)
739 {
740 rubikCallbackStruct cb;
741 int k, position, sizeOfRow, sizeOfColumn, sizeOnOppAxis;
742
743 faceSizes(w, face, &sizeOfRow, &sizeOfColumn);
744 if (direction == TOP || direction == BOTTOM) {
745 sizeOnOppAxis = sizeOfRow;
746 } else {
747 sizeOnOppAxis = sizeOfColumn;
748 }
749 for (k = 0; k < sizeOnOppAxis; k++) {
750 position = k * sizeOfRow + k;
751 MovePolyhedrons(w, face, position, direction);
752 cb.reason = RUBIK_CONTROL;
753 cb.face = face;
754 cb.position = position;
755 cb.direction = direction;
756 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
757 }
758 }
759
760 static void
CheckPolyhedrons(RubikWidget w)761 CheckPolyhedrons(RubikWidget w)
762 {
763 if (w->rubik.sizex < MINCUBES) {
764 char buf[121];
765
766 (void) sprintf(buf, "Number of Cubes on edge (x-axis) out of bounds, use %d..MAXINT",
767 MINCUBES);
768 XtWarning(buf);
769 w->rubik.sizex = DEFAULTCUBES;
770 }
771 if (w->rubik.sizey < MINCUBES) {
772 char buf[121];
773
774 (void) sprintf(buf, "Number of Cubes on edge (y-axis) out of bounds, use %d..MAXINT",
775 MINCUBES);
776 XtWarning(buf);
777 w->rubik.sizey = DEFAULTCUBES;
778 }
779 if (w->rubik.sizez < MINCUBES) {
780 char buf[121];
781
782 (void) sprintf(buf, "Number of Cubes on edge (z-axis) out of bounds, use %d..MAXINT",
783 MINCUBES);
784 XtWarning(buf);
785 w->rubik.sizez = DEFAULTCUBES;
786 }
787 }
788
789 void
ResetPolyhedrons(RubikWidget w)790 ResetPolyhedrons(RubikWidget w)
791 {
792 int face, position, orient, sizeOfFace;
793
794 for (face = 0; face < MAXFACES; face++) {
795 sizeOfFace = sizeFace(w, face);
796 if (w->rubik.cubeLoc[face])
797 (void) free((void *) w->rubik.cubeLoc[face]);
798 if (!(w->rubik.cubeLoc[face] = (RubikLoc *)
799 malloc(sizeof (RubikLoc) * sizeOfFace)))
800 XtError("Not enough memory, exiting.");
801 if (startLoc[face])
802 (void) free((void *) startLoc[face]);
803 if (!(startLoc[face] = (RubikLoc *)
804 malloc(sizeof (RubikLoc) * sizeOfFace)))
805 XtError("Not enough memory, exiting.");
806 for (position = 0; position < sizeOfFace; position++) {
807 w->rubik.cubeLoc[face][position].face = face;
808 w->rubik.cubeLoc[face][position].rotation = STRT - MAXORIENT;
809 }
810 }
811 for (orient = 0; orient < MAXORIENT; orient++) {
812 if (w->rubik.rowLoc[orient])
813 (void) free((void *) w->rubik.rowLoc[orient]);
814 if (!(w->rubik.rowLoc[orient] = (RubikLoc *)
815 malloc(sizeof (RubikLoc) * MAXMAXSIZE)))
816 XtError("Not enough memory, exiting.");
817 }
818 FlushMoves(w);
819 w->rubik.started = False;
820 }
821
822 static Boolean
SelectPolyhedrons(RubikWidget w,int x,int y,int * face,int * position)823 SelectPolyhedrons(RubikWidget w, int x, int y, int *face, int *position)
824 {
825 if (w->rubik.dim == 2)
826 return SelectPolyhedrons2D((Rubik2DWidget) w, x, y,
827 face, position);
828 else if (w->rubik.dim == 3)
829 return SelectPolyhedrons3D((Rubik3DWidget) w, x, y,
830 face, position);
831 return False;
832 }
833
834 static Boolean
NarrowSelection(RubikWidget w,int * face,int * position,int * direction)835 NarrowSelection(RubikWidget w, int *face, int *position, int *direction)
836 {
837 if (w->rubik.dim == 2)
838 return NarrowSelection2D((Rubik2DWidget) w, face, position, direction);
839 else if (w->rubik.dim == 3)
840 return NarrowSelection3D((Rubik3DWidget) w, face, position, direction);
841 return False;
842 }
843
844 static Boolean
PositionPolyhedrons(RubikWidget w,int x,int y,int * face,int * position,int * direction)845 PositionPolyhedrons(RubikWidget w, int x, int y, int *face, int *position, int *direction)
846 {
847 if (!SelectPolyhedrons(w, x, y, face, position))
848 return False;
849 return NarrowSelection(w, face, position, direction);
850 }
851
852 static void
MoveNoPolyhedrons(RubikWidget w)853 MoveNoPolyhedrons(RubikWidget w)
854 {
855 rubikCallbackStruct cb;
856
857 cb.reason = RUBIK_ILLEGAL;
858 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
859 }
860
861 static void
PracticePolyhedrons(RubikWidget w)862 PracticePolyhedrons(RubikWidget w)
863 {
864 rubikCallbackStruct cb;
865
866 cb.reason = RUBIK_PRACTICE;
867 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
868 }
869
870 static void
RandomizePolyhedrons(RubikWidget w)871 RandomizePolyhedrons(RubikWidget w)
872 {
873 rubikCallbackStruct cb;
874 int face, position, direction;
875 int avg = w->rubik.sizex + w->rubik.sizey + w->rubik.sizez / 3;
876 int big = w->rubik.sizex * w->rubik.sizey * w->rubik.sizez /
877 avg * 3 + NRAND(2);
878
879 if (big > 1000)
880 big = 1000;
881 if (w->rubik.practice)
882 PracticePolyhedrons(w);
883 cb.reason = RUBIK_RESET;
884 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
885
886 #ifdef DEBUG
887 big = 3;
888 #endif
889
890 while (big--) {
891 face = NRAND(MAXFACES);
892 position = NRAND(sizeFace(w, face));
893 direction = NRAND(MAXORIENT);
894 MoveRubik(w, face, position, direction, FALSE);
895 }
896 FlushMoves(w);
897 cb.reason = RUBIK_RANDOMIZE;
898 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
899 if (CheckSolved(w)) {
900 cb.reason = RUBIK_SOLVED;
901 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
902 }
903 }
904
905 /* Yeah this is big and ugly */
906 static void
SlideRC(int face,int direction,int h,int sizeOnOppAxis,int * newFace,int * newDirection,int * newH,int * rotate,Bool * reverse)907 SlideRC(int face, int direction, int h, int sizeOnOppAxis,
908 int *newFace, int *newDirection, int *newH,
909 int *rotate, Bool * reverse)
910 {
911 *newFace = slideNextRow[face][direction].face;
912 *rotate = slideNextRow[face][direction].rotation;
913 *newDirection = (*rotate + direction) % MAXORIENT;
914 switch (*rotate) {
915 case TOP:
916 *newH = h;
917 *reverse = False;
918 break;
919 case RIGHT:
920 if (*newDirection == TOP || *newDirection == BOTTOM) {
921 *newH = sizeOnOppAxis - 1 - h;
922 *reverse = False;
923 } else { /* *newDirection == RIGHT || *newDirect
924 ion == LEFT */
925 *newH = h;
926 *reverse = True;
927 }
928 break;
929 case BOTTOM:
930 *newH = sizeOnOppAxis - 1 - h;
931 *reverse = True;
932 break;
933 case LEFT:
934 if (*newDirection == TOP || *newDirection == BOTTOM) {
935 *newH = h;
936 *reverse = True;
937 } else { /* *newDirection == RIGHT || *newDirect
938 ion == LEFT */
939 *newH = sizeOnOppAxis - 1 - h;
940 *reverse = False;
941 }
942 break;
943 default:
944 (void) printf("SlideRC: rotate %d\n", *rotate);
945 }
946 }
947
948
949 static void
MovePolyhedrons(RubikWidget w,int face,int position,int direction)950 MovePolyhedrons(RubikWidget w, int face, int position, int direction)
951 {
952 int newFace, newDirection, rotate, reverse = FALSE;
953 int h, k, newH = 0;
954 int i, j, sizeOfRow, sizeOfColumn, sizeOnAxis, sizeOnOppAxis;
955
956 w->rubik.degreeTurn = (checkFaceSquare(w,
957 rowToRotate[face][direction])) ? 90 : 180;
958 faceSizes(w, face, &sizeOfRow, &sizeOfColumn);
959 i = position % sizeOfRow;
960 j = position / sizeOfRow;
961 h = (direction == TOP || direction == BOTTOM) ? i : j;
962 if (direction == TOP || direction == BOTTOM) {
963 sizeOnAxis = sizeOfColumn;
964 sizeOnOppAxis = sizeOfRow;
965 } else {
966 sizeOnAxis = sizeOfRow;
967 sizeOnOppAxis = sizeOfColumn;
968 }
969 /* rotate sides CW or CCW or HALF */
970
971 if (h == sizeOnOppAxis - 1) {
972 newDirection = (direction == TOP || direction == BOTTOM) ?
973 TOP : RIGHT;
974 if (w->rubik.degreeTurn == 180)
975 RotateFace(w, rowToRotate[face][newDirection], HALF);
976 else if (direction == TOP || direction == RIGHT)
977 RotateFace(w, rowToRotate[face][newDirection], CW);
978 else /* direction == BOTTOM || direction == LEFT */
979 RotateFace(w, rowToRotate[face][newDirection], CCW);
980 }
981 if (h == 0) {
982 newDirection = (direction == TOP || direction == BOTTOM) ?
983 BOTTOM : LEFT;
984 if (w->rubik.degreeTurn == 180)
985 RotateFace(w, rowToRotate[face][newDirection], HALF);
986 else if (direction == TOP || direction == RIGHT)
987 RotateFace(w, rowToRotate[face][newDirection], CCW);
988 else /* direction == BOTTOM || direction == LEFT */
989 RotateFace(w, rowToRotate[face][newDirection], CW);
990 }
991 /* Slide rows */
992 ReadRC(w, face, direction, h, 0, sizeOnAxis);
993 if (w->rubik.degreeTurn == 180) {
994 int sizeOnDepthAxis;
995
996 SlideRC(face, direction, h, sizeOnOppAxis,
997 &newFace, &newDirection, &newH, &rotate, &reverse);
998 sizeOnDepthAxis = sizeFace(w, newFace) / sizeOnOppAxis;
999 ReadRC(w, newFace, newDirection, newH, 1, sizeOnDepthAxis);
1000 RotateRC(w, rotate, 0, sizeOnAxis);
1001 if (reverse == True)
1002 ReverseRC(w, 0, sizeOnAxis);
1003 face = newFace;
1004 direction = newDirection;
1005 h = newH;
1006 for (k = 2; k <= MAXORIENT + 1; k++) {
1007 SlideRC(face, direction, h, sizeOnOppAxis,
1008 &newFace, &newDirection, &newH, &rotate, &reverse);
1009 if (k != MAXORIENT && k != MAXORIENT + 1)
1010 ReadRC(w, newFace, newDirection, newH, k,
1011 (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1012 RotateRC(w, rotate, k - 2,
1013 (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1014 if (k != MAXORIENT + 1)
1015 RotateRC(w, rotate, k - 1,
1016 (k % 2) ? sizeOnAxis : sizeOnDepthAxis);
1017 if (reverse == True) {
1018 ReverseRC(w, k - 2,
1019 (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1020 if (k != MAXORIENT + 1)
1021 ReverseRC(w, k - 1,
1022 (k % 2) ? sizeOnAxis : sizeOnDepthAxis);
1023 }
1024 WriteRC(w, newFace, newDirection, newH, k - 2,
1025 (k % 2) ? sizeOnDepthAxis : sizeOnAxis);
1026 face = newFace;
1027 direction = newDirection;
1028 h = newH;
1029 }
1030 } else {
1031 for (k = 1; k <= MAXORIENT; k++) {
1032 SlideRC(face, direction, h, sizeOnOppAxis,
1033 &newFace, &newDirection, &newH, &rotate, &reverse);
1034 if (k != MAXORIENT)
1035 ReadRC(w, newFace, newDirection, newH, k, sizeOnAxis);
1036 RotateRC(w, rotate, k - 1, sizeOnAxis);
1037 if (reverse == TRUE)
1038 ReverseRC(w, k - 1, sizeOnAxis);
1039 WriteRC(w, newFace, newDirection, newH, k - 1, sizeOnAxis);
1040 face = newFace;
1041 direction = newDirection;
1042 h = newH;
1043 }
1044 }
1045 }
1046
1047 static void
ReadRC(RubikWidget w,int face,int dir,int h,int orient,int size)1048 ReadRC(RubikWidget w, int face, int dir, int h, int orient, int size)
1049 {
1050 int g, sizeOfRow;
1051
1052 sizeOfRow = sizeRow(w, face);
1053 if (dir == TOP || dir == BOTTOM)
1054 for (g = 0; g < size; g++)
1055 w->rubik.rowLoc[orient][g] =
1056 w->rubik.cubeLoc[face][g * sizeOfRow + h];
1057 else /* dir == RIGHT || dir == LEFT */
1058 for (g = 0; g < size; g++)
1059 w->rubik.rowLoc[orient][g] =
1060 w->rubik.cubeLoc[face][h * sizeOfRow + g];
1061 }
1062
1063 static void
RotateRC(RubikWidget w,int rotate,int orient,int size)1064 RotateRC(RubikWidget w, int rotate, int orient, int size)
1065 {
1066 int g;
1067
1068 for (g = 0; g < size; g++)
1069 w->rubik.rowLoc[orient][g].rotation =
1070 (w->rubik.rowLoc[orient][g].rotation + rotate) % MAXORIENT;
1071 }
1072
1073 static void
ReverseRC(RubikWidget w,int orient,int size)1074 ReverseRC(RubikWidget w, int orient, int size)
1075 {
1076 int g;
1077 RubikLoc temp;
1078
1079 for (g = 0; g < size / 2; g++) {
1080 temp = w->rubik.rowLoc[orient][size - 1 - g];
1081 w->rubik.rowLoc[orient][size - 1 - g] = w->rubik.rowLoc[orient][g];
1082 w->rubik.rowLoc[orient][g] = temp;
1083 }
1084 }
1085
1086 static void
WriteRC(RubikWidget w,int face,int dir,int h,int orient,int size)1087 WriteRC(RubikWidget w, int face, int dir, int h, int orient, int size)
1088 {
1089 int g, position, sizeOfRow;
1090
1091 sizeOfRow = sizeRow(w, face);
1092 if (dir == TOP || dir == BOTTOM) {
1093 for (g = 0; g < size; g++) {
1094 position = g * sizeOfRow + h;
1095 w->rubik.cubeLoc[face][position] = w->rubik.rowLoc[orient][g];
1096 DrawSquare(w, face, position, FALSE);
1097 }
1098 } else { /* dir == RIGHT || dir == LEFT */
1099 for (g = 0; g < size; g++) {
1100 position = h * sizeOfRow + g;
1101 w->rubik.cubeLoc[face][position] = w->rubik.rowLoc[orient][g];
1102 DrawSquare(w, face, position, FALSE);
1103 }
1104 }
1105 }
1106
1107 static void
RotateFace(RubikWidget w,int face,int direction)1108 RotateFace(RubikWidget w, int face, int direction)
1109 {
1110 int position, i, j, sizeOfRow, sizeOfColumn, sizeOnPlane;
1111 RubikLoc *faceLoc = NULL;
1112
1113 faceSizes(w, face, &sizeOfRow, &sizeOfColumn);
1114 sizeOnPlane = sizeOfRow * sizeOfColumn;
1115 if ((faceLoc = (RubikLoc *) malloc(sizeOnPlane * sizeof (RubikLoc))) ==
1116 NULL)
1117 (void) fprintf(stderr,
1118 "Could not allocate memory for rubik face position info\n");
1119 /* Read Face */
1120 for (position = 0; position < sizeOnPlane; position++)
1121 faceLoc[position] = w->rubik.cubeLoc[face][position];
1122 /* Write Face */
1123 for (position = 0; position < sizeOnPlane; position++) {
1124 i = position % sizeOfRow;
1125 j = position / sizeOfRow;
1126 if (direction == CW)
1127 w->rubik.cubeLoc[face][position] =
1128 faceLoc[(sizeOfRow - i - 1) * sizeOfRow + j];
1129 else if (direction == CCW)
1130 w->rubik.cubeLoc[face][position] =
1131 faceLoc[i * sizeOfRow + sizeOfColumn - j - 1];
1132 else /* (direction == HALF) */
1133 w->rubik.cubeLoc[face][position] =
1134 faceLoc[sizeOfRow - i - 1 + (sizeOfColumn - j - 1) * sizeOfRow];
1135
1136 w->rubik.cubeLoc[face][position].rotation =
1137 (w->rubik.cubeLoc[face][position].rotation +
1138 direction - MAXORIENT) % MAXORIENT;
1139 DrawSquare(w, face, position, FALSE);
1140 }
1141 if (faceLoc != NULL)
1142 (void) free((void *) faceLoc);
1143 }
1144
1145 void
DrawAllPolyhedrons(RubikWidget w)1146 DrawAllPolyhedrons(RubikWidget w)
1147 {
1148 int face, position;
1149
1150 for (face = 0; face < MAXFACES; face++)
1151 for (position = 0; position < sizeFace(w, face); position++)
1152 DrawSquare(w, face, position, FALSE);
1153 }
1154
1155 static void
DrawSquare(RubikWidget w,int face,int position,int offset)1156 DrawSquare(RubikWidget w, int face, int position, int offset)
1157 {
1158 if (w->rubik.dim == 2)
1159 DrawSquare2D((Rubik2DWidget) w, face, position, offset);
1160 else if (w->rubik.dim == 3)
1161 DrawSquare3D((Rubik3DWidget) w, face, position, offset);
1162 }
1163
1164 Boolean
CheckSolved(RubikWidget w)1165 CheckSolved(RubikWidget w)
1166 {
1167 int face, position;
1168 RubikLoc test;
1169
1170 for (face = 0; face < MAXFACES; face++)
1171 for (position = 0; position < sizeFace(w, face); position++) {
1172 if (!position) {
1173 test.face = w->rubik.cubeLoc[face][position].face;
1174 test.rotation = w->rubik.cubeLoc[face][position].rotation;
1175 } else if (test.face != /*face */
1176 w->rubik.cubeLoc[face][position].face ||
1177 (w->rubik.orient && test.rotation != /*STRT - MAXORIENT */
1178 w->rubik.cubeLoc[face][position].rotation))
1179 return False;
1180 }
1181 return True;
1182 }
1183
1184 static int
CheckMoveDir(RubikWidget w,int face,int position1,int position2,int * direction)1185 CheckMoveDir(RubikWidget w, int face, int position1, int position2, int *direction)
1186 {
1187 int count = 0;
1188 int column1, column2, row1, row2, sizeOfRow;
1189
1190 sizeOfRow = sizeRow(w, face);
1191 column1 = position1 % sizeOfRow;
1192 column2 = position2 % sizeOfRow;
1193 row1 = position1 / sizeOfRow;
1194 row2 = position2 / sizeOfRow;
1195 if (column1 == column2 && row1 != row2) {
1196 *direction = (row2 > row1) ? BOTTOM : TOP;
1197 count = 1;
1198 } else if (row1 == row2 && column1 != column2) {
1199 *direction = (column2 > column1) ? RIGHT : LEFT;
1200 count = 1;
1201 } else if (row1 == row2 && column1 == column2)
1202 count = 2;
1203 return count;
1204 }
1205
1206
1207 #ifdef DEBUG
1208
1209 void
PrintCube(RubikWidget w)1210 PrintCube(RubikWidget w)
1211 {
1212 int face, position, sizeOfRow, sizeOfColumn;
1213
1214 for (face = 0; face < MAXFACES; face++) {
1215 faceSizes(rp, face, &sizeOfRow, &sizeOfColumn);
1216 for (position = 0; position < sizeOfRow * sizeOfColumn; position++) {
1217 (void) printf("%d %d ", w->rubik.cubeLoc[face][position].face,
1218 w->rubik.cubeLoc[face][position].rotation);
1219 if (!((position + 1) % sizeOfRow))
1220 (void) printf("\n");
1221 }
1222 (void) printf("\n");
1223 }
1224 (void) printf("\n");
1225 }
1226
1227 void
PrintRow(RubikWidget w,int orient,int size)1228 PrintRow(RubikWidget w, int orient, int size)
1229 {
1230 int i;
1231
1232 (void) printf("Row %d:\n", orient);
1233 for (i = 0; i < size; i++)
1234 (void) printf("%d %d ", w->rubik.rowLoc[orient][i].face,
1235 w->rubik.rowLoc[orient][i].rotation);
1236 (void) printf("\n");
1237 }
1238
1239 #endif
1240