1 /*-
2 # X-BASED CUBES
3 #
4 # Cubes.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 Cubes */
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 "CubesP.h"
42
43 #ifndef DATAFILE
44 #define DATAFILE "/usr/games/lib/cubes.data"
45 #endif
46
47 static void InitializeCubes(Widget request, Widget renew);
48 static void ExposeCubes(Widget renew, XEvent * event, Region region);
49 static void ResizeCubes(CubesWidget w);
50 static void DestroyCubes(Widget old);
51 static Boolean SetValuesCubes(Widget current, Widget request, Widget renew);
52
53 static void QuitCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
54 static void MoveCubesOut(CubesWidget w, XEvent * event, char **args, int nArgs);
55 static void MoveCubesTop(CubesWidget w, XEvent * event, char **args, int nArgs);
56 static void MoveCubesLeft(CubesWidget w, XEvent * event, char **args, int nArgs);
57 static void MoveCubesIn(CubesWidget w, XEvent * event, char **args, int nArgs);
58 static void MoveCubesRight(CubesWidget w, XEvent * event, char **args, int nArgs);
59 static void MoveCubesBottom(CubesWidget w, XEvent * event, char **args, int nArgs);
60 static void SelectCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
61 static void ReleaseCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
62 static void RandomizeCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
63 static void RandomizeCubesMaybe(CubesWidget w, XEvent * event, char **args, int nArgs);
64 static void GetCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
65 static void WriteCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
66 static void UndoCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
67 static void SolveCubes(CubesWidget w, XEvent * event, char **args, int nArgs);
68 static int MoveCubes(CubesWidget w, int direction, int control);
69
70 static int PositionToBrick(CubesWidget w, int x, int y, int *i, int *j, int *k);
71 static int MovableBrick(CubesWidget w);
72 static void SelectBricks(CubesWidget w);
73 static void SetAllColors(CubesWidget w, Boolean init);
74 static void CheckBricks(CubesWidget w);
75 static void ResetBricks(CubesWidget w);
76 static void ResizeBricks(CubesWidget w);
77 static void MoveNoBricks(CubesWidget w);
78 static int MoveBricksDir(CubesWidget w, int direction);
79 static void RandomizeBricks(CubesWidget w);
80 static void MoveBricks(CubesWidget w, int from);
81 static int ExchangeBricks(CubesWidget w, int pos1, int pos2);
82 static void DrawFrame(CubesWidget w, GC gc);
83 static void DrawBrick(CubesWidget w, int pos, Boolean blank, Boolean erase, int offset);
84 static int Row(CubesWidget w, int pos);
85 static int Column(CubesWidget w, int pos);
86 static int Stack(CubesWidget w, int pos);
87 static int int2String(char *buf, int number, int base);
88
89 static char defaultTranslationsCubes[] =
90 "<KeyPress>q: Quit()\n\
91 Ctrl<KeyPress>C: Quit()\n\
92 <KeyPress>o: MoveOut()\n\
93 <KeyPress>KP_Divide: MoveOut()\n\
94 <KeyPress>R5: MoveOut()\n\
95 <KeyPress>Up: MoveTop()\n\
96 <KeyPress>KP_8: MoveTop()\n\
97 <KeyPress>R8: MoveTop()\n\
98 <KeyPress>Left: MoveLeft()\n\
99 <KeyPress>KP_4: MoveLeft()\n\
100 <KeyPress>R10: MoveLeft()\n\
101 <KeyPress>i: MoveIn()\n\
102 <KeyPress>Begin: MoveIn()\n\
103 <KeyPress>KP_5: MoveIn()\n\
104 <KeyPress>R11: MoveIn()\n\
105 <KeyPress>Right: MoveRight()\n\
106 <KeyPress>KP_6: MoveRight()\n\
107 <KeyPress>R12: MoveRight()\n\
108 <KeyPress>Down: MoveBottom()\n\
109 <KeyPress>KP_2: MoveBottom()\n\
110 <KeyPress>R14: MoveBottom()\n\
111 <Btn1Down>: Select()\n\
112 <Btn1Up>: Release()\n\
113 <KeyPress>r: Randomize()\n\
114 <Btn3Down>(2+): Randomize()\n\
115 <Btn3Down>: RandomizeMaybe()\n\
116 <KeyPress>g: Get()\n\
117 <KeyPress>w: Write()\n\
118 <KeyPress>u: Undo()\n\
119 <KeyPress>s: Solve()";
120
121 static XtActionsRec actionsListCubes[] =
122 {
123 {"Quit", (XtActionProc) QuitCubes},
124 {"MoveOut", (XtActionProc) MoveCubesOut},
125 {"MoveTop", (XtActionProc) MoveCubesTop},
126 {"MoveLeft", (XtActionProc) MoveCubesLeft},
127 {"MoveIn", (XtActionProc) MoveCubesIn},
128 {"MoveRight", (XtActionProc) MoveCubesRight},
129 {"MoveBottom", (XtActionProc) MoveCubesBottom},
130 {"Select", (XtActionProc) SelectCubes},
131 {"Release", (XtActionProc) ReleaseCubes},
132 {"Randomize", (XtActionProc) RandomizeCubes},
133 {"RandomizeMaybe", (XtActionProc) RandomizeCubesMaybe},
134 {"Get", (XtActionProc) GetCubes},
135 {"Write", (XtActionProc) WriteCubes},
136 {"Undo", (XtActionProc) UndoCubes},
137 {"Solve", (XtActionProc) SolveCubes}
138 };
139
140 static XtResource resourcesCubes[] =
141 {
142 {XtNuserName, XtCUserName, XtRString, sizeof (String),
143 XtOffset(CubesWidget, cubes.username), XtRString, "nobody"},
144 {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
145 XtOffset(CubesWidget, cubes.foreground), XtRString, XtDefaultForeground},
146 {XtNbrickColor, XtCColor, XtRPixel, sizeof (Pixel),
147 XtOffset(CubesWidget, cubes.brickColor), XtRString, XtDefaultForeground},
148 {XtNbrickBorder, XtCColor, XtRPixel, sizeof (Pixel),
149 XtOffset(CubesWidget, cubes.borderColor), XtRString, XtDefaultBackground},
150 {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
151 XtOffset(CubesWidget, core.width), XtRString, "100"},
152 {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
153 XtOffset(CubesWidget, core.height), XtRString, "300"},
154 {XtNsizeX, XtCSizeX, XtRInt, sizeof (int),
155 XtOffset(CubesWidget, cubes.sizeX), XtRString, "3"}, /* DEFAULTCUBES */
156 {XtNsizeY, XtCSizeY, XtRInt, sizeof (int),
157 XtOffset(CubesWidget, cubes.sizeY), XtRString, "3"}, /* DEFAULTCUBES */
158 {XtNsizeZ, XtCSizeZ, XtRInt, sizeof (int),
159 XtOffset(CubesWidget, cubes.sizeZ), XtRString, "3"}, /* DEFAULTCUBES */
160 {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
161 XtOffset(CubesWidget, cubes.mono), XtRString, "FALSE"},
162 {XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
163 XtOffset(CubesWidget, cubes.reverse), XtRString, "FALSE"},
164 {XtNbase, XtCBase, XtRInt, sizeof (int),
165 XtOffset(CubesWidget, cubes.base), XtRString, "10"},
166 {XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
167 XtOffset(CubesWidget, cubes.started), XtRString, "FALSE"},
168 {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
169 XtOffset(CubesWidget, cubes.select), XtRCallback, NULL}
170 };
171
172 CubesClassRec cubesClassRec =
173 {
174 {
175 (WidgetClass) & widgetClassRec, /* superclass */
176 "Cubes", /* class name */
177 sizeof (CubesRec), /* widget size */
178 NULL, /* class initialize */
179 NULL, /* class part initialize */
180 FALSE, /* class inited */
181 (XtInitProc) InitializeCubes, /* initialize */
182 NULL, /* initialize hook */
183 XtInheritRealize, /* realize */
184 actionsListCubes, /* actions */
185 XtNumber(actionsListCubes), /* num actions */
186 resourcesCubes, /* resources */
187 XtNumber(resourcesCubes), /* num resources */
188 NULLQUARK, /* xrm class */
189 TRUE, /* compress motion */
190 TRUE, /* compress exposure */
191 TRUE, /* compress enterleave */
192 TRUE, /* visible interest */
193 (XtWidgetProc) DestroyCubes, /* destroy */
194 (XtWidgetProc) ResizeCubes, /* resize */
195 (XtExposeProc) ExposeCubes, /* expose */
196 (XtSetValuesFunc) SetValuesCubes, /* set values */
197 NULL, /* set values hook */
198 XtInheritSetValuesAlmost, /* set values almost */
199 NULL, /* get values hook */
200 NULL, /* accept focus */
201 XtVersion, /* version */
202 NULL, /* callback private */
203 defaultTranslationsCubes, /* tm table */
204 NULL, /* query geometry */
205 NULL, /* display accelerator */
206 NULL /* extension */
207 },
208 {
209 0 /* ignore */
210 }
211 };
212
213 WidgetClass cubesWidgetClass = (WidgetClass) & cubesClassRec;
214
215 #ifndef HAVE_USLEEP
216 #if !defined( VMS ) || defined( XVMSUTILS ) || ( __VMS_VER >= 70000000 )
217 #ifdef USE_XVMSUTILS
218 #include <X11/unix_time.h>
219 #endif
220 #if HAVE_SYS_TIME_H
221 #include <sys/time.h>
222 #else
223 #if HAVE_SYS_SELECT_H
224 #include <sys/select.h>
225 #endif
226 #endif
227 #endif
228 #if defined(SYSV) || defined(SVR4)
229 #ifdef LESS_THAN_AIX3_2
230 #include <sys/poll.h>
231 #else /* !LESS_THAN_AIX3_2 */
232 #include <poll.h>
233 #endif /* !LESS_THAN_AIX3_2 */
234 #endif /* defined(SYSV) || defined(SVR4) */
235
236 static int
usleep(unsigned int usec)237 usleep(unsigned int usec)
238 {
239 #if (defined (SYSV) || defined(SVR4)) && !defined(__hpux)
240 #if defined(HAVE_NANOSLEEP)
241 {
242 struct timespec rqt;
243
244 rqt.tv_nsec = 1000 * (usec % (unsigned int) 1000000);
245 rqt.tv_sec = usec / (unsigned int) 1000000;
246 return nanosleep(&rqt, NULL);
247 }
248 #else
249 (void) poll((void *) 0, (int) 0, usec / 1000); /* ms resolution */
250 #endif
251 #else
252 #ifdef VMS
253 long timadr[2];
254
255 if (usec != 0) {
256 timadr[0] = -usec * 10;
257 timadr[1] = -1;
258
259 sys$setimr(4, &timadr, 0, 0, 0);
260 sys$waitfr(4);
261 }
262 #else
263 struct timeval time_out;
264
265 #if 0
266 /* (!defined(AIXV3) && !defined(__hpux)) */
267 extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
268
269 #endif
270
271 time_out.tv_usec = usec % (unsigned int) 1000000;
272 time_out.tv_sec = usec / (unsigned int) 1000000;
273 (void) select(0, (void *) 0, (void *) 0, (void *) 0, &time_out);
274 #endif
275 #endif
276 return 0;
277 }
278 #endif
279
280 static void
Sleep(unsigned int cMilliseconds)281 Sleep(unsigned int cMilliseconds)
282 {
283 (void) usleep(cMilliseconds * 1000);
284 }
285
286 static void
InitializeCubes(Widget request,Widget renew)287 InitializeCubes(Widget request, Widget renew)
288 {
289 CubesWidget w = (CubesWidget) renew;
290
291 w->cubes.brickOfPosition = NULL;
292 CheckBricks(w);
293 InitMoves();
294 ResetBricks(w);
295 (void) SRAND(getpid());
296 w->cubes.depth = DefaultDepthOfScreen(XtScreen(w));
297 SetAllColors(w, True);
298 ResizeCubes(w);
299 }
300
301 static void
DestroyCubes(Widget old)302 DestroyCubes(Widget old)
303 {
304 CubesWidget w = (CubesWidget) old;
305
306 XtReleaseGC(old, w->cubes.brickGC);
307 XtReleaseGC(old, w->cubes.borderGC);
308 XtReleaseGC(old, w->cubes.puzzleGC);
309 XtReleaseGC(old, w->cubes.inverseGC);
310 XtRemoveCallbacks(old, XtNselectCallback, w->cubes.select);
311 }
312
313 static void
ResizeCubes(CubesWidget w)314 ResizeCubes(CubesWidget w)
315 {
316 w->cubes.delta.x = 3;
317 w->cubes.delta.y = 3;
318 w->cubes.offset.x = MAX(((int) w->core.width - w->cubes.delta.x) /
319 w->cubes.sizeX, 0);
320 w->cubes.offset.y = MAX(((int) w->core.height - w->cubes.delta.y) /
321 w->cubes.sizeY, 0);
322 if (w->cubes.offset.y >= w->cubes.offset.x) {
323 w->cubes.vertical = TRUE;
324 w->cubes.offset.y = MAX(((int) w->core.height / w->cubes.sizeZ -
325 w->cubes.delta.y) / w->cubes.sizeY, 0);
326 } else {
327 w->cubes.vertical = FALSE;
328 w->cubes.offset.x = MAX(((int) w->core.width / w->cubes.sizeZ -
329 w->cubes.delta.x) / w->cubes.sizeX, 0);
330 }
331 w->cubes.faceSize.x = w->cubes.offset.x * w->cubes.sizeX +
332 w->cubes.delta.x + 2;
333 w->cubes.faceSize.y = w->cubes.offset.y * w->cubes.sizeY +
334 w->cubes.delta.y + 2;
335 if (w->cubes.vertical) {
336 w->cubes.puzzleSize.x = w->cubes.faceSize.x;
337 w->cubes.puzzleSize.y = (w->cubes.faceSize.y - w->cubes.delta.y) *
338 w->cubes.sizeZ + w->cubes.delta.y;
339 } else {
340 w->cubes.puzzleSize.x = (w->cubes.faceSize.x - w->cubes.delta.x) *
341 w->cubes.sizeZ + w->cubes.delta.x;
342 w->cubes.puzzleSize.y = w->cubes.faceSize.y;
343 }
344 w->cubes.puzzleOffset.x = ((int) w->core.width -
345 w->cubes.puzzleSize.x + 2) / 2;
346 w->cubes.puzzleOffset.y = ((int) w->core.height -
347 w->cubes.puzzleSize.y + 2) / 2;
348 w->cubes.brickSize.x = MAX(w->cubes.offset.x - w->cubes.delta.x, 0);
349 w->cubes.brickSize.y = MAX(w->cubes.offset.y - w->cubes.delta.y, 0);
350 ResizeBricks(w);
351 }
352
353 static void
ExposeCubes(Widget renew,XEvent * event,Region region)354 ExposeCubes(Widget renew, XEvent * event, Region region)
355 {
356 CubesWidget w = (CubesWidget) renew;
357
358 if (w->core.visible) {
359 if (w->cubes.reverse)
360 XFillRectangle(XtDisplay(w), XtWindow(w),
361 w->cubes.inverseGC, 0, 0, w->core.width, w->core.height);
362 DrawFrame(w, w->cubes.puzzleGC);
363 DrawAllBricks(w);
364 }
365 }
366
367 static Boolean
SetValuesCubes(Widget current,Widget request,Widget renew)368 SetValuesCubes(Widget current, Widget request, Widget renew)
369 {
370 CubesWidget c = (CubesWidget) current, w = (CubesWidget) renew;
371 Boolean redraw = FALSE;
372 Boolean redrawBricks = FALSE;
373
374 CheckBricks(w);
375 if (w->core.background_pixel != c->core.background_pixel ||
376 w->cubes.foreground != c->cubes.foreground ||
377 w->cubes.borderColor != c->cubes.borderColor ||
378 w->cubes.brickColor != c->cubes.brickColor ||
379 w->cubes.reverse != c->cubes.reverse ||
380 w->cubes.mono != c->cubes.mono) {
381 SetAllColors(w, False);
382 redrawBricks = True;
383 }
384 if (w->cubes.sizeX != c->cubes.sizeX ||
385 w->cubes.sizeY != c->cubes.sizeY ||
386 w->cubes.sizeZ != c->cubes.sizeZ ||
387 w->cubes.base != c->cubes.base) {
388 ResetBricks(w);
389 ResizeCubes(w);
390 redraw = TRUE;
391 } else if (w->cubes.offset.x != c->cubes.offset.x ||
392 w->cubes.offset.y != c->cubes.offset.y) {
393 ResizeCubes(w);
394 redraw = TRUE;
395 }
396 if (redrawBricks && !redraw && XtIsRealized(renew) && renew->core.visible) {
397 DrawFrame(c, c->cubes.inverseGC);
398 DrawFrame(w, w->cubes.puzzleGC);
399 DrawAllBricks(w);
400 }
401 return (redraw);
402 }
403
404 static void
QuitCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)405 QuitCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
406 {
407 XtCloseDisplay(XtDisplay(w));
408 exit(0);
409 }
410
411 static void
SelectCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)412 SelectCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
413 {
414 int pos, i, j, k, rowType;
415
416 pos = PositionToBrick(w, event->xbutton.x, event->xbutton.y, &i, &j, &k);
417 if (pos >= 0) {
418 if (CheckSolved(w)) {
419 MoveNoBricks(w);
420 w->cubes.currentPosition = -1;
421 return;
422 }
423 w->cubes.currentPosition = pos;
424 w->cubes.currentRow[0] = i;
425 w->cubes.currentRow[1] = j;
426 w->cubes.currentRow[2] = k;
427 rowType = MovableBrick(w);
428 if (rowType < 0) {
429 cubesCallbackStruct cb;
430
431 DrawBrick(w, w->cubes.currentPosition, rowType == CUBES_SPACE, False, TRUE);
432 XFlush(XtDisplay(w));
433 Sleep(100);
434 DrawBrick(w, w->cubes.currentPosition, True, True, TRUE);
435 if (rowType != CUBES_SPACE)
436 DrawBrick(w, w->cubes.currentPosition, False, False, FALSE);
437 cb.reason = rowType;
438 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
439 w->cubes.currentPosition = -1;
440 return;
441 }
442 DrawBrick(w, w->cubes.currentPosition, False, False, TRUE);
443 } else
444 w->cubes.currentPosition = -1;
445 }
446
447 static void
ReleaseCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)448 ReleaseCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
449 {
450 if (w->cubes.currentPosition == -1)
451 return;
452 DrawBrick(w, w->cubes.currentPosition, True, True, TRUE);
453 DrawBrick(w, w->cubes.currentPosition, False, False, FALSE);
454 SelectBricks(w);
455 w->cubes.currentPosition = -1;
456 }
457
458 static void
RandomizeCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)459 RandomizeCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
460 {
461 RandomizeBricks(w);
462 }
463
464 static void
RandomizeCubesMaybe(CubesWidget w,XEvent * event,char ** args,int nArgs)465 RandomizeCubesMaybe(CubesWidget w, XEvent * event, char **args, int nArgs)
466 {
467 if (!w->cubes.started)
468 RandomizeBricks(w);
469 }
470
471 static void
GetCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)472 GetCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
473 {
474 FILE *fp;
475 char c;
476 int i, sizeX, sizeY, sizeZ, moves;
477 cubesCallbackStruct cb;
478
479 if ((fp = fopen(DATAFILE, "r")) == NULL)
480 (void) printf("Can not read %s for get.\n", DATAFILE);
481 else {
482 FlushMoves(w);
483 while ((c = getc(fp)) != EOF && c != SYMBOL);
484 (void) fscanf(fp, "%d", &sizeX);
485 if (sizeX >= MINCUBES) {
486 for (i = w->cubes.sizeX; i < sizeX; i++) {
487 cb.reason = CUBES_INC_X;
488 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
489 }
490 for (i = w->cubes.sizeX; i > sizeX; i--) {
491 cb.reason = CUBES_DEC_X;
492 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
493 }
494 } else
495 (void) printf("%s corrupted: sizeX %d should be between %d and MAXINT\n",
496 DATAFILE, sizeX, MINCUBES);
497 while ((c = getc(fp)) != EOF && c != SYMBOL);
498 (void) fscanf(fp, "%d", &sizeY);
499 if (sizeY >= MINCUBES) {
500 for (i = w->cubes.sizeY; i < sizeY; i++) {
501 cb.reason = CUBES_INC_Y;
502 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
503 }
504 for (i = w->cubes.sizeY; i > sizeY; i--) {
505 cb.reason = CUBES_DEC_Y;
506 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
507 }
508 } else
509 (void) printf("%s corrupted: sizeY %d should be between %d and MAXINT\n",
510 DATAFILE, sizeY, MINCUBES);
511 while ((c = getc(fp)) != EOF && c != SYMBOL);
512 (void) fscanf(fp, "%d", &sizeZ);
513 if (sizeZ >= MINCUBES) {
514 for (i = w->cubes.sizeZ; i < sizeZ; i++) {
515 cb.reason = CUBES_INC_Z;
516 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
517 }
518 for (i = w->cubes.sizeZ; i > sizeZ; i--) {
519 cb.reason = CUBES_DEC_Z;
520 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
521 }
522 } else
523 (void) printf("%s corrupted: sizeZ %d should be between %d and MAXINT\n",
524 DATAFILE, sizeZ, MINCUBES);
525 while ((c = getc(fp)) != EOF && c != SYMBOL);
526 (void) fscanf(fp, "%d", &moves);
527 ScanStartPosition(fp, w);
528 cb.reason = CUBES_RESTORE;
529 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
530 SetStartPosition(w);
531 ScanMoves(fp, w, moves);
532 (void) fclose(fp);
533 (void) printf("%s: sizeX %d, sizeY %d, sizeZ %d, moves %d.\n",
534 DATAFILE, sizeX, sizeY, sizeZ, moves);
535 }
536 }
537
538 static void
WriteCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)539 WriteCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
540 {
541 FILE *fp;
542
543 if ((fp = fopen(DATAFILE, "w")) == NULL)
544 (void) printf("Can not write to %s.\n", DATAFILE);
545 else {
546 (void) fprintf(fp, "sizeX%c %d\n", SYMBOL, w->cubes.sizeX);
547 (void) fprintf(fp, "sizeY%c %d\n", SYMBOL, w->cubes.sizeY);
548 (void) fprintf(fp, "sizeZ%c %d\n", SYMBOL, w->cubes.sizeZ);
549 (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
550 PrintStartPosition(fp, w);
551 PrintMoves(fp);
552 (void) fclose(fp);
553 (void) printf("Saved to %s.\n", DATAFILE);
554 }
555 }
556
557 static void
UndoCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)558 UndoCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
559 {
560 if (MadeMoves()) {
561 int direction;
562
563 GetMove(&direction);
564 direction = (direction < 4) ? (direction + 2) % 4 :
565 ((direction == IN) ? OUT : IN);
566
567 if (MoveBricksDir(w, direction)) {
568 cubesCallbackStruct cb;
569
570 cb.reason = CUBES_UNDO;
571 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
572 }
573 }
574 }
575
576 static void
SolveCubes(CubesWidget w,XEvent * event,char ** args,int nArgs)577 SolveCubes(CubesWidget w, XEvent * event, char **args, int nArgs)
578 {
579 #if 0
580 SolveBricks(w); /* Sorry, this is not implemented */
581 #endif
582 }
583
584 static void
MoveCubesOut(CubesWidget w,XEvent * event,char ** args,int nArgs)585 MoveCubesOut(CubesWidget w, XEvent * event, char **args, int nArgs)
586 {
587 (void) MoveCubes(w, OUT, (int) (event->xkey.state & ControlMask));
588 }
589
590 static void
MoveCubesTop(CubesWidget w,XEvent * event,char ** args,int nArgs)591 MoveCubesTop(CubesWidget w, XEvent * event, char **args, int nArgs)
592 {
593 (void) MoveCubes(w, TOP, (int) (event->xkey.state & ControlMask));
594 }
595
596 static void
MoveCubesLeft(CubesWidget w,XEvent * event,char ** args,int nArgs)597 MoveCubesLeft(CubesWidget w, XEvent * event, char **args, int nArgs)
598 {
599 (void) MoveCubes(w, LEFT, (int) (event->xkey.state & ControlMask));
600 }
601
602 static void
MoveCubesIn(CubesWidget w,XEvent * event,char ** args,int nArgs)603 MoveCubesIn(CubesWidget w, XEvent * event, char **args, int nArgs)
604 {
605 (void) MoveCubes(w, IN, (int) (event->xkey.state & ControlMask));
606 }
607
608 static void
MoveCubesRight(CubesWidget w,XEvent * event,char ** args,int nArgs)609 MoveCubesRight(CubesWidget w, XEvent * event, char **args, int nArgs)
610 {
611 (void) MoveCubes(w, RIGHT, (int) (event->xkey.state & ControlMask));
612 }
613
614 static void
MoveCubesBottom(CubesWidget w,XEvent * event,char ** args,int nArgs)615 MoveCubesBottom(CubesWidget w, XEvent * event, char **args, int nArgs)
616 {
617 (void) MoveCubes(w, BOTTOM, (int) (event->xkey.state & ControlMask));
618 }
619
620 static int
MoveCubes(CubesWidget w,int direction,int control)621 MoveCubes(CubesWidget w, int direction, int control)
622 {
623 cubesCallbackStruct cb;
624
625 if (control) {
626 cb.reason = CUBES_IGNORE;
627 switch (direction) {
628 case TOP:
629 if (w->cubes.sizeY <= MINCUBES)
630 return FALSE;
631 cb.reason = CUBES_DEC_Y;
632 break;
633 case RIGHT:
634 cb.reason = CUBES_INC_X;
635 break;
636 case BOTTOM:
637 cb.reason = CUBES_INC_Y;
638 break;
639 case LEFT:
640 if (w->cubes.sizeX <= MINCUBES)
641 return FALSE;
642 cb.reason = CUBES_DEC_X;
643 break;
644 case IN:
645 if (w->cubes.sizeZ <= MINCUBES)
646 return FALSE;
647 cb.reason = CUBES_DEC_Z;
648 break;
649 case OUT:
650 cb.reason = CUBES_INC_Z;
651 break;
652 default:
653 (void) printf("MoveCubes: direction %d\n", direction);
654 }
655 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
656 return FALSE;
657 }
658 if (CheckSolved(w)) {
659 MoveNoBricks(w);
660 return FALSE;
661 }
662 if (!MoveCubesDir(w, direction)) {
663 cb.reason = CUBES_BLOCKED;
664 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
665 return FALSE;
666 }
667 if (CheckSolved(w)) {
668 cb.reason = CUBES_SOLVED;
669 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
670 }
671 return TRUE;
672 }
673
674 int
MoveCubesDir(CubesWidget w,int direction)675 MoveCubesDir(CubesWidget w, int direction)
676 {
677 cubesCallbackStruct cb;
678
679 if (MoveBricksDir(w, direction)) {
680 cb.reason = CUBES_MOVED;
681 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
682 PutMove(direction);
683 return TRUE;
684 }
685 return FALSE;
686 }
687
688 static int
PositionToBrick(CubesWidget w,int x,int y,int * i,int * j,int * k)689 PositionToBrick(CubesWidget w, int x, int y, int *i, int *j, int *k)
690 {
691 if (w->cubes.vertical) {
692 *i = (x - w->cubes.delta.x / 2 -
693 w->cubes.puzzleOffset.x) / w->cubes.offset.x;
694 *j = ((y - w->cubes.delta.y / 2 -
695 w->cubes.puzzleOffset.y) % (w->cubes.sizeY * w->cubes.offset.y +
696 w->cubes.delta.y - 1)) / w->cubes.offset.y;
697 *k = (y - w->cubes.delta.y / 2 -
698 w->cubes.puzzleOffset.y) / (w->cubes.sizeY * w->cubes.offset.y +
699 w->cubes.delta.y - 1);
700 } else {
701 *i = ((x - w->cubes.delta.x / 2 -
702 w->cubes.puzzleOffset.x) % (w->cubes.sizeX * w->cubes.offset.x +
703 w->cubes.delta.x - 1)) / w->cubes.offset.x;
704 *j = (y - w->cubes.delta.y / 2 -
705 w->cubes.puzzleOffset.y) / w->cubes.offset.y;
706 *k = (x - w->cubes.delta.x / 2 -
707 w->cubes.puzzleOffset.x) / (w->cubes.sizeX * w->cubes.offset.x +
708 w->cubes.delta.x - 1);
709 }
710 if (*i >= 0 && *j >= 0 && *k >= 0 &&
711 *i < w->cubes.sizeX && *j < w->cubes.sizeY && *k < w->cubes.sizeZ)
712 return (*i + w->cubes.sizeX * *j + w->cubes.sizeRect * *k);
713 else
714 return -1;
715 }
716
717 static int
MovableBrick(CubesWidget w)718 MovableBrick(CubesWidget w)
719 {
720 int i, j, k, l, m;
721
722 i = w->cubes.currentRow[0];
723 j = w->cubes.currentRow[1];
724 k = w->cubes.currentRow[2];
725 l = i + w->cubes.sizeX * j - w->cubes.spacePosition % w->cubes.sizeRect;
726 m = i + w->cubes.sizeX * j + w->cubes.sizeRect * k - w->cubes.spacePosition;
727
728 /* Order important if w->cubes.sizeX = 1 */
729 if (l % w->cubes.sizeX == 0 && k == Stack(w, w->cubes.spacePosition)) {
730 if (l == 0) {
731 return CUBES_SPACE;
732 }
733 } else if (!(l / w->cubes.sizeX == 0 &&
734 j == Column(w, w->cubes.spacePosition) &&
735 k == Stack(w, w->cubes.spacePosition)) &&
736 (m % w->cubes.sizeRect != 0)) {
737 return CUBES_BLOCKED;
738 }
739 return 0;
740 }
741
742 static void
SelectBricks(CubesWidget w)743 SelectBricks(CubesWidget w)
744 {
745 cubesCallbackStruct cb;
746 int i, j, k, l, m, n;
747
748 i = w->cubes.currentRow[0];
749 j = w->cubes.currentRow[1];
750 k = w->cubes.currentRow[2];
751 l = i + w->cubes.sizeX * j - w->cubes.spacePosition % w->cubes.sizeRect;
752 m = i + w->cubes.sizeX * j + w->cubes.sizeRect * k - w->cubes.spacePosition;
753
754 /* Order important if w->cubes.sizeX = 1 */
755 if (l % w->cubes.sizeX == 0 && k == Stack(w, w->cubes.spacePosition)) {
756 if (l < 0) {
757 for (n = 1; n <= -l / w->cubes.sizeX; n++) {
758 MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeX);
759 cb.reason = CUBES_MOVED;
760 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
761 PutMove(BOTTOM);
762 }
763 } else if (l > 0) {
764 for (n = 1; n <= l / w->cubes.sizeX; n++) {
765 MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeX);
766 cb.reason = CUBES_MOVED;
767 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
768 PutMove(TOP);
769 }
770 } else { /* (l == 0) */
771 (void) printf("SelectBricks: %d\n", CUBES_SPACE);
772 return;
773 }
774 } else if (l / w->cubes.sizeX == 0 &&
775 j == Column(w, w->cubes.spacePosition) &&
776 k == Stack(w, w->cubes.spacePosition)) {
777 if (l < 0) {
778 for (n = 1; n <= -l % w->cubes.sizeX; n++) {
779 MoveBricks(w, w->cubes.spacePosition - 1);
780 cb.reason = CUBES_MOVED;
781 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
782 PutMove(RIGHT);
783 }
784 } else { /* (l > 0) */
785 for (n = 1; n <= l % w->cubes.sizeX; n++) {
786 MoveBricks(w, w->cubes.spacePosition + 1);
787 cb.reason = CUBES_MOVED;
788 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
789 PutMove(LEFT);
790 }
791 }
792 } else if (m % w->cubes.sizeRect == 0) {
793 if (m < 0) {
794 for (n = 1; n <= -Stack(w, m); n++) {
795 MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeRect);
796 cb.reason = CUBES_MOVED;
797 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
798 PutMove(IN);
799 }
800 } else { /* (m > 0) */
801 for (n = 1; n <= Stack(w, m); n++) {
802 MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeRect);
803 cb.reason = CUBES_MOVED;
804 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
805 PutMove(OUT);
806 }
807 }
808 } else {
809 (void) printf("SelectBricks: %d\n", CUBES_BLOCKED);
810 return;
811 }
812 if (CheckSolved(w)) {
813 cb.reason = CUBES_SOLVED;
814 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
815 }
816 }
817
818 static void
SetAllColors(CubesWidget w,Boolean init)819 SetAllColors(CubesWidget w, Boolean init)
820 {
821 XGCValues values;
822 XtGCMask valueMask;
823
824 valueMask = GCForeground | GCBackground;
825
826 if (w->cubes.reverse) {
827 values.foreground = w->cubes.foreground;
828 values.background = w->core.background_pixel;
829 } else {
830 values.foreground = w->core.background_pixel;
831 values.background = w->cubes.foreground;
832 }
833 if (!init)
834 XtReleaseGC((Widget) w, w->cubes.inverseGC);
835 w->cubes.inverseGC = XtGetGC((Widget) w, valueMask, &values);
836 if (w->cubes.reverse) {
837 values.foreground = w->core.background_pixel;
838 values.background = w->cubes.foreground;
839 } else {
840 values.foreground = w->cubes.foreground;
841 values.background = w->core.background_pixel;
842 }
843 if (!init)
844 XtReleaseGC((Widget) w, w->cubes.puzzleGC);
845 w->cubes.puzzleGC = XtGetGC((Widget) w, valueMask, &values);
846 if (w->cubes.depth < 2 || w->cubes.mono) {
847 if (w->cubes.reverse) {
848 values.foreground = w->core.background_pixel;
849 values.background = w->cubes.foreground;
850 } else {
851 values.foreground = w->cubes.foreground;
852 values.background = w->core.background_pixel;
853 }
854 } else {
855 values.foreground = w->cubes.brickColor;
856 values.background = w->cubes.borderColor;
857 }
858 if (!init)
859 XtReleaseGC((Widget) w, w->cubes.brickGC);
860 w->cubes.brickGC = XtGetGC((Widget) w, valueMask, &values);
861 if (w->cubes.depth < 2 || w->cubes.mono) {
862 if (w->cubes.reverse) {
863 values.foreground = w->cubes.foreground;
864 values.background = w->core.background_pixel;
865 } else {
866 values.foreground = w->core.background_pixel;
867 values.background = w->cubes.foreground;
868 }
869 } else {
870 values.foreground = w->cubes.borderColor;
871 values.background = w->cubes.brickColor;
872 }
873 if (!init)
874 XtReleaseGC((Widget) w, w->cubes.borderGC);
875 w->cubes.borderGC = XtGetGC((Widget) w, valueMask, &values);
876 }
877
878 static void
CheckBricks(CubesWidget w)879 CheckBricks(CubesWidget w)
880 {
881 char buf[121];
882
883 if (w->cubes.sizeX < MINCUBES) {
884 (void) sprintf(buf,
885 "Number of Cubes in X direction out of bounds, use %d..MAXINT",
886 MINCUBES);
887 XtWarning(buf);
888 w->cubes.sizeX = DEFAULTCUBES;
889 }
890 if (w->cubes.sizeY < MINCUBES) {
891 (void) sprintf(buf,
892 "Number of Cubes in Y direction out of bounds, use %d..MAXINT",
893 MINCUBES);
894 XtWarning(buf);
895 w->cubes.sizeY = DEFAULTCUBES;
896 }
897 if (w->cubes.sizeZ < MINCUBES) {
898 (void) sprintf(buf,
899 "Number of Cubes in Z direction out of bounds, use %d..MAXINT",
900 MINCUBES);
901 XtWarning(buf);
902 w->cubes.sizeZ = DEFAULTCUBES;
903 }
904 if (w->cubes.base > 36) {
905 /* 10 numbers + 26 letters (ASCII or EBCDIC) */
906 XtWarning("Base must be less than or equal to 36");
907 w->cubes.base = 10;
908 } else if (w->cubes.base <= 1) { /* Base 1 is rediculous :) */
909 XtWarning("Base must be greater than 1");
910 w->cubes.base = 10;
911 }
912 }
913
914 static void
ResetBricks(CubesWidget w)915 ResetBricks(CubesWidget w)
916 {
917 int i;
918
919 w->cubes.sizeRect = w->cubes.sizeX * w->cubes.sizeY;
920 w->cubes.sizeBlock = w->cubes.sizeRect * w->cubes.sizeZ;
921 if (w->cubes.brickOfPosition)
922 (void) free((void *) w->cubes.brickOfPosition);
923 if (!(w->cubes.brickOfPosition = (int *)
924 malloc(sizeof (int) * w->cubes.sizeBlock)))
925 XtError("Not enough memory, exiting.");
926
927 if (startPosition)
928 (void) free((void *) startPosition);
929 if (!(startPosition = (int *)
930 malloc(sizeof (int) * w->cubes.sizeBlock)))
931 XtError("Not enough memory, exiting.");
932
933 w->cubes.spacePosition = w->cubes.sizeBlock - 1;
934 w->cubes.brickOfPosition[w->cubes.sizeBlock - 1] = 0;
935 for (i = 1; i < w->cubes.sizeBlock; i++)
936 w->cubes.brickOfPosition[i - 1] = i;
937 FlushMoves(w);
938 w->cubes.currentPosition = -1;
939 w->cubes.started = FALSE;
940 }
941
942 static void
ResizeBricks(CubesWidget w)943 ResizeBricks(CubesWidget w)
944 {
945 w->cubes.digitOffset.x = 3;
946 w->cubes.digitOffset.y = 4;
947 }
948
949 static void
MoveNoBricks(CubesWidget w)950 MoveNoBricks(CubesWidget w)
951 {
952 cubesCallbackStruct cb;
953
954 cb.reason = CUBES_IGNORE;
955 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
956 }
957
958 static int
MoveBricksDir(CubesWidget w,int direction)959 MoveBricksDir(CubesWidget w, int direction)
960 {
961 switch (direction) {
962 case TOP:
963 if (Column(w, w->cubes.spacePosition) < w->cubes.sizeY - 1) {
964 MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeX);
965 return TRUE;
966 }
967 break;
968 case RIGHT:
969 if (Row(w, w->cubes.spacePosition) > 0) {
970 MoveBricks(w, w->cubes.spacePosition - 1);
971 return TRUE;
972 }
973 break;
974 case BOTTOM:
975 if (Column(w, w->cubes.spacePosition) > 0) {
976 MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeX);
977 return TRUE;
978 }
979 break;
980 case LEFT:
981 if (Row(w, w->cubes.spacePosition) < w->cubes.sizeX - 1) {
982 MoveBricks(w, w->cubes.spacePosition + 1);
983 return TRUE;
984 }
985 break;
986 case IN:
987 if (Stack(w, w->cubes.spacePosition) > 0) {
988 MoveBricks(w, w->cubes.spacePosition - w->cubes.sizeRect);
989 return TRUE;
990 }
991 break;
992 case OUT:
993 if (Stack(w, w->cubes.spacePosition) < w->cubes.sizeZ - 1) {
994 MoveBricks(w, w->cubes.spacePosition + w->cubes.sizeRect);
995 return TRUE;
996 }
997 break;
998 default:
999 (void) printf("MoveBricksDir: direction %d\n", direction);
1000 }
1001 return FALSE;
1002 }
1003
1004 static void
RandomizeBricks(CubesWidget w)1005 RandomizeBricks(CubesWidget w)
1006 {
1007 cubesCallbackStruct cb;
1008
1009 /* First interchange bricks an even number of times */
1010 if (w->cubes.sizeX > 1 && w->cubes.sizeY > 1 && w->cubes.sizeZ > 1 &&
1011 w->cubes.sizeBlock > 4) {
1012 int pos, count = 0;
1013
1014 for (pos = 0; pos < w->cubes.sizeBlock; pos++) {
1015 int randomPos = pos;
1016
1017 while (randomPos == pos)
1018 randomPos = NRAND(w->cubes.sizeBlock);
1019 count += ExchangeBricks(w, pos, randomPos);
1020 }
1021 if (count % 2)
1022 if (!ExchangeBricks(w, 0, 1))
1023 if (!ExchangeBricks(w, w->cubes.sizeBlock - 2, w->cubes.sizeBlock - 1))
1024 (void) printf("RandomizeBricks: should not get here\n");
1025 DrawAllBricks(w);
1026 }
1027 /* Now move the space around randomly */
1028 if (w->cubes.sizeX > 1 || w->cubes.sizeY > 1 || w->cubes.sizeZ > 1) {
1029 int big = w->cubes.sizeBlock + NRAND(2);
1030 int lastDirection = 0;
1031 int randomDirection;
1032
1033 cb.reason = CUBES_RESET;
1034 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1035
1036 #ifdef DEBUG
1037 big = 3;
1038 #endif
1039
1040 if (big > 1000)
1041 big = 1000;
1042 while (big--) {
1043 randomDirection = NRAND(COORD);
1044
1045 #ifdef DEBUG
1046 sleep(1);
1047 #endif
1048
1049 if ((randomDirection + COORD / 2) % COORD != lastDirection ||
1050 (w->cubes.sizeX == 1 && w->cubes.sizeY == 1) ||
1051 (w->cubes.sizeY == 1 && w->cubes.sizeZ == 1) ||
1052 (w->cubes.sizeZ == 1 && w->cubes.sizeX == 1)) {
1053 if (MoveCubesDir(w, randomDirection))
1054 lastDirection = randomDirection;
1055 else
1056 big++;
1057 }
1058 }
1059 FlushMoves(w);
1060 cb.reason = CUBES_RANDOMIZE;
1061 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1062 }
1063 if (CheckSolved(w)) {
1064 cb.reason = CUBES_SOLVED;
1065 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1066 }
1067 }
1068
1069 static void
MoveBricks(CubesWidget w,int from)1070 MoveBricks(CubesWidget w, int from)
1071 {
1072 int tempBrick;
1073
1074 tempBrick = w->cubes.brickOfPosition[from];
1075 w->cubes.brickOfPosition[from] =
1076 w->cubes.brickOfPosition[w->cubes.spacePosition];
1077 w->cubes.brickOfPosition[w->cubes.spacePosition] = tempBrick;
1078 DrawBrick(w, w->cubes.spacePosition, False, False, FALSE);
1079 w->cubes.spacePosition = from;
1080 DrawBrick(w, w->cubes.spacePosition, True, True, FALSE);
1081 }
1082
1083 static int
ExchangeBricks(CubesWidget w,int pos1,int pos2)1084 ExchangeBricks(CubesWidget w, int pos1, int pos2)
1085 {
1086 int tempBrick;
1087
1088 if (w->cubes.brickOfPosition[pos1] <= 0)
1089 return FALSE;
1090 else if (w->cubes.brickOfPosition[pos2] <= 0)
1091 return FALSE;
1092 tempBrick = w->cubes.brickOfPosition[pos1];
1093 w->cubes.brickOfPosition[pos1] = w->cubes.brickOfPosition[pos2];
1094 w->cubes.brickOfPosition[pos2] = tempBrick;
1095 return TRUE;
1096 }
1097
1098 static void
DrawFrame(CubesWidget w,GC gc)1099 DrawFrame(CubesWidget w, GC gc)
1100 {
1101 int sumX, sumY, sumZ, offsetX, offsetY, dz, k;
1102
1103 sumX = w->cubes.sizeX * w->cubes.offset.x + w->cubes.delta.x / 2 + 1;
1104 sumY = w->cubes.sizeY * w->cubes.offset.y + w->cubes.delta.y / 2 + 1;
1105 offsetX = w->cubes.puzzleOffset.x;
1106 offsetY = w->cubes.puzzleOffset.y;
1107 if (w->cubes.vertical) {
1108 sumZ = offsetY;
1109 dz = sumY;
1110 } else {
1111 sumZ = offsetX;
1112 dz = sumX;
1113 }
1114 for (k = 0; k < w->cubes.sizeZ; k++) {
1115 if (w->cubes.vertical) {
1116 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1117 offsetX, sumZ, 1, sumY);
1118 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1119 offsetX, sumZ, sumX, 1);
1120 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1121 sumX + offsetX, sumZ, 1, sumY + 1);
1122 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1123 offsetX, sumY + sumZ, sumX + 1, 1);
1124 } else {
1125 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1126 sumZ, offsetY, 1, sumY);
1127 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1128 sumZ, offsetY, sumX, 1);
1129 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1130 sumX + sumZ, offsetY, 1, sumY + 1);
1131 XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1132 sumZ, sumY + offsetY, sumX + 1, 1);
1133 }
1134 sumZ += dz;
1135 }
1136 }
1137
1138 void
DrawAllBricks(CubesWidget w)1139 DrawAllBricks(CubesWidget w)
1140 {
1141 int k;
1142
1143 for (k = 0; k < w->cubes.sizeBlock; k++)
1144 DrawBrick(w, k, (w->cubes.brickOfPosition[k] <= 0), (w->cubes.brickOfPosition[k] <= 0), FALSE);
1145 }
1146
1147 static void
DrawBrick(CubesWidget w,int pos,Boolean blank,Boolean erase,int offset)1148 DrawBrick(CubesWidget w, int pos, Boolean blank, Boolean erase, int offset)
1149 {
1150 int dx, dy, dz;
1151 GC brickGC, borderGC;
1152
1153 if (erase) {
1154 brickGC = w->cubes.inverseGC;
1155 borderGC = w->cubes.inverseGC;
1156 } else if (offset) {
1157 brickGC = w->cubes.borderGC;
1158 borderGC = w->cubes.brickGC;
1159 } else {
1160 brickGC = w->cubes.brickGC;
1161 borderGC = w->cubes.borderGC;
1162 }
1163 if (w->cubes.vertical) {
1164 dx = Row(w, pos) * w->cubes.offset.x + w->cubes.delta.x +
1165 w->cubes.puzzleOffset.x + offset;
1166 dy = Column(w, pos) * w->cubes.offset.y + w->cubes.delta.y +
1167 w->cubes.puzzleOffset.y + offset;
1168 dz = Stack(w, pos) * (w->cubes.sizeY * w->cubes.offset.y +
1169 w->cubes.delta.y - 1);
1170 dy += dz;
1171 } else {
1172 dx = Row(w, pos) * w->cubes.offset.x + w->cubes.delta.x +
1173 w->cubes.puzzleOffset.x + offset;
1174 dy = Column(w, pos) * w->cubes.offset.y + w->cubes.delta.y +
1175 w->cubes.puzzleOffset.y + offset;
1176 dz = Stack(w, pos) * (w->cubes.sizeX * w->cubes.offset.x +
1177 w->cubes.delta.x - 1);
1178 dx += dz;
1179 }
1180 XFillRectangle(XtDisplay(w), XtWindow(w), brickGC, dx, dy,
1181 w->cubes.brickSize.x, w->cubes.brickSize.y);
1182 XDrawRectangle(XtDisplay(w), XtWindow(w), borderGC, dx, dy,
1183 w->cubes.brickSize.x, w->cubes.brickSize.y);
1184 if (!blank) {
1185 int i = 0, offsetX = 0, brick = w->cubes.brickOfPosition[pos];
1186 char buf[5];
1187
1188 (void) int2String(buf, brick, w->cubes.base);
1189 while (brick >= 1) {
1190 brick /= w->cubes.base;
1191 offsetX += w->cubes.digitOffset.x;
1192 i++;
1193 }
1194 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
1195 dx + w->cubes.brickSize.x / 2 - offsetX,
1196 dy + w->cubes.brickSize.y / 2 + w->cubes.digitOffset.y, buf, i);
1197 }
1198 }
1199
1200 static int
Row(CubesWidget w,int pos)1201 Row(CubesWidget w, int pos)
1202 {
1203 return ((pos % w->cubes.sizeRect) % w->cubes.sizeX);
1204 }
1205
1206 static int
Column(CubesWidget w,int pos)1207 Column(CubesWidget w, int pos)
1208 {
1209 return ((pos % w->cubes.sizeRect) / w->cubes.sizeX);
1210 }
1211
1212 static int
Stack(CubesWidget w,int pos)1213 Stack(CubesWidget w, int pos)
1214 {
1215 return (pos / w->cubes.sizeRect);
1216 }
1217
1218 static int
int2String(char * buf,int number,int base)1219 int2String(char *buf, int number, int base)
1220 {
1221 int digit, mult = base, last, position;
1222
1223 if (number < 0) {
1224 (void) printf("number %d < 0\n", number);
1225 return 0;
1226 }
1227 last = 1;
1228 while (number >= mult) {
1229 last++;
1230 mult *= base;
1231 }
1232 for (position = 0; position < last; position++) {
1233 mult /= base;
1234 digit = number / mult;
1235 number -= digit * mult;
1236 buf[position] = digit + '0';
1237 if (buf[position] > '9') { /* ASCII */
1238 buf[position] += ('A' - '9' - 1);
1239 } else if (buf[position] < '0') { /* EBCDIC */
1240 buf[position] += ('A' - '9' - 1);
1241 if (buf[position] > 'I')
1242 buf[position] += ('J' - 'I' - 1);
1243 if (buf[position] > 'R')
1244 buf[position] += ('S' - 'R' - 1);
1245 }
1246 }
1247 buf[last] = '\0';
1248 return last;
1249 }
1250
1251 Boolean
CheckSolved(CubesWidget w)1252 CheckSolved(CubesWidget w)
1253 {
1254 int i;
1255
1256 for (i = 1; i < w->cubes.sizeBlock; i++)
1257 if (w->cubes.brickOfPosition[i - 1] != i)
1258 return FALSE;
1259 return TRUE;
1260 }
1261