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