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