1
2 /*-
3 # MOTIF-BASED RUBIK'S CUBE(tm)
4 #
5 # xmrubik.c
6 #
7 ###
8 #
9 # Copyright (c) 1993 - 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 "useful",
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 #
25 */
26
27 /*-
28 Version 5: 95/10/06 Xt/Motif
29 Version 4: 94/04/07 Xt
30 Version 3: 93/05/20 Motif
31 Version 2: 92/01/16 XView
32 Version 1: 91/01/16 SunView
33 */
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <errno.h>
38 #ifdef VMS
39 #include <unixlib.h>
40 #define getlogin() cuserid(NULL)
41 #else
42 #if HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 #endif
46 #if HAVE_FCNTL_H
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #endif
51 #include <X11/Intrinsic.h>
52 #include <X11/StringDefs.h>
53 #include <X11/Shell.h>
54 #include <X11/cursorfont.h>
55 #include <Xm/PanedW.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/Label.h>
58 #include <Xm/LabelG.h>
59 #include <Xm/Scale.h>
60 #include <Xm/ToggleB.h>
61 #include "Rubik.h"
62 #include "Rubik2d.h"
63 #include "Rubik3d.h"
64 #include "rubik.xbm"
65 #include "mouse-l.xbm"
66 #include "mouse-r.xbm"
67
68 #ifndef SCOREFILE
69 #define SCOREFILE "/usr/games/lib/mball.scores"
70 #endif
71
72 /* The following are in RubikP.h also */
73 #define MINCUBES 1
74 #define MAXFACES 6
75
76 #define MAXCUBES 6
77 #define MAXRECORD 32767
78 #define FILENAMELEN 1024
79 #define USERNAMELEN 128
80 #define NOACCESS "noaccess"
81 #define NOBODY "nobody"
82
83 typedef struct {
84 int score;
85 char name[USERNAMELEN];
86 } GameRecord;
87
88 static void Initialize(void);
89 static void CallbackRubik(Widget w, caddr_t clientData,
90 rubikCallbackStruct * callData);
91
92 static void PrintRecord(int sizex, int sizey, int sizez,
93 Boolean orient, Boolean practice);
94 static int HandleSolved(int counter, int sizex, int sizey, int sizez,
95 Boolean orient);
96 static void InitRecords(void);
97 static void ReadRecords(void);
98 static void WriteRecords(void);
99
100 static void CubesXSlider(Widget w, XtPointer clientData,
101 XmScaleCallbackStruct * cbs);
102 static void CubesYSlider(Widget w, XtPointer clientData,
103 XmScaleCallbackStruct * cbs);
104 static void CubesZSlider(Widget w, XtPointer clientData,
105 XmScaleCallbackStruct * cbs);
106 static void OrientToggle(Widget w, XtPointer clientData,
107 XmToggleButtonCallbackStruct * cbs);
108 static void PracticeToggle(Widget w, XtPointer clientData,
109 XmToggleButtonCallbackStruct * cbs);
110 static void motif_print(Widget w, char *text);
111 static Arg arg[4];
112 static Widget moves, record, message, rubik2d, rubik3d, cubesx, cubesy,
113 cubesz, orientSwitch, practiceSwitch;
114 static GameRecord rubikRecord[2][MAXCUBES - MINCUBES + 1][MAXCUBES - MINCUBES + 1][MAXCUBES - MINCUBES + 1];
115 static int movesDsp = 0;
116 static char messageDsp[128] = "Welcome";
117 static char usernameDsp[USERNAMELEN] = "";
118 static char buff[256];
119
120 static void
usage(void)121 usage(void)
122 {
123 (void) fprintf(stderr, "usage: xmrubik\n");
124 (void) fprintf(stderr,
125 "\t[-geometry [{width}][x{height}][{+-}{xoff}[{+-}{yoff}]]]\n");
126 (void) fprintf(stderr,
127 "\t[-display [{host}]:[{vs}]] [-[no]mono] [-[no]{reverse|rv}]\n");
128 (void) fprintf(stderr,
129 "\t[-{foreground|fg} {color}] [-{background|bg} {color}]\n");
130 (void) fprintf(stderr,
131 "\t[-{border|bd} {color}] [-face{0|1|2|3|4|5} {color}]\n");
132 (void) fprintf(stderr,
133 "\t[-sizex {int}] [-sizey {int}] [-sizez {int}]\n");
134 (void) fprintf(stderr,
135 "\t[-[no]orient] [-[no]practice] [-username {string}]\n");
136 exit(1);
137 }
138
139 static XrmOptionDescRec options[] =
140 {
141 {"-mono", "*rubik.mono", XrmoptionNoArg, "TRUE"},
142 {"-nomono", "*rubik.mono", XrmoptionNoArg, "FALSE"},
143 {"-rv", "*rubik.reverse", XrmoptionNoArg, "TRUE"},
144 {"-reverse", "*rubik.reverse", XrmoptionNoArg, "TRUE"},
145 {"-norv", "*rubik.reverse", XrmoptionNoArg, "FALSE"},
146 {"-noreverse", "*rubik.reverse", XrmoptionNoArg, "FALSE"},
147 {"-fg", "rubik.Foreground", XrmoptionSepArg, NULL},
148 {"-foreground", "rubik.Foreground", XrmoptionSepArg, NULL},
149 {"-bg", "*Background", XrmoptionSepArg, NULL},
150 {"-background", "*Background", XrmoptionSepArg, NULL},
151 {"-bd", "*rubik.pieceBorder", XrmoptionSepArg, NULL},
152 {"-border", "*rubik.pieceBorder", XrmoptionSepArg, NULL},
153 {"-face0", "*rubik.faceColor0", XrmoptionSepArg, NULL},
154 {"-face1", "*rubik.faceColor1", XrmoptionSepArg, NULL},
155 {"-face2", "*rubik.faceColor2", XrmoptionSepArg, NULL},
156 {"-face3", "*rubik.faceColor3", XrmoptionSepArg, NULL},
157 {"-face4", "*rubik.faceColor4", XrmoptionSepArg, NULL},
158 {"-face5", "*rubik.faceColor5", XrmoptionSepArg, NULL},
159 {"-sizex", "*rubik.sizex", XrmoptionSepArg, NULL},
160 {"-sizey", "*rubik.sizey", XrmoptionSepArg, NULL},
161 {"-sizez", "*rubik.sizez", XrmoptionSepArg, NULL},
162 {"-orient", "*rubik.orient", XrmoptionNoArg, "TRUE"},
163 {"-noorient", "*rubik.orient", XrmoptionNoArg, "FALSE"},
164 {"-practice", "*rubik.practice", XrmoptionNoArg, "TRUE"},
165 {"-nopractice", "*rubik.practice", XrmoptionNoArg, "FALSE"},
166 {"-username", "*rubik.userName", XrmoptionSepArg, NULL}
167 };
168
169 int
main(int argc,char ** argv)170 main(int argc, char **argv)
171 {
172 Widget toplevel;
173 Widget panel, panel2, rowcol, rowcol2, rowcol3, rowcol4;
174 Pixmap mouseLeftCursor, mouseRightCursor;
175 Pixel fg, bg;
176
177 toplevel = XtInitialize(argv[0], "Rubik",
178 options, XtNumber(options), &argc, argv);
179 if (argc != 1)
180 usage();
181
182 XtSetArg(arg[0],
183 XtNiconPixmap, XCreateBitmapFromData(XtDisplay(toplevel),
184 RootWindowOfScreen(XtScreen(toplevel)),
185 (char *) rubik_bits, rubik_width, rubik_height));
186 XtSetArg(arg[1], XmNkeyboardFocusPolicy, XmPOINTER); /* not XmEXPLICIT */
187 XtSetValues(toplevel, arg, 2);
188 panel = XtCreateManagedWidget("panel",
189 xmPanedWindowWidgetClass, toplevel, NULL, 0);
190 panel2 = XtVaCreateManagedWidget("panel2",
191 xmPanedWindowWidgetClass, panel,
192 XmNseparatorOn, False,
193 XmNsashWidth, 1,
194 XmNsashHeight, 1, NULL);
195
196 rowcol = XtVaCreateManagedWidget("Rowcol",
197 xmRowColumnWidgetClass, panel2,
198 XmNnumColumns, 2,
199 XmNorientation, XmHORIZONTAL,
200 XmNpacking, XmPACK_COLUMN, NULL);
201 XtVaGetValues(rowcol,
202 XmNforeground, &fg,
203 XmNbackground, &bg, NULL);
204 mouseLeftCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
205 RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_left_bits,
206 mouse_left_width, mouse_left_height, fg, bg,
207 DefaultDepthOfScreen(XtScreen(rowcol)));
208 mouseRightCursor = XCreatePixmapFromBitmapData(XtDisplay(rowcol),
209 RootWindowOfScreen(XtScreen(rowcol)), (char *) mouse_right_bits,
210 mouse_right_width, mouse_right_height, fg, bg,
211 DefaultDepthOfScreen(XtScreen(rowcol)));
212 XtVaCreateManagedWidget("mouseLeftText",
213 xmLabelGadgetClass, rowcol,
214 XtVaTypedArg, XmNlabelString, XmRString, "Move", 5, NULL);
215 XtVaCreateManagedWidget("mouseLeft",
216 xmLabelGadgetClass, rowcol,
217 XmNlabelType, XmPIXMAP, XmNlabelPixmap, mouseLeftCursor, NULL);
218 XtVaCreateManagedWidget("mouseRightText", xmLabelGadgetClass, rowcol,
219 XtVaTypedArg, XmNlabelString, XmRString, "Randomize", 10, NULL);
220 XtVaCreateManagedWidget("mouseRight",
221 xmLabelGadgetClass, rowcol,
222 XmNlabelType, XmPIXMAP,
223 XmNlabelPixmap, mouseRightCursor, NULL);
224 XtVaCreateManagedWidget("movesText", xmLabelGadgetClass, rowcol,
225 XtVaTypedArg, XmNlabelString, XmRString, "Moves", 6, NULL);
226 moves = XtVaCreateManagedWidget("0",
227 xmLabelWidgetClass, rowcol, NULL);
228 XtVaCreateManagedWidget("recordText",
229 xmLabelGadgetClass, rowcol,
230 XtVaTypedArg, XmNlabelString, XmRString, "Record", 7, NULL);
231 record = XtVaCreateManagedWidget("0",
232 xmLabelWidgetClass, rowcol, NULL);
233
234 rowcol2 = XtVaCreateManagedWidget("Rowcol2",
235 xmRowColumnWidgetClass, panel2, NULL);
236 cubesx = XtVaCreateManagedWidget("cubesx",
237 xmScaleWidgetClass, rowcol2,
238 XtVaTypedArg, XmNtitleString, XmRString, "CubesX", 7,
239 XmNminimum, MINCUBES,
240 XmNmaximum, MAXCUBES,
241 XmNvalue, MINCUBES,
242 XmNshowValue, True,
243 XmNorientation, XmHORIZONTAL, NULL);
244 XtAddCallback(cubesx,
245 XmNvalueChangedCallback, (XtCallbackProc) CubesXSlider, (XtPointer) NULL);
246 cubesy = XtVaCreateManagedWidget("cubesy",
247 xmScaleWidgetClass, rowcol2,
248 XtVaTypedArg, XmNtitleString, XmRString, "CubesY", 7,
249 XmNminimum, MINCUBES,
250 XmNmaximum, MAXCUBES,
251 XmNvalue, MINCUBES,
252 XmNshowValue, True,
253 XmNorientation, XmHORIZONTAL, NULL);
254 XtAddCallback(cubesy,
255 XmNvalueChangedCallback, (XtCallbackProc) CubesYSlider, (XtPointer) NULL);
256 cubesz = XtVaCreateManagedWidget("cubesz",
257 xmScaleWidgetClass, rowcol2,
258 XtVaTypedArg, XmNtitleString, XmRString, "CubesZ", 7,
259 XmNminimum, MINCUBES,
260 XmNmaximum, MAXCUBES,
261 XmNvalue, MINCUBES,
262 XmNshowValue, True,
263 XmNorientation, XmHORIZONTAL, NULL);
264 XtAddCallback(cubesz,
265 XmNvalueChangedCallback, (XtCallbackProc) CubesZSlider, (XtPointer) NULL);
266 rowcol3 = XtVaCreateManagedWidget("Rowcol3",
267 xmRowColumnWidgetClass, panel2,
268 XmNnumColumns, 1,
269 XmNorientation, XmHORIZONTAL,
270 XmNpacking, XmPACK_COLUMN, NULL);
271 orientSwitch = XtVaCreateManagedWidget("Orient",
272 xmToggleButtonWidgetClass, rowcol3, NULL);
273 XtAddCallback(orientSwitch,
274 XmNvalueChangedCallback, (XtCallbackProc) OrientToggle, (XtPointer) NULL);
275 practiceSwitch = XtVaCreateManagedWidget("Practice",
276 xmToggleButtonWidgetClass, rowcol3, NULL);
277 XtAddCallback(practiceSwitch,
278 XmNvalueChangedCallback, (XtCallbackProc) PracticeToggle, (XtPointer) NULL);
279 rowcol4 = XtVaCreateManagedWidget("Rowcol4",
280 xmRowColumnWidgetClass, panel2, NULL);
281 message = XtVaCreateManagedWidget("Play Rubik's Cube! (use mouse and keypad)",
282 xmLabelWidgetClass, rowcol4, NULL);
283
284 rubik2d = XtCreateManagedWidget("rubik",
285 rubik2dWidgetClass, panel, NULL, 0);
286 XtVaSetValues(rubik2d,
287 XtNheight, 200, NULL);
288 XtAddCallback(rubik2d,
289 XtNselectCallback, (XtCallbackProc) CallbackRubik, (XtPointer) NULL);
290 rubik3d = XtCreateManagedWidget("rubik",
291 rubik3dWidgetClass, panel, NULL, 0);
292 XtVaSetValues(rubik3d,
293 XtNheight, 200, NULL);
294 XtAddCallback(rubik3d,
295 XtNselectCallback, (XtCallbackProc) CallbackRubik, (XtPointer) NULL);
296 Initialize();
297 XtRealizeWidget(toplevel);
298 XGrabButton(XtDisplay(rubik2d), (unsigned int) AnyButton, AnyModifier,
299 XtWindow(rubik2d), TRUE,
300 (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
301 GrabModeAsync, GrabModeAsync, XtWindow(rubik2d),
302 XCreateFontCursor(XtDisplay(rubik2d), XC_crosshair));
303 XGrabButton(XtDisplay(rubik3d), (unsigned int) AnyButton, AnyModifier,
304 XtWindow(rubik3d), TRUE,
305 (unsigned int) (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask),
306 GrabModeAsync, GrabModeAsync, XtWindow(rubik3d),
307 XCreateFontCursor(XtDisplay(rubik3d), XC_crosshair));
308 XtMainLoop();
309
310 #ifdef VMS
311 return 1;
312 #else
313 return 0;
314 #endif
315 }
316
317 /* There's probably a better way to assure that they are the same but I don't
318 know it off hand. */
319 static void
MakeEquivalent(String * username,int * sizex,int * sizey,int * sizez,Boolean * orient,Boolean * practice)320 MakeEquivalent(String * username, int *sizex, int *sizey, int *sizez, Boolean * orient, Boolean * practice)
321 {
322 Boolean mono, reverse;
323 Pixel foreground, background, pieceBorder;
324 String faceColor[MAXFACES];
325
326 XtVaGetValues(rubik2d,
327 XtNuserName, username,
328 XtNsizex, sizex,
329 XtNsizey, sizey,
330 XtNsizez, sizez,
331 XtNorient, orient,
332 XtNpractice, practice,
333 XtNmono, &mono,
334 XtNreverse, &reverse,
335 XtNforeground, &foreground,
336 XtNbackground, &background,
337 XtNpieceBorder, &pieceBorder,
338 XtNfaceColor0, &(faceColor[0]),
339 XtNfaceColor1, &(faceColor[1]),
340 XtNfaceColor2, &(faceColor[2]),
341 XtNfaceColor3, &(faceColor[3]),
342 XtNfaceColor4, &(faceColor[4]),
343 XtNfaceColor5, &(faceColor[5]), NULL);
344 XtVaSetValues(rubik2d,
345 XtNdirection, RUBIK_IGNORE,
346 XtNstart, False, NULL);
347 XtVaSetValues(rubik3d,
348 XtNuserName, *username,
349 XtNsizex, *sizex,
350 XtNsizey, *sizey,
351 XtNsizez, *sizez,
352 XtNorient, *orient,
353 XtNmono, mono,
354 XtNreverse, reverse,
355 XtNdirection, RUBIK_IGNORE,
356 XtNpractice, *practice,
357 XtNstart, False,
358 XtNforeground, foreground,
359 XtNbackground, background,
360 XtNpieceBorder, pieceBorder,
361 XtNfaceColor0, faceColor[0],
362 XtNfaceColor1, faceColor[1],
363 XtNfaceColor2, faceColor[2],
364 XtNfaceColor3, faceColor[3],
365 XtNfaceColor4, faceColor[4],
366 XtNfaceColor5, faceColor[5], NULL);
367 }
368
369 static void
Initialize(void)370 Initialize(void)
371 {
372 int sizex, sizey, sizez;
373 Boolean orient, practice;
374 String username;
375
376 MakeEquivalent(&username, &sizex, &sizey, &sizez, &orient, &practice);
377 if (sizex <= MAXCUBES)
378 XmScaleSetValue(cubesx, sizex);
379 if (sizey <= MAXCUBES)
380 XmScaleSetValue(cubesy, sizey);
381 if (sizez <= MAXCUBES)
382 XmScaleSetValue(cubesz, sizez);
383 XmToggleButtonSetState(orientSwitch, orient, True);
384 XmToggleButtonSetState(practiceSwitch, practice, True);
385 InitRecords();
386 ReadRecords();
387 (void) strcpy(usernameDsp, username);
388 if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS) ||
389 !strcmp(usernameDsp, NOBODY)) {
390 /* The NOACCESS is not necasary, but it stops people from being cute. */
391 (void) sprintf(usernameDsp, "%s", getlogin());
392 if (!strcmp(usernameDsp, "") || !strcmp(usernameDsp, NOACCESS))
393 (void) sprintf(usernameDsp, "%s", NOBODY); /* It really IS nobody */
394 }
395 PrintRecord(sizex, sizey, sizez, orient, practice);
396 }
397
398 static void
CallbackRubik(Widget w,caddr_t clientData,rubikCallbackStruct * callData)399 CallbackRubik(Widget w, caddr_t clientData, rubikCallbackStruct * callData)
400 {
401 int sizex, sizey, sizez;
402 Boolean orient, practice, start;
403 Widget otherw;
404
405 if (w == rubik2d)
406 otherw = rubik3d;
407 else /* (w == rubik3d) */
408 otherw = rubik2d;
409 XtVaGetValues(w,
410 XtNsizex, &sizex,
411 XtNsizey, &sizey,
412 XtNsizez, &sizez,
413 XtNorient, &orient,
414 XtNpractice, &practice,
415 XtNstart, &start, NULL);
416 (void) strcpy(messageDsp, "");
417 switch (callData->reason) {
418 case RUBIK_RESTORE:
419 XtSetArg(arg[0], XtNdirection, RUBIK_RESTORE);
420 XtSetValues(otherw, arg, 1);
421 XtSetValues(w, arg, 1);
422 movesDsp = 0;
423 break;
424 case RUBIK_RESET:
425 movesDsp = 0;
426 break;
427 case RUBIK_ILLEGAL:
428 if (practice || start)
429 (void) strcpy(messageDsp, "Illegal move");
430 else
431 (void) strcpy(messageDsp, "Randomize to start");
432 break;
433 case RUBIK_MOVED:
434 movesDsp++;
435 XtSetArg(arg[0], XtNstart, True);
436 XtSetArg(arg[1], XtNface, callData->face);
437 XtSetArg(arg[2], XtNpos, callData->position);
438 XtSetArg(arg[3], XtNdirection, callData->direction);
439 XtSetValues(otherw, arg, 4);
440 XtSetValues(w, arg, 1);
441 break;
442 case RUBIK_CONTROL:
443 XtSetArg(arg[0], XtNface, callData->face);
444 XtSetArg(arg[1], XtNpos, callData->position);
445 XtSetArg(arg[2], XtNdirection, callData->direction);
446 XtSetValues(otherw, arg, 3);
447 return;
448 case RUBIK_SOLVED:
449 if (practice)
450 movesDsp = 0;
451 else {
452 if (HandleSolved(movesDsp, sizex, sizey, sizez, orient))
453 (void) sprintf(messageDsp, "Congratulations %s!!", usernameDsp);
454 else
455 (void) strcpy(messageDsp, "Solved!");
456 }
457 XtSetArg(arg[0], XtNstart, False);
458 XtSetValues(w, arg, 1);
459 XtSetValues(otherw, arg, 1);
460 break;
461 case RUBIK_PRACTICE:
462 movesDsp = 0;
463 practice = !practice;
464 if (!practice)
465 (void) strcpy(messageDsp, "Randomize to start");
466 PrintRecord(sizex, sizey, sizez, orient, practice);
467 XtSetArg(arg[0], XtNpractice, practice);
468 XtSetArg(arg[1], XtNstart, False);
469 XtSetValues(w, arg, 2);
470 XtSetValues(otherw, arg, 2);
471 XmToggleButtonSetState(practiceSwitch, practice, True);
472 break;
473 case RUBIK_RANDOMIZE:
474 movesDsp = 0;
475 XtSetArg(arg[0], XtNpractice, False);
476 XtSetArg(arg[1], XtNstart, False);
477 XtSetValues(w, arg, 2);
478 XtSetValues(otherw, arg, 2);
479 break;
480 case RUBIK_ORIENT:
481 movesDsp = 0;
482 orient = !orient;
483 PrintRecord(sizex, sizey, sizez, orient, practice);
484 XtSetArg(arg[0], XtNorient, orient);
485 XtSetValues(w, arg, 1);
486 XtSetValues(otherw, arg, 1);
487 XmToggleButtonSetState(orientSwitch, orient, True);
488 break;
489 case RUBIK_DECX:
490 movesDsp = 0;
491 sizex--;
492 PrintRecord(sizex, sizey, sizez, orient, practice);
493 XtSetArg(arg[0], XtNsizex, sizex);
494 XtSetValues(w, arg, 1);
495 XtSetValues(otherw, arg, 1);
496 if (sizex <= MAXCUBES)
497 XmScaleSetValue(cubesx, sizex);
498 break;
499 case RUBIK_INCX:
500 movesDsp = 0;
501 sizex++;
502 PrintRecord(sizex, sizey, sizez, orient, practice);
503 XtSetArg(arg[0], XtNsizex, sizex);
504 XtSetValues(w, arg, 1);
505 XtSetValues(otherw, arg, 1);
506 if (sizex <= MAXCUBES)
507 XmScaleSetValue(cubesx, sizex);
508 break;
509 case RUBIK_DECY:
510 movesDsp = 0;
511 sizey--;
512 PrintRecord(sizex, sizey, sizez, orient, practice);
513 XtSetArg(arg[0], XtNsizey, sizey);
514 XtSetValues(w, arg, 1);
515 XtSetValues(otherw, arg, 1);
516 if (sizey <= MAXCUBES)
517 XmScaleSetValue(cubesy, sizey);
518 break;
519 case RUBIK_INCY:
520 movesDsp = 0;
521 sizey++;
522 PrintRecord(sizex, sizey, sizez, orient, practice);
523 XtSetArg(arg[0], XtNsizey, sizey);
524 XtSetValues(w, arg, 1);
525 XtSetValues(otherw, arg, 1);
526 if (sizey <= MAXCUBES)
527 XmScaleSetValue(cubesy, sizey);
528 break;
529 case RUBIK_DECZ:
530 movesDsp = 0;
531 sizez--;
532 PrintRecord(sizex, sizey, sizez, orient, practice);
533 XtSetArg(arg[0], XtNsizez, sizez);
534 XtSetValues(w, arg, 1);
535 XtSetValues(otherw, arg, 1);
536 if (sizez <= MAXCUBES)
537 XmScaleSetValue(cubesz, sizez);
538 break;
539 case RUBIK_INCZ:
540 movesDsp = 0;
541 sizez++;
542 PrintRecord(sizex, sizey, sizez, orient, practice);
543 XtSetArg(arg[0], XtNsizez, sizez);
544 XtSetValues(w, arg, 1);
545 XtSetValues(otherw, arg, 1);
546 if (sizez <= MAXCUBES)
547 XmScaleSetValue(cubesz, sizez);
548 break;
549 case RUBIK_COMPUTED:
550 XtSetArg(arg[0], XtNstart, False);
551 XtSetValues(w, arg, 1);
552 XtSetValues(otherw, arg, 1);
553 break;
554 case RUBIK_UNDO:
555 movesDsp--;
556 XtSetArg(arg[0], XtNstart, True);
557 XtSetArg(arg[1], XtNface, callData->face);
558 XtSetArg(arg[2], XtNpos, callData->position);
559 XtSetArg(arg[3], XtNdirection, callData->direction);
560 XtSetValues(otherw, arg, 4);
561 XtSetValues(w, arg, 1);
562 break;
563 }
564 motif_print(message, messageDsp);
565 (void) sprintf(buff, "%d", movesDsp);
566 motif_print(moves, buff);
567 }
568
569 static void
CubesXSlider(Widget w,XtPointer clientData,XmScaleCallbackStruct * cbs)570 CubesXSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs)
571 {
572 int sizex = cbs->value, old, sizey, sizez;
573 Boolean orient, practice;
574
575 XtVaGetValues(rubik2d,
576 XtNsizex, &old,
577 XtNsizey, &sizey,
578 XtNsizez, &sizez,
579 XtNorient, &orient,
580 XtNpractice, &practice, NULL);
581 if (old != sizex) {
582 XtVaSetValues(rubik2d,
583 XtNsizex, sizex, NULL);
584 XtVaSetValues(rubik3d,
585 XtNsizex, sizex, NULL);
586 movesDsp = 0;
587 (void) sprintf(buff, "%d", movesDsp);
588 motif_print(moves, buff);
589 PrintRecord(sizex, sizey, sizez, orient, practice);
590 }
591 }
592
593 static void
CubesYSlider(Widget w,XtPointer clientData,XmScaleCallbackStruct * cbs)594 CubesYSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs)
595 {
596 int sizey = cbs->value, old, sizex, sizez;
597 Boolean orient, practice;
598
599 XtVaGetValues(rubik2d,
600 XtNsizex, &sizex,
601 XtNsizey, &old,
602 XtNsizez, &sizez,
603 XtNorient, &orient,
604 XtNpractice, &practice, NULL);
605 if (old != sizey) {
606 XtVaSetValues(rubik2d,
607 XtNsizey, sizey, NULL);
608 XtVaSetValues(rubik3d,
609 XtNsizey, sizey, NULL);
610 movesDsp = 0;
611 (void) sprintf(buff, "%d", movesDsp);
612 motif_print(moves, buff);
613 PrintRecord(sizex, sizey, sizez, orient, practice);
614 }
615 }
616
617 static void
CubesZSlider(Widget w,XtPointer clientData,XmScaleCallbackStruct * cbs)618 CubesZSlider(Widget w, XtPointer clientData, XmScaleCallbackStruct * cbs)
619 {
620 int sizez = cbs->value, old, sizex, sizey;
621 Boolean orient, practice;
622
623 XtVaGetValues(rubik2d,
624 XtNsizex, &sizex,
625 XtNsizey, &sizey,
626 XtNsizez, &old,
627 XtNorient, &orient,
628 XtNpractice, &practice, NULL);
629 if (old != sizez) {
630 XtVaSetValues(rubik2d,
631 XtNsizez, sizez, NULL);
632 XtVaSetValues(rubik3d,
633 XtNsizez, sizez, NULL);
634 movesDsp = 0;
635 (void) sprintf(buff, "%d", movesDsp);
636 motif_print(moves, buff);
637 PrintRecord(sizex, sizey, sizez, orient, practice);
638 }
639 }
640
641 static void
OrientToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)642 OrientToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
643 {
644 int sizex, sizey, sizez;
645 Boolean orient = cbs->set, practice;
646
647 XtVaGetValues(rubik2d,
648 XtNsizex, &sizex,
649 XtNsizey, &sizey,
650 XtNsizez, &sizez,
651 XtNpractice, &practice, NULL);
652 XtVaSetValues(rubik2d,
653 XtNorient, orient, NULL);
654 XtVaSetValues(rubik3d,
655 XtNorient, orient, NULL);
656 movesDsp = 0;
657 (void) sprintf(buff, "%d", movesDsp);
658 motif_print(moves, buff);
659 PrintRecord(sizex, sizey, sizez, orient, practice);
660 }
661
662 static void
PracticeToggle(Widget w,XtPointer clientData,XmToggleButtonCallbackStruct * cbs)663 PracticeToggle(Widget w, XtPointer clientData, XmToggleButtonCallbackStruct * cbs)
664 {
665 int sizex, sizey, sizez;
666 Boolean orient, practice = cbs->set;
667
668 XtVaSetValues(rubik2d,
669 XtNpractice, practice,
670 XtNstart, False, NULL);
671 XtVaSetValues(rubik3d,
672 XtNpractice, practice,
673 XtNstart, False, NULL);
674 XtVaGetValues(rubik2d,
675 XtNsizex, &sizex,
676 XtNsizey, &sizey,
677 XtNsizez, &sizez,
678 XtNpractice, &orient, NULL);
679 movesDsp = 0;
680 (void) sprintf(buff, "%d", movesDsp);
681 motif_print(moves, buff);
682 if (!practice)
683 (void) strcpy(messageDsp, "Randomize to start");
684 PrintRecord(sizex, sizey, sizez, orient, practice);
685 }
686
687 static void
PrintRecord(int sizex,int sizey,int sizez,Boolean orient,Boolean practice)688 PrintRecord(int sizex, int sizey, int sizez, Boolean orient, Boolean practice)
689 {
690 int i = sizex - MINCUBES, j = sizey - MINCUBES, k = sizez - MINCUBES;
691 int l = (orient) ? 1 : 0;
692
693 if (practice)
694 motif_print(record, "practice");
695 else if (sizex > MAXCUBES || sizey > MAXCUBES || sizez > MAXCUBES)
696 motif_print(record, "NOT RECORDED");
697 else if (rubikRecord[l][i][j][k].score >= MAXRECORD) {
698 (void) sprintf(buff, "NEVER %s", NOACCESS);
699 motif_print(record, buff);
700 } else {
701 (void) sprintf(buff, "%d %s",
702 rubikRecord[l][i][j][k].score, rubikRecord[l][i][j][k].name);
703 motif_print(record, buff);
704 }
705 }
706
707 static int
HandleSolved(int counter,int sizex,int sizey,int sizez,Boolean orient)708 HandleSolved(int counter, int sizex, int sizey, int sizez, Boolean orient)
709 {
710 int i = sizex - MINCUBES, j = sizey - MINCUBES, k = sizez - MINCUBES;
711 int l = (orient) ? 1 : 0;
712
713 if (sizex <= MAXCUBES && sizey <= MAXCUBES && sizez <= MAXCUBES &&
714 counter < rubikRecord[l][i][j][k].score) {
715 rubikRecord[l][i][j][k].score = counter;
716 (void) strcpy(rubikRecord[l][i][j][k].name, usernameDsp);
717 if ((sizex < 2 && sizey < 2 && sizez < 2) || (orient &&
718 (counter < rubikRecord[!l][i][j][k].score))) {
719 rubikRecord[!l][i][j][k].score = counter;
720 (void) strcpy(rubikRecord[!l][i][j][k].name, usernameDsp);
721 }
722 WriteRecords();
723 PrintRecord(sizex, sizey, sizez, orient, False);
724 return True;
725 }
726 return False;
727 }
728
729 static void
InitRecords(void)730 InitRecords(void)
731 {
732 int i, j, k, orient;
733
734 for (orient = 0; orient < 2; orient++)
735 for (i = 0; i < MAXCUBES - MINCUBES + 1; i++)
736 for (j = i; j < MAXCUBES - MINCUBES + 1; j++)
737 for (k = j; k < MAXCUBES - MINCUBES + 1; k++) {
738 rubikRecord[orient][k][j][i].score = rubikRecord[orient][k][i][j].score =
739 rubikRecord[orient][j][k][i].score = rubikRecord[orient][j][i][k].score =
740 rubikRecord[orient][i][k][j].score = rubikRecord[orient][i][j][k].score = MAXRECORD;
741 (void) strcpy(rubikRecord[orient][k][j][i].name, NOACCESS);
742 (void) strcpy(rubikRecord[orient][k][i][j].name, NOACCESS);
743 (void) strcpy(rubikRecord[orient][j][k][i].name, NOACCESS);
744 (void) strcpy(rubikRecord[orient][j][i][k].name, NOACCESS);
745 (void) strcpy(rubikRecord[orient][i][k][j].name, NOACCESS);
746 (void) strcpy(rubikRecord[orient][i][j][k].name, NOACCESS);
747 }
748 }
749
750 static void
ReadRecords(void)751 ReadRecords(void)
752 {
753 FILE *fp;
754 int i, j, k, n, orient;
755 char username[USERNAMELEN];
756
757 if ((fp = fopen(SCOREFILE, "r")) == NULL) {
758 (void) sprintf(buff, "Can not open %s, taking defaults.", SCOREFILE);
759 motif_print(message, buff);
760 } else {
761 for (orient = 0; orient < 2; orient++)
762 for (i = 0; i < MAXCUBES - MINCUBES + 1; i++)
763 for (j = i; j < MAXCUBES - MINCUBES + 1; j++)
764 for (k = j; k < MAXCUBES - MINCUBES + 1; k++) {
765 (void) fscanf(fp, "%d %s\n", &n, username);
766 if (n <= rubikRecord[orient][i][j][k].score) {
767 rubikRecord[orient][k][j][i].score = rubikRecord[orient][k][i][j].score =
768 rubikRecord[orient][j][k][i].score = rubikRecord[orient][j][i][k].score =
769 rubikRecord[orient][i][k][j].score = rubikRecord[orient][i][j][k].score = n;
770 (void) strcpy(rubikRecord[orient][k][j][i].name, username);
771 (void) strcpy(rubikRecord[orient][k][i][j].name, username);
772 (void) strcpy(rubikRecord[orient][j][k][i].name, username);
773 (void) strcpy(rubikRecord[orient][j][i][k].name, username);
774 (void) strcpy(rubikRecord[orient][i][k][j].name, username);
775 (void) strcpy(rubikRecord[orient][i][j][k].name, username);
776 }
777 }
778 (void) fclose(fp);
779 }
780 }
781
782 static void
WriteRecords(void)783 WriteRecords(void)
784 {
785 FILE *fp;
786 int i, j, k, orient;
787
788 if ((fp = fopen(SCOREFILE, "w")) == NULL) {
789 (void) sprintf(buff, "Can not write to %s.", SCOREFILE);
790 motif_print(message, buff);
791 } else {
792 #if HAVE_FCNTL_H
793 int lfd;
794 char lockfile[FILENAMELEN];
795
796 (void) strcpy(lockfile, SCOREFILE);
797 (void) strcat(lockfile, ".lock");
798 while (((lfd = open(lockfile, O_CREAT | O_EXCL, 0644)) < 0) &&
799 errno == EEXIST)
800 (void) sleep(1);
801 if (lfd < 0) {
802 #if 1
803 (void) fprintf(stderr, "Lock file exists... guessing its an old one.\n");
804 #else
805 (void) fprintf(stderr, "Lock file exists... score not recorded - sorry.\n"
806 );
807 return;
808 #endif
809 }
810 #endif
811 for (orient = 0; orient < 2; orient++) {
812 for (i = 0; i < MAXCUBES - MINCUBES + 1; i++) {
813 for (j = i; j < MAXCUBES - MINCUBES + 1; j++) {
814 for (k = j; k < MAXCUBES - MINCUBES + 1; k++)
815 (void) fprintf(fp, "%d %s\n",
816 rubikRecord[orient][i][j][k].score, rubikRecord[orient][i][j][k].name);
817 (void) fprintf(fp, "\n");
818 }
819 (void) fprintf(fp, "\n");
820 }
821
822 (void) fprintf(fp, "\n");
823 }
824 #if HAVE_FCNTL_H
825 (void) close(lfd);
826 (void) unlink(lockfile);
827 #endif
828 (void) fclose(fp);
829 }
830 }
831
832 static void
motif_print(Widget w,char * text)833 motif_print(Widget w, char *text)
834 {
835 Arg wargs[1];
836 XmString xmstr;
837
838 if (!XtIsSubclass(w, xmLabelWidgetClass))
839 XtError("motif_print() requires a Label Widget");
840 xmstr = XmStringCreateLtoR(text, XmSTRING_DEFAULT_CHARSET);
841 XtSetArg(wargs[0], XmNlabelString, xmstr);
842 XtSetValues(w, wargs, 1);
843 }
844