1 /*-
2 # X-BASED MASTERBALL(tm)
3 #
4 # Mball.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 Mball */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <math.h>
31 #ifndef M_PI
32 #define M_PI 3.14159265358979323846
33 #endif
34 #ifdef VMS
35 #include <unixlib.h>
36 #else
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #endif
41 #include <X11/IntrinsicP.h>
42 #include <X11/Intrinsic.h>
43 #include <X11/StringDefs.h>
44 #include <X11/CoreP.h>
45 #include "MballP.h"
46
47 #ifndef DATAFILE
48 #define DATAFILE "/usr/games/lib/mball.data"
49 #endif
50
51 static void InitializeMball(Widget request, Widget renew);
52 static void ExposeMball(Widget renew, XEvent * event, Region region);
53 static void ResizeMball(MballWidget w);
54 static void DestroyMball(Widget old);
55 static Boolean SetValuesMball(Widget current, Widget request, Widget renew);
56 static void QuitMball(MballWidget w, XEvent * event, char **args, int nArgs);
57 static void PracticeMball(MballWidget w, XEvent * event, char **args, int nArgs);
58 static void PracticeMballMaybe(MballWidget w, XEvent * event, char **args, int nArgs);
59 static void RandomizeMball(MballWidget w, XEvent * event, char **args, int nArgs);
60 static void RandomizeMballMaybe(MballWidget w, XEvent * event, char **args, int nArgs);
61 static void GetMball(MballWidget w, XEvent * event, char **args, int nArgs);
62 static void WriteMball(MballWidget w, XEvent * event, char **args, int nArgs);
63 static void UndoMball(MballWidget w, XEvent * event, char **args, int nArgs);
64 static void SolveMball(MballWidget w, XEvent * event, char **args, int nArgs);
65 static void IncrementMball(MballWidget w, XEvent * event, char **args, int nArgs);
66 static void DecrementMball(MballWidget w, XEvent * event, char **args, int nArgs);
67 static void OrientizeMball(MballWidget w, XEvent * event, char **args, int nArgs);
68 static void Wedge2ModeMball(MballWidget w, XEvent * event, char **args, int nArgs);
69 static void Wedge4ModeMball(MballWidget w, XEvent * event, char **args, int nArgs);
70 static void Wedge6ModeMball(MballWidget w, XEvent * event, char **args, int nArgs);
71 static void Wedge8ModeMball(MballWidget w, XEvent * event, char **args, int nArgs);
72 static void Wedge10ModeMball(MballWidget w, XEvent * event, char **args, int nArgs);
73 static void Wedge12ModeMball(MballWidget w, XEvent * event, char **args, int nArgs);
74 static void MoveMballTl(MballWidget w, XEvent * event, char **args, int nArgs);
75 static void MoveMballTop(MballWidget w, XEvent * event, char **args, int nArgs);
76 static void MoveMballTr(MballWidget w, XEvent * event, char **args, int nArgs);
77 static void MoveMballLeft(MballWidget w, XEvent * event, char **args, int nArgs);
78 static void MoveMballCw(MballWidget w, XEvent * event, char **args, int nArgs);
79 static void MoveMballRight(MballWidget w, XEvent * event, char **args, int nArgs);
80 static void MoveMballBl(MballWidget w, XEvent * event, char **args, int nArgs);
81 static void MoveMballBottom(MballWidget w, XEvent * event, char **args, int nArgs);
82 static void MoveMballBr(MballWidget w, XEvent * event, char **args, int nArgs);
83 static void MoveMballCcw(MballWidget w, XEvent * event, char **args, int nArgs);
84 static void MoveMballInput(MballWidget w, int x, int y, int direction, int control);
85 static void SelectMball(MballWidget w, XEvent * event, char **args, int nArgs);
86 static void ReleaseMball(MballWidget w, XEvent * event, char **args, int nArgs);
87
88 static void SetAllColors(MballWidget w, Boolean init);
89 static void GetColor(MballWidget w, int wedge, Boolean init);
90 static void MoveControlCb(MballWidget w, int wedge, int direction);
91 static void CheckWedges(MballWidget w);
92 static void ResetWedges(MballWidget w);
93 static void ResizeWedges(MballWidget w);
94 static Boolean SelectWedges(MballWidget w, int x, int y, int *wedge, int *ring, int *view);
95 static Boolean PositionWedges(MballWidget w, int x, int y, int *wedge, int *ring, int *direction);
96 static void MoveNoWedges(MballWidget w);
97 static void PracticeWedges(MballWidget w);
98 static void RandomizeWedges(MballWidget w);
99 static void MoveWedges(MballWidget w, int wedge, int ring, int direction);
100
101 /* rcd : row, column, or diagonal */
102 static void SwapWedges(MballWidget w, int wedge1, int wedge2);
103 static void DrawFrame(MballWidget w, GC gc);
104 static void DrawWedge(MballWidget w, int wedge);
105 static void DrawSector(MballWidget w, int wedge, int ring, int offset);
106 static void DrawRadar(MballWidget w, GC gc, int startx, int starty, int lengthx, int lengthy);
107 static void DrawSect(MballWidget w, GC wedgeGC, GC borderGC, int r, int wedge, int startx, int starty, int lengthx, int lengthy);
108 static void LetterPosition(MballWidget w, int wedge, int ring, int lengthx, int lengthy, int *dx, int *dy);
109 static void OffsetSect(MballWidget w, int wedge, int *dx, int *dy);
110 static void XFillSector(Display * display, Drawable drawable, GC gc, int xo, int yo, int width1, int height1, int width2, int height2, int angle1, int angle2);
111 static void XDrawSector(Display * display, Drawable drawable, GC gc, int xo, int yo, int width1, int height1, int width2, int height2, int angle1, int angle2);
112 static int int2String(char *buf, int number, int base, Boolean capital);
113
114 #ifdef DEBUG
115 static void PrintMball(MballWidget w);
116
117 #endif
118
119 static char defaultTranslationsMball[] =
120 "<KeyPress>q: Quit()\n\
121 Ctrl<KeyPress>C: Quit()\n\
122 <KeyPress>KP_Divide: MoveCcw()\n\
123 <KeyPress>Home: MoveTl()\n\
124 <KeyPress>KP_7: MoveTl()\n\
125 <KeyPress>R7: MoveTl()\n\
126 <KeyPress>Up: MoveTop()\n\
127 <KeyPress>KP_8: MoveTop()\n\
128 <KeyPress>R8: MoveTop()\n\
129 <KeyPress>Prior: MoveTr()\n\
130 <KeyPress>KP_9: MoveTr()\n\
131 <KeyPress>R9: MoveTr()\n\
132 <KeyPress>Left: MoveLeft()\n\
133 <KeyPress>KP_4: MoveLeft()\n\
134 <KeyPress>R10: MoveLeft()\n\
135 <KeyPress>Begin: MoveCw()\n\
136 <KeyPress>KP_5: MoveCw()\n\
137 <KeyPress>R11: MoveCw()\n\
138 <KeyPress>Right: MoveRight()\n\
139 <KeyPress>KP_6: MoveRight()\n\
140 <KeyPress>R12: MoveRight()\n\
141 <KeyPress>End: MoveBl()\n\
142 <KeyPress>KP_1: MoveBl()\n\
143 <KeyPress>R13: MoveBl()\n\
144 <KeyPress>Down: MoveBottom()\n\
145 <KeyPress>KP_2: MoveBottom()\n\
146 <KeyPress>R14: MoveBottom()\n\
147 <KeyPress>Next: MoveBr()\n\
148 <KeyPress>KP_3: MoveBr()\n\
149 <KeyPress>R15: MoveBr()\n\
150 <KeyPress>p: Practice()\n\
151 <Btn1Down>: Select()\n\
152 <Btn1Up>: Release()\n\
153 <Btn2Down>(2+): Practice()\n\
154 <Btn2Down>: PracticeMaybe()\n\
155 <KeyPress>r: Randomize()\n\
156 <Btn3Down>(2+): Randomize()\n\
157 <Btn3Down>: RandomizeMaybe()\n\
158 <KeyPress>g: Get()\n\
159 <KeyPress>w: Write()\n\
160 <KeyPress>u: Undo()\n\
161 <KeyPress>s: Solve()\n\
162 <KeyPress>i: Increment()\n\
163 <KeyPress>d: Decrement()\n\
164 <KeyPress>o: Orientize()\n\
165 <KeyPress>2: Wedge2()\n\
166 <KeyPress>4: Wedge4()\n\
167 <KeyPress>6: Wedge6()\n\
168 <KeyPress>8: Wedge8()\n\
169 <KeyPress>0: Wedge10()\n\
170 <KeyPress>=: Wedge12()\n\
171 <KeyPress>.: Wedge12()";
172
173 /* '=' is the 2nd key to the right of '0' on keyboard
174 '.' follows '0' on keypad
175 */
176
177 static XtActionsRec actionsListMball[] =
178 {
179 {"Quit", (XtActionProc) QuitMball},
180 {"MoveCcw", (XtActionProc) MoveMballCcw},
181 {"MoveTl", (XtActionProc) MoveMballTl},
182 {"MoveTop", (XtActionProc) MoveMballTop},
183 {"MoveTr", (XtActionProc) MoveMballTr},
184 {"MoveLeft", (XtActionProc) MoveMballLeft},
185 {"MoveCw", (XtActionProc) MoveMballCw},
186 {"MoveRight", (XtActionProc) MoveMballRight},
187 {"MoveBl", (XtActionProc) MoveMballBl},
188 {"MoveBottom", (XtActionProc) MoveMballBottom},
189 {"MoveBr", (XtActionProc) MoveMballBr},
190 {"Select", (XtActionProc) SelectMball},
191 {"Release", (XtActionProc) ReleaseMball},
192 {"Practice", (XtActionProc) PracticeMball},
193 {"PracticeMaybe", (XtActionProc) PracticeMballMaybe},
194 {"Randomize", (XtActionProc) RandomizeMball},
195 {"RandomizeMaybe", (XtActionProc) RandomizeMballMaybe},
196 {"Get", (XtActionProc) GetMball},
197 {"Write", (XtActionProc) WriteMball},
198 {"Undo", (XtActionProc) UndoMball},
199 {"Solve", (XtActionProc) SolveMball},
200 {"Increment", (XtActionProc) IncrementMball},
201 {"Decrement", (XtActionProc) DecrementMball},
202 {"Orientize", (XtActionProc) OrientizeMball},
203 {"Wedge2", (XtActionProc) Wedge2ModeMball},
204 {"Wedge4", (XtActionProc) Wedge4ModeMball},
205 {"Wedge6", (XtActionProc) Wedge6ModeMball},
206 {"Wedge8", (XtActionProc) Wedge8ModeMball},
207 {"Wedge10", (XtActionProc) Wedge10ModeMball},
208 {"Wedge12", (XtActionProc) Wedge12ModeMball}
209 };
210
211 static XtResource resourcesMball[] =
212 {
213 {XtNuserName, XtCUserName, XtRString, sizeof (String),
214 XtOffset(MballWidget, mball.username), XtRString, "nobody"},
215 {XtNwedgeColor0, XtCLabel, XtRString, sizeof (String),
216 XtOffset(MballWidget, mball.wedgeName[0]), XtRString, "Yellow"},
217 {XtNwedgeColor1, XtCLabel, XtRString, sizeof (String),
218 XtOffset(MballWidget, mball.wedgeName[1]), XtRString, "Blue"},
219 {XtNwedgeColor2, XtCLabel, XtRString, sizeof (String),
220 XtOffset(MballWidget, mball.wedgeName[2]), XtRString, "Red"},
221 {XtNwedgeColor3, XtCLabel, XtRString, sizeof (String),
222 XtOffset(MballWidget, mball.wedgeName[3]), XtRString, "Magenta"},
223 {XtNwedgeColor4, XtCLabel, XtRString, sizeof (String),
224 XtOffset(MballWidget, mball.wedgeName[4]), XtRString, "Green"},
225 {XtNwedgeColor5, XtCLabel, XtRString, sizeof (String),
226 XtOffset(MballWidget, mball.wedgeName[5]), XtRString, "Orange"},
227 {XtNwedgeColor6, XtCLabel, XtRString, sizeof (String),
228 XtOffset(MballWidget, mball.wedgeName[6]), XtRString, "Cyan"},
229 {XtNwedgeColor7, XtCLabel, XtRString, sizeof (String),
230 XtOffset(MballWidget, mball.wedgeName[7]), XtRString, "Dark Green"},
231 {XtNwedgeColor8, XtCLabel, XtRString, sizeof (String),
232 XtOffset(MballWidget, mball.wedgeName[8]), XtRString, "Pink"},
233 {XtNwedgeColor9, XtCLabel, XtRString, sizeof (String),
234 XtOffset(MballWidget, mball.wedgeName[9]), XtRString, "Light Gray"},
235 {XtNwedgeColor10, XtCLabel, XtRString, sizeof (String),
236 XtOffset(MballWidget, mball.wedgeName[10]), XtRString, "Aquamarine"},
237 {XtNwedgeColor11, XtCLabel, XtRString, sizeof (String),
238 XtOffset(MballWidget, mball.wedgeName[11]), XtRString, "Turquoise"},
239 {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
240 XtOffset(MballWidget, mball.foreground), XtRString, XtDefaultForeground},
241 {XtNpieceBorder, XtCColor, XtRPixel, sizeof (Pixel),
242 XtOffset(MballWidget, mball.borderColor), XtRString, XtDefaultForeground},
243 {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
244 XtOffset(MballWidget, core.width), XtRString, "200"},
245 {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
246 XtOffset(MballWidget, core.height), XtRString, "400"},
247 {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
248 XtOffset(MballWidget, mball.mono), XtRString, "FALSE"},
249 {XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
250 XtOffset(MballWidget, mball.reverse), XtRString, "FALSE"},
251 {XtNwedges, XtCWedges, XtRInt, sizeof (int),
252 XtOffset(MballWidget, mball.wedges), XtRString, "8"}, /*DEFAULTWEDGES */
253 {XtNrings, XtCRings, XtRInt, sizeof (int),
254 XtOffset(MballWidget, mball.rings), XtRString, "4"}, /*DEFAULTRINGS */
255 {XtNorient, XtCOrient, XtRBoolean, sizeof (Boolean),
256 XtOffset(MballWidget, mball.orient), XtRString, "FALSE"}, /*DEFAULTORIENT */
257 {XtNpractice, XtCPractice, XtRBoolean, sizeof (Boolean),
258 XtOffset(MballWidget, mball.practice), XtRString, "FALSE"}, /*DEFAULTPRACTICE */
259 {XtNbase, XtCBase, XtRInt, sizeof (int),
260 XtOffset(MballWidget, mball.base), XtRString, "16"},
261 {XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
262 XtOffset(MballWidget, mball.started), XtRString, "FALSE"},
263 {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
264 XtOffset(MballWidget, mball.select), XtRCallback, NULL}
265 };
266
267 MballClassRec mballClassRec =
268 {
269 {
270 (WidgetClass) & widgetClassRec, /* superclass */
271 "Mball", /* class name */
272 sizeof (MballRec), /* widget size */
273 NULL, /* class initialize */
274 NULL, /* class part initialize */
275 FALSE, /* class inited */
276 (XtInitProc) InitializeMball, /* initialize */
277 NULL, /* initialize hook */
278 XtInheritRealize, /* realize */
279 actionsListMball, /* actions */
280 XtNumber(actionsListMball), /* num actions */
281 resourcesMball, /* resources */
282 XtNumber(resourcesMball), /* num resources */
283 NULLQUARK, /* xrm class */
284 TRUE, /* compress motion */
285 TRUE, /* compress exposure */
286 TRUE, /* compress enterleave */
287 TRUE, /* visible interest */
288 (XtWidgetProc) DestroyMball, /* destroy */
289 (XtWidgetProc) ResizeMball, /* resize */
290 (XtExposeProc) ExposeMball, /* expose */
291 (XtSetValuesFunc) SetValuesMball, /* set values */
292 NULL, /* set values hook */
293 XtInheritSetValuesAlmost, /* set values almost */
294 NULL, /* get values hook */
295 NULL, /* accept focus */
296 XtVersion, /* version */
297 NULL, /* callback private */
298 defaultTranslationsMball, /* tm table */
299 NULL, /* query geometry */
300 NULL, /* display accelerator */
301 NULL /* extension */
302 },
303 {
304 0 /* ignore */
305 }
306 };
307
308
309 /* COORD == 12 not 8 */
310 static int mapDirToWedge[(MAXWEDGES - MINWEDGES) / 2 + 1][12] =
311 {
312 {
313 0, 4, 4, 4, 0, 4, 4, 4
314 },
315 {
316 0, 4, 1, 4, 0, 4, 1, 4
317 },
318 {
319 0, 1, 4, 2, 0, 1, 4, 2
320 },
321 {
322 0, 1, 2, 3, 0, 1, 2, 3
323 },
324 {
325 0, 1, 2, 3, 0, 1, 2, 3
326 },
327 {
328 0, 1, 2, 3, 0, 1, 2, 3
329 }
330 };
331
332 /* COORD == 12 not 8 */
333 static int mapWedgeToDir[(MAXWEDGES - MINWEDGES) / 2 + 1][12] =
334 {
335 {
336 0, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
337 },
338 {
339 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8
340 },
341 {
342 0, 1, 3, 4, 5, 7, 8, 8, 8, 8, 8, 8
343 },
344 {
345 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8
346 },
347 {
348 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8
349 },
350 {
351 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
352 }
353 };
354
355 WidgetClass mballWidgetClass = (WidgetClass) & mballClassRec;
356
357 static void
InitializeMball(Widget request,Widget renew)358 InitializeMball(Widget request, Widget renew)
359 {
360 MballWidget w = (MballWidget) renew;
361 int wedge;
362
363 for (wedge = 0; wedge < MAXWEDGES; wedge++)
364 w->mball.mballLoc[wedge] = NULL;
365 CheckWedges(w);
366 InitMoves();
367 ResetWedges(w);
368 (void) SRAND(getpid());
369 w->mball.depth = DefaultDepthOfScreen(XtScreen(w));
370 SetAllColors(w, True);
371 ResizeMball(w);
372 }
373
374 static void
DestroyMball(Widget old)375 DestroyMball(Widget old)
376 {
377 MballWidget w = (MballWidget) old;
378 int wedge;
379
380 for (wedge = 0; wedge < MAXWEDGES; wedge++) {
381 XtReleaseGC(old, w->mball.wedgeGC[wedge]);
382 }
383 XtReleaseGC(old, w->mball.borderGC);
384 XtReleaseGC(old, w->mball.puzzleGC);
385 XtReleaseGC(old, w->mball.inverseGC);
386 XtRemoveCallbacks(old, XtNselectCallback, w->mball.select);
387 }
388
389 static void
ResizeMball(MballWidget w)390 ResizeMball(MballWidget w)
391 {
392 int tempLength;
393
394 w->mball.delta = 4;
395 w->mball.vertical = (w->core.height >= w->core.width);
396 if (w->mball.vertical)
397 tempLength = MIN(w->core.height / 2, w->core.width);
398 else
399 tempLength = MIN(w->core.height, w->core.width / 2);
400 w->mball.mballLength = MAX((tempLength - w->mball.delta + 1) /
401 w->mball.wedges, 0);
402 w->mball.wedgeLength = w->mball.wedges * w->mball.mballLength;
403 w->mball.viewLength = w->mball.wedgeLength + w->mball.delta;
404 w->mball.viewMiddle = w->mball.viewLength / 2;
405 if (w->mball.vertical) {
406 w->mball.puzzleSize.x = w->mball.viewLength - 1;
407 w->mball.puzzleSize.y = 2 * w->mball.viewLength - w->mball.delta - 2;
408 } else {
409 w->mball.puzzleSize.x = 2 * w->mball.viewLength - w->mball.delta - 2;
410 w->mball.puzzleSize.y = w->mball.viewLength - 1;
411 }
412 w->mball.puzzleOffset.x = ((int) w->core.width - w->mball.puzzleSize.x) / 2;
413 w->mball.puzzleOffset.y = ((int) w->core.height - w->mball.puzzleSize.y) / 2;
414 ResizeWedges(w);
415 }
416
417 static void
ExposeMball(Widget renew,XEvent * event,Region region)418 ExposeMball(Widget renew, XEvent * event, Region region)
419 {
420 MballWidget w = (MballWidget) renew;
421
422 if (w->core.visible) {
423 if (w->mball.reverse)
424 XFillRectangle(XtDisplay(w), XtWindow(w),
425 w->mball.inverseGC, 0, 0, w->core.width, w->core.height);
426 DrawFrame(w, w->mball.puzzleGC);
427 DrawAllWedges(w);
428 }
429 }
430
431 static Boolean
SetValuesMball(Widget current,Widget request,Widget renew)432 SetValuesMball(Widget current, Widget request, Widget renew)
433 {
434 MballWidget c = (MballWidget) current, w = (MballWidget) renew;
435 Boolean redraw = False, setColors = False;
436 int wedge;
437
438 CheckWedges(w);
439 for (wedge = 0; wedge < MAXWEDGES; wedge++) {
440 if (strcmp(w->mball.wedgeName[wedge], c->mball.wedgeName[wedge])) {
441 setColors = True;
442 break;
443 }
444 }
445 if (w->core.background_pixel != c->core.background_pixel ||
446 w->mball.foreground != c->mball.foreground ||
447 w->mball.borderColor != c->mball.borderColor ||
448 w->mball.reverse != c->mball.reverse ||
449 w->mball.mono != c->mball.mono ||
450 setColors) {
451 SetAllColors(w, False);
452 redraw = True;
453 }
454 if (w->mball.orient != c->mball.orient ||
455 w->mball.base != c->mball.base ||
456 w->mball.practice != c->mball.practice) {
457 ResetWedges(w);
458 redraw = True;
459 }
460 if (w->mball.wedges != c->mball.wedges ||
461 w->mball.rings != c->mball.rings) {
462 ResetWedges(w);
463 ResizeMball(w);
464 redraw = True;
465 }
466 if (w->mball.mballLength != c->mball.mballLength) {
467 ResizeMball(w);
468 redraw = True;
469 }
470 return (redraw);
471 }
472
473 static void
QuitMball(MballWidget w,XEvent * event,char ** args,int nArgs)474 QuitMball(MballWidget w, XEvent * event, char **args, int nArgs)
475 {
476 XtCloseDisplay(XtDisplay(w));
477 exit(0);
478 }
479
480 static void
SelectMball(MballWidget w,XEvent * event,char ** args,int nArgs)481 SelectMball(MballWidget w, XEvent * event, char **args, int nArgs)
482 {
483 int view, control;
484
485 if (SelectWedges(w, event->xbutton.x, event->xbutton.y,
486 &(w->mball.currentWedge), &(w->mball.currentRing), &view)) {
487 control = (int) (event->xkey.state & ControlMask);
488 if (control || w->mball.practice || !CheckSolved(w))
489 DrawSector(w, w->mball.currentWedge, w->mball.currentRing, TRUE);
490 } else
491 w->mball.currentWedge = -1;
492 }
493
494 static void
ReleaseMball(MballWidget w,XEvent * event,char ** args,int nArgs)495 ReleaseMball(MballWidget w, XEvent * event, char **args, int nArgs)
496 {
497 int control, wedge, ring, view, i, diff, opp;
498 mballCallbackStruct cb;
499
500 if (w->mball.currentWedge == -1)
501 return;
502 DrawSector(w, w->mball.currentWedge, w->mball.currentRing, FALSE);
503 control = (int) (event->xkey.state & ControlMask);
504 if (!control && !w->mball.practice && CheckSolved(w))
505 MoveNoWedges(w);
506 else if (SelectWedges(w, event->xbutton.x, event->xbutton.y,
507 &wedge, &ring, &view)) {
508 opp = (w->mball.currentWedge + w->mball.wedges / 2) % w->mball.wedges;
509 if (ring == w->mball.currentRing) {
510 if (wedge == w->mball.currentWedge)
511 return;
512 if (opp == (wedge + 1) % w->mball.wedges ||
513 wedge == (opp + 1) % w->mball.wedges) {
514 cb.reason = MBALL_AMBIGUOUS;
515 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
516 } else {
517 diff = (w->mball.currentWedge - wedge + w->mball.wedges) %
518 w->mball.wedges;
519 if (diff > w->mball.wedges / 2)
520 for (i = 0; i < w->mball.wedges - diff; i++)
521 MoveMball(w, wedge, ring, CW, control);
522 else
523 for (i = 0; i < diff; i++)
524 MoveMball(w, wedge, ring, CCW, control);
525 if (!control && CheckSolved(w)) {
526 cb.reason = MBALL_SOLVED;
527 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
528 }
529 }
530 } else if (wedge == w->mball.currentWedge && w->mball.wedges > 2) {
531 cb.reason = MBALL_AMBIGUOUS;
532 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
533 } else if (opp == (wedge + 1) % w->mball.wedges)
534 MoveMball(w, wedge, ring,
535 mapWedgeToDir[(w->mball.wedges - MINWEDGES) / 2]
536 [w->mball.currentWedge], control);
537 else if (wedge == (opp + 1) % w->mball.wedges)
538 MoveMball(w, wedge, ring,
539 mapWedgeToDir[(w->mball.wedges - MINWEDGES) / 2][wedge], control);
540 else
541 MoveNoWedges(w);
542 }
543 }
544
545 static void
PracticeMball(MballWidget w,XEvent * event,char ** args,int nArgs)546 PracticeMball(MballWidget w, XEvent * event, char **args, int nArgs)
547 {
548 PracticeWedges(w);
549 }
550
551 static void
PracticeMballMaybe(MballWidget w,XEvent * event,char ** args,int nArgs)552 PracticeMballMaybe(MballWidget w, XEvent * event, char **args, int nArgs)
553 {
554 if (!w->mball.started)
555 PracticeWedges(w);
556 }
557
558 static void
RandomizeMball(MballWidget w,XEvent * event,char ** args,int nArgs)559 RandomizeMball(MballWidget w, XEvent * event, char **args, int nArgs)
560 {
561 RandomizeWedges(w);
562 }
563
564 static void
RandomizeMballMaybe(MballWidget w,XEvent * event,char ** args,int nArgs)565 RandomizeMballMaybe(MballWidget w, XEvent * event, char **args, int nArgs)
566 {
567 if (!w->mball.started)
568 RandomizeWedges(w);
569 }
570
571 static void
GetMball(MballWidget w,XEvent * event,char ** args,int nArgs)572 GetMball(MballWidget w, XEvent * event, char **args, int nArgs)
573 {
574 FILE *fp;
575 char c;
576 int i, wedge, ring, orient, practice, moves;
577 mballCallbackStruct cb;
578
579 if ((fp = fopen(DATAFILE, "r")) == NULL)
580 (void) printf("Can not read %s for get.\n", DATAFILE);
581 else {
582 FlushMoves(w);
583 while ((c = getc(fp)) != EOF && c != SYMBOL);
584 (void) fscanf(fp, "%d", &wedge);
585 if (wedge >= MINWEDGES && wedge <= MAXWEDGES && !(wedge % 2)) {
586 if (w->mball.wedges != wedge) {
587 cb.reason = (wedge - MINWEDGES) / 2 + MBALL_WEDGE2;
588 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
589 }
590 } else {
591 (void) printf("%s corrupted: ", DATAFILE);
592 (void) printf("wedge %d should be even and between %d and %d\n",
593 wedge, MINWEDGES, MAXWEDGES);
594 }
595 while ((c = getc(fp)) != EOF && c != SYMBOL);
596 (void) fscanf(fp, "%d", &ring);
597 if (ring >= MINRINGS) {
598 for (i = w->mball.rings; i < ring; i++) {
599 cb.reason = MBALL_INC;
600 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
601 }
602 for (i = w->mball.rings; i > ring; i--) {
603 cb.reason = MBALL_DEC;
604 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
605 }
606 } else
607 (void) printf("%s corrupted: ring %d should be between %d and MAXINT\n",
608 DATAFILE, ring, MINRINGS);
609 while ((c = getc(fp)) != EOF && c != SYMBOL);
610 (void) fscanf(fp, "%d", &orient);
611 if (w->mball.orient != (Boolean) orient) {
612 cb.reason = MBALL_ORIENT;
613 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
614 }
615 while ((c = getc(fp)) != EOF && c != SYMBOL);
616 (void) fscanf(fp, "%d", &practice);
617 if (w->mball.practice != (Boolean) practice) {
618 cb.reason = MBALL_PRACTICE;
619 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
620 }
621 while ((c = getc(fp)) != EOF && c != SYMBOL);
622 (void) fscanf(fp, "%d", &moves);
623 ScanStartPosition(fp, w);
624 cb.reason = MBALL_RESTORE;
625 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
626 SetStartPosition(w);
627 ScanMoves(fp, w, moves);
628 (void) fclose(fp);
629 (void) printf("%s: wedge %d, ring %d, orient %d, ",
630 DATAFILE, wedge, ring, orient);
631 (void) printf("practice %d, moves %d\n", practice, moves);
632 }
633 }
634
635 static void
WriteMball(MballWidget w,XEvent * event,char ** args,int nArgs)636 WriteMball(MballWidget w, XEvent * event, char **args, int nArgs)
637 {
638 FILE *fp;
639
640 if ((fp = fopen(DATAFILE, "w")) == NULL)
641 (void) printf("Can not write to %s.\n", DATAFILE);
642 else {
643 (void) fprintf(fp, "wedge%c %d\n", SYMBOL, w->mball.wedges);
644 (void) fprintf(fp, "ring%c %d\n", SYMBOL, w->mball.rings);
645 (void) fprintf(fp, "orient%c %d\n", SYMBOL, (w->mball.orient) ? 1 : 0);
646 (void) fprintf(fp, "practice%c %d\n", SYMBOL, (w->mball.practice) ? 1 : 0);
647 (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
648 PrintStartPosition(fp, w);
649 PrintMoves(fp);
650 (void) fclose(fp);
651 (void) printf("Saved to %s.\n", DATAFILE);
652 }
653 }
654
655 static void
UndoMball(MballWidget w,XEvent * event,char ** args,int nArgs)656 UndoMball(MballWidget w, XEvent * event, char **args, int nArgs)
657 {
658 if (MadeMoves()) {
659 int wedge, ring, direction, control;
660
661 GetMove(&wedge, &ring, &direction, &control);
662 direction = (direction < COORD) ? direction : 3 * COORD - direction;
663 if (control)
664 MoveControlCb(w, wedge, direction);
665 else {
666 mballCallbackStruct cb;
667
668 MoveWedges(w, wedge, ring, direction);
669 cb.reason = MBALL_UNDO;
670 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
671 }
672 }
673 }
674
675 static void
SolveMball(MballWidget w,XEvent * event,char ** args,int nArgs)676 SolveMball(MballWidget w, XEvent * event, char **args, int nArgs)
677 {
678 #if 0
679 SolveWedges(w); /* Sorry, this is not implemented */
680 #endif
681 }
682
683 static void
IncrementMball(MballWidget w,XEvent * event,char ** args,int nArgs)684 IncrementMball(MballWidget w, XEvent * event, char **args, int nArgs)
685 {
686 mballCallbackStruct cb;
687
688 cb.reason = MBALL_INC;
689 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
690 }
691
692 static void
DecrementMball(MballWidget w,XEvent * event,char ** args,int nArgs)693 DecrementMball(MballWidget w, XEvent * event, char **args, int nArgs)
694 {
695 mballCallbackStruct cb;
696
697 if (w->mball.rings <= MINRINGS)
698 return;
699 cb.reason = MBALL_DEC;
700 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
701 }
702
703 static void
OrientizeMball(MballWidget w,XEvent * event,char ** args,int nArgs)704 OrientizeMball(MballWidget w, XEvent * event, char **args, int nArgs)
705 {
706 mballCallbackStruct cb;
707
708 cb.reason = MBALL_ORIENT;
709 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
710 }
711
712 static void
Wedge2ModeMball(MballWidget w,XEvent * event,char ** args,int nArgs)713 Wedge2ModeMball(MballWidget w, XEvent * event, char **args, int nArgs)
714 {
715 mballCallbackStruct cb;
716
717 cb.reason = MBALL_WEDGE2;
718 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
719 }
720
721 static void
Wedge4ModeMball(MballWidget w,XEvent * event,char ** args,int nArgs)722 Wedge4ModeMball(MballWidget w, XEvent * event, char **args, int nArgs)
723 {
724 mballCallbackStruct cb;
725
726 cb.reason = MBALL_WEDGE4;
727 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
728 }
729
730 static void
Wedge6ModeMball(MballWidget w,XEvent * event,char ** args,int nArgs)731 Wedge6ModeMball(MballWidget w, XEvent * event, char **args, int nArgs)
732 {
733 mballCallbackStruct cb;
734
735 cb.reason = MBALL_WEDGE6;
736 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
737 }
738
739 static void
Wedge8ModeMball(MballWidget w,XEvent * event,char ** args,int nArgs)740 Wedge8ModeMball(MballWidget w, XEvent * event, char **args, int nArgs)
741 {
742 mballCallbackStruct cb;
743
744 cb.reason = MBALL_WEDGE8;
745 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
746 }
747
748 static void
Wedge10ModeMball(MballWidget w,XEvent * event,char ** args,int nArgs)749 Wedge10ModeMball(MballWidget w, XEvent * event, char **args, int nArgs)
750 {
751 mballCallbackStruct cb;
752
753 cb.reason = MBALL_WEDGE10;
754 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
755 }
756
757 static void
Wedge12ModeMball(MballWidget w,XEvent * event,char ** args,int nArgs)758 Wedge12ModeMball(MballWidget w, XEvent * event, char **args, int nArgs)
759 {
760 mballCallbackStruct cb;
761
762 cb.reason = MBALL_WEDGE12;
763 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
764 }
765
766 static void
MoveMballCcw(MballWidget w,XEvent * event,char ** args,int nArgs)767 MoveMballCcw(MballWidget w, XEvent * event, char **args, int nArgs)
768 {
769 MoveMballInput(w, event->xbutton.x, event->xbutton.y, CCW,
770 (int) (event->xbutton.state & ControlMask));
771 }
772
773 static void
MoveMballTl(MballWidget w,XEvent * event,char ** args,int nArgs)774 MoveMballTl(MballWidget w, XEvent * event, char **args, int nArgs)
775 {
776 MoveMballInput(w, event->xbutton.x, event->xbutton.y, TL,
777 (int) (event->xkey.state & ControlMask));
778 }
779
780 static void
MoveMballTop(MballWidget w,XEvent * event,char ** args,int nArgs)781 MoveMballTop(MballWidget w, XEvent * event, char **args, int nArgs)
782 {
783 MoveMballInput(w, event->xbutton.x, event->xbutton.y, TOP,
784 (int) (event->xkey.state & ControlMask));
785 }
786
787 static void
MoveMballTr(MballWidget w,XEvent * event,char ** args,int nArgs)788 MoveMballTr(MballWidget w, XEvent * event, char **args, int nArgs)
789 {
790 MoveMballInput(w, event->xbutton.x, event->xbutton.y, TR,
791 (int) (event->xkey.state & ControlMask));
792 }
793
794 static void
MoveMballLeft(MballWidget w,XEvent * event,char ** args,int nArgs)795 MoveMballLeft(MballWidget w, XEvent * event, char **args, int nArgs)
796 {
797 MoveMballInput(w, event->xbutton.x, event->xbutton.y, LEFT,
798 (int) (event->xkey.state & ControlMask));
799 }
800
801 static void
MoveMballCw(MballWidget w,XEvent * event,char ** args,int nArgs)802 MoveMballCw(MballWidget w, XEvent * event, char **args, int nArgs)
803 {
804 MoveMballInput(w, event->xbutton.x, event->xbutton.y, CW,
805 (int) (event->xkey.state & ControlMask));
806 }
807
808 static void
MoveMballRight(MballWidget w,XEvent * event,char ** args,int nArgs)809 MoveMballRight(MballWidget w, XEvent * event, char **args, int nArgs)
810 {
811 MoveMballInput(w, event->xbutton.x, event->xbutton.y, RIGHT,
812 (int) (event->xkey.state & ControlMask));
813 }
814
815 static void
MoveMballBl(MballWidget w,XEvent * event,char ** args,int nArgs)816 MoveMballBl(MballWidget w, XEvent * event, char **args, int nArgs)
817 {
818 MoveMballInput(w, event->xbutton.x, event->xbutton.y, BL,
819 (int) (event->xkey.state & ControlMask));
820 }
821
822 static void
MoveMballBottom(MballWidget w,XEvent * event,char ** args,int nArgs)823 MoveMballBottom(MballWidget w, XEvent * event, char **args, int nArgs)
824 {
825 MoveMballInput(w, event->xbutton.x, event->xbutton.y, BOTTOM,
826 (int) (event->xkey.state & ControlMask));
827 }
828
829 static void
MoveMballBr(MballWidget w,XEvent * event,char ** args,int nArgs)830 MoveMballBr(MballWidget w, XEvent * event, char **args, int nArgs)
831 {
832 MoveMballInput(w, event->xbutton.x, event->xbutton.y, BR,
833 (int) (event->xkey.state & ControlMask));
834 }
835
836 static void
MoveMballInput(MballWidget w,int x,int y,int direction,int control)837 MoveMballInput(MballWidget w, int x, int y, int direction, int control)
838 {
839 int wedge, ring;
840
841 if (CheckSolved(w) && !w->mball.practice && !control) {
842 MoveNoWedges(w);
843 return;
844 }
845 if (!PositionWedges(w, x, y, &wedge, &ring, &direction))
846 return;
847 control = (control) ? 1 : 0;
848 MoveMball(w, wedge, ring, direction, control);
849 if (!control && CheckSolved(w)) {
850 mballCallbackStruct cb;
851
852 cb.reason = MBALL_SOLVED;
853 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
854 }
855 }
856
857 void
MoveMball(MballWidget w,int wedge,int ring,int direction,int control)858 MoveMball(MballWidget w, int wedge, int ring, int direction, int control)
859 {
860 mballCallbackStruct cb;
861
862 if (control)
863 MoveControlCb(w, wedge, direction);
864 else {
865 MoveWedges(w, wedge, ring, direction);
866 cb.reason = MBALL_MOVED;
867 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
868 }
869 PutMove(wedge, ring, direction, control);
870 }
871
872 static void
SetAllColors(MballWidget w,Boolean init)873 SetAllColors(MballWidget w, Boolean init)
874 {
875 XGCValues values;
876 XtGCMask valueMask;
877 int wedge;
878
879 valueMask = GCForeground | GCBackground;
880
881 if (w->mball.reverse) {
882 values.background = w->core.background_pixel;
883 values.foreground = w->mball.foreground;
884 } else {
885 values.foreground = w->core.background_pixel;
886 values.background = w->mball.foreground;
887 }
888 if (!init)
889 XtReleaseGC((Widget) w, w->mball.inverseGC);
890 w->mball.inverseGC = XtGetGC((Widget) w, valueMask, &values);
891 if (w->mball.reverse) {
892 values.background = w->mball.foreground;
893 values.foreground = w->core.background_pixel;
894 } else {
895 values.foreground = w->mball.foreground;
896 values.background = w->core.background_pixel;
897 }
898 if (!init)
899 XtReleaseGC((Widget) w, w->mball.puzzleGC);
900 w->mball.puzzleGC = XtGetGC((Widget) w, valueMask, &values);
901 if (w->mball.depth < 2 || w->mball.mono) {
902 if (w->mball.reverse) {
903 values.background = w->mball.foreground;
904 values.foreground = w->core.background_pixel;
905 } else {
906 values.foreground = w->mball.foreground;
907 values.background = w->core.background_pixel;
908 }
909 } else {
910 values.foreground = w->mball.borderColor;
911 values.background = w->core.background_pixel;
912 }
913 if (!init)
914 XtReleaseGC((Widget) w, w->mball.borderGC);
915 w->mball.borderGC = XtGetGC((Widget) w, valueMask, &values);
916 for (wedge = 0; wedge < MAXWEDGES; wedge++)
917 GetColor(w, wedge, init);
918 }
919
920 static void
GetColor(MballWidget w,int wedge,Boolean init)921 GetColor(MballWidget w, int wedge, Boolean init)
922 {
923 XGCValues values;
924 XtGCMask valueMask;
925 XColor colorCell, rgb;
926
927 valueMask = GCForeground | GCBackground;
928 if (w->mball.reverse) {
929 values.background = w->mball.foreground;
930 } else {
931 values.background = w->core.background_pixel;
932 }
933 if (w->mball.depth > 1 && !w->mball.mono) {
934 if (XAllocNamedColor(XtDisplay(w),
935 DefaultColormap(XtDisplay(w), XtWindow(w)),
936 w->mball.wedgeName[wedge], &colorCell, &rgb)) {
937 values.foreground = w->mball.wedgeColor[wedge] = colorCell.pixel;
938 if (!init)
939 XtReleaseGC((Widget) w, w->mball.wedgeGC[wedge]);
940 w->mball.wedgeGC[wedge] = XtGetGC((Widget) w, valueMask, &values);
941 return;
942 } else {
943 char buf[121];
944
945 (void) sprintf(buf, "Color name \"%s\" is not defined %d",
946 w->mball.wedgeName[wedge], wedge);
947 XtWarning(buf);
948 }
949 }
950 if (w->mball.reverse) {
951 values.background = w->mball.foreground;
952 values.foreground = w->core.background_pixel;
953 } else {
954 values.background = w->core.background_pixel;
955 values.foreground = w->mball.foreground;
956 }
957 if (!init)
958 XtReleaseGC((Widget) w, w->mball.wedgeGC[wedge]);
959 w->mball.wedgeGC[wedge] = XtGetGC((Widget) w, valueMask, &values);
960 }
961
962 static void
MoveControlCb(MballWidget w,int wedge,int direction)963 MoveControlCb(MballWidget w, int wedge, int direction)
964 {
965 mballCallbackStruct cb;
966 int ring;
967
968 if (direction > COORD)
969 for (ring = 0; ring < w->mball.rings; ring++) {
970 MoveWedges(w, wedge, ring, direction);
971 cb.reason = MBALL_CONTROL;
972 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
973 } else {
974 MoveWedges(w, 0, 0, direction);
975 cb.reason = MBALL_CONTROL;
976 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
977 MoveWedges(w, w->mball.wedges / 2, 0, direction);
978 cb.reason = MBALL_CONTROL;
979 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
980 }
981 }
982
983 static void
CheckWedges(MballWidget w)984 CheckWedges(MballWidget w)
985 {
986 if (w->mball.wedges < MINWEDGES || w->mball.wedges > MAXWEDGES ||
987 w->mball.wedges % 2) {
988 char buf[121];
989
990 (void) sprintf(buf,
991 "Number of wedges out of bounds, use even %d..%d", MINWEDGES, MAXWEDGES);
992 XtWarning(buf);
993 w->mball.wedges = DEFAULTWEDGES;
994 }
995 if (w->mball.rings < MINRINGS) {
996 char buf[121];
997
998 (void) sprintf(buf,
999 "Number of rings out of bounds, use %d..MAXINT", MINRINGS);
1000 XtWarning(buf);
1001 w->mball.rings = DEFAULTRINGS;
1002 }
1003 if (w->mball.base > 36) {
1004 /* 10 numbers + 26 letters (ASCII or EBCDIC) */
1005 XtWarning("Base must be less than or equal to 36");
1006 w->mball.base = 16; /* It has less digits for 12 wedges */
1007 } else if (w->mball.base <= 1) { /* Base 1 is rediculous :) */
1008 XtWarning("Base must be greater than 1");
1009 w->mball.base = 16; /* It has less digits for 12 wedges */
1010 }
1011 }
1012
1013 static void
ResetWedges(MballWidget w)1014 ResetWedges(MballWidget w)
1015 {
1016 int wedge, ring;
1017
1018 for (wedge = 0; wedge < MAXWEDGES; wedge++) {
1019 if (w->mball.mballLoc[wedge])
1020 (void) free((void *) w->mball.mballLoc[wedge]);
1021 if (!(w->mball.mballLoc[wedge] = (MballLoc *)
1022 malloc(sizeof (MballLoc) * w->mball.rings)))
1023 XtError("Not enough memory, exiting.");
1024 if (startLoc[wedge])
1025 (void) free((void *) startLoc[wedge]);
1026 if (!(startLoc[wedge] = (MballLoc *)
1027 malloc(sizeof (MballLoc) * w->mball.rings)))
1028 XtError("Not enough memory, exiting.");
1029 }
1030 for (wedge = 0; wedge < w->mball.wedges; wedge++)
1031 for (ring = 0; ring < w->mball.rings; ring++) {
1032 w->mball.mballLoc[wedge][ring].wedge = wedge;
1033 w->mball.mballLoc[wedge][ring].direction = DOWN;
1034 }
1035 FlushMoves(w);
1036 w->mball.started = False;
1037 }
1038
1039 static void
ResizeWedges(MballWidget w)1040 ResizeWedges(MballWidget w)
1041 {
1042 w->mball.mballLength = w->mball.wedgeLength / (2 * w->mball.wedges) -
1043 w->mball.delta - 1;
1044 w->mball.letterOffset.x = -2;
1045 w->mball.letterOffset.y = 4;
1046 w->mball.dr = w->mball.wedges;
1047 }
1048
1049 static Boolean
SelectWedges(MballWidget w,int x,int y,int * wedge,int * ring,int * view)1050 SelectWedges(MballWidget w, int x, int y, int *wedge, int *ring, int *view)
1051 {
1052 double angle, radius;
1053
1054 x -= w->mball.puzzleOffset.x;
1055 y -= w->mball.puzzleOffset.y;
1056 if (w->mball.vertical && y > w->mball.viewLength - 1) {
1057 y -= (w->mball.viewLength - 1);
1058 *view = DOWN;
1059 } else if (!w->mball.vertical && x > w->mball.viewLength - 1) {
1060 x -= (w->mball.viewLength - 1);
1061 *view = DOWN;
1062 } else
1063 *view = UP;
1064 x -= (w->mball.wedgeLength + 1) / 2;
1065 y -= (w->mball.wedgeLength + 1) / 2;
1066 radius = sqrt((double) x * x + y * y);
1067 if (y >= 0)
1068 angle = atan2((double) -x, (double) y) + M_PI;
1069 else if (x < 0)
1070 angle = 2 * M_PI - atan2((double) -x, (double) -y);
1071 else
1072 angle = -atan2((double) -x, (double) -y);
1073 *ring = (int) (radius * (double) w->mball.rings /
1074 ((double) w->mball.wedgeLength));
1075 *wedge = (int) (angle * (double) w->mball.wedges / (2.0 * M_PI));
1076 if (*view == DOWN) {
1077 if (w->mball.vertical)
1078 *wedge = (3 * w->mball.wedges / 2 - 1 - *wedge) % w->mball.wedges;
1079 else
1080 *wedge = (w->mball.wedges - 1 - *wedge) % w->mball.wedges;
1081 *ring = w->mball.rings - 1 - *ring;
1082 }
1083 if (radius > w->mball.wedgeLength / 2 + w->mball.delta)
1084 return False;
1085 return True;
1086 }
1087
1088 static Boolean
PositionWedges(MballWidget w,int x,int y,int * wedge,int * ring,int * direction)1089 PositionWedges(MballWidget w, int x, int y, int *wedge, int *ring, int *direction)
1090 {
1091 int view, inside;
1092
1093 inside = SelectWedges(w, x, y, wedge, ring, &view);
1094 if ((*direction == CW || *direction == CCW) && !inside)
1095 return False;
1096 if (view == DOWN) {
1097 if (*direction == CCW)
1098 *direction = CW;
1099 else if (*direction == CW)
1100 *direction = CCW;
1101 else if (*direction < COORD)
1102 *direction = (COORD - *direction) % COORD;
1103 }
1104 if (w->mball.wedges % 4 && (*direction == LEFT || *direction == RIGHT))
1105 return False;
1106 if (w->mball.wedges <= 4 && *direction % 2 && *direction < COORD)
1107 return False;
1108 return True;
1109 }
1110
1111 static void
MoveNoWedges(MballWidget w)1112 MoveNoWedges(MballWidget w)
1113 {
1114 mballCallbackStruct cb;
1115
1116 cb.reason = MBALL_ILLEGAL;
1117 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1118 }
1119
1120 static void
PracticeWedges(MballWidget w)1121 PracticeWedges(MballWidget w)
1122 {
1123 mballCallbackStruct cb;
1124
1125 cb.reason = MBALL_PRACTICE;
1126 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1127 }
1128
1129 static void
RandomizeWedges(MballWidget w)1130 RandomizeWedges(MballWidget w)
1131 {
1132 mballCallbackStruct cb;
1133 int randomDirection, wedge, ring;
1134 int big = w->mball.wedges * (w->mball.rings + 1) + NRAND(2);
1135
1136 if (big > 100)
1137 big = 100;
1138 if (w->mball.practice)
1139 PracticeWedges(w);
1140 cb.reason = MBALL_RESET;
1141 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1142
1143 #ifdef DEBUG
1144 big = 3;
1145 #endif
1146
1147 while (big--) {
1148 wedge = NRAND(w->mball.wedges);
1149 ring = NRAND(w->mball.rings);
1150 do
1151 randomDirection = NRAND(2 * COORD);
1152 while (randomDirection < COORD &&
1153 mapDirToWedge[(w->mball.wedges - MINWEDGES) / 2][randomDirection] ==
1154 CUTS);
1155 if (randomDirection >= COORD) {
1156 if (randomDirection - COORD < CUTS)
1157 randomDirection = CW;
1158 else
1159 randomDirection = CCW;
1160 }
1161 MoveMball(w, wedge, ring, randomDirection, FALSE);
1162 }
1163 FlushMoves(w);
1164 cb.reason = MBALL_RANDOMIZE;
1165 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1166 if (CheckSolved(w)) {
1167 cb.reason = MBALL_SOLVED;
1168 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1169 }
1170 }
1171
1172 static void
SwapWedges(MballWidget w,int wedge1,int wedge2)1173 SwapWedges(MballWidget w, int wedge1, int wedge2)
1174 {
1175 MballLoc temp;
1176 int ring;
1177
1178 if (wedge1 == wedge2) {
1179 for (ring = 0; ring < w->mball.rings / 2; ring++) {
1180 temp = w->mball.mballLoc[wedge1][ring];
1181 w->mball.mballLoc[wedge1][ring] =
1182 w->mball.mballLoc[wedge1][w->mball.rings - 1 - ring];
1183 w->mball.mballLoc[wedge1][w->mball.rings - 1 - ring] = temp;
1184 }
1185 for (ring = 0; ring < w->mball.rings; ring++)
1186 w->mball.mballLoc[wedge1][ring].direction =
1187 !w->mball.mballLoc[wedge1][ring].direction;
1188 DrawWedge(w, wedge1);
1189 } else {
1190 for (ring = 0; ring < w->mball.rings; ring++) {
1191 temp = w->mball.mballLoc[wedge1][ring];
1192 w->mball.mballLoc[wedge1][ring] =
1193 w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring];
1194 w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring] = temp;
1195 w->mball.mballLoc[wedge1][ring].direction =
1196 !w->mball.mballLoc[wedge1][ring].direction;
1197 w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring].direction =
1198 !w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring].direction;
1199 }
1200 DrawWedge(w, wedge1);
1201 DrawWedge(w, wedge2);
1202 }
1203 }
1204
1205 static void
MoveWedges(MballWidget w,int wedge,int ring,int direction)1206 MoveWedges(MballWidget w, int wedge, int ring, int direction)
1207 {
1208 int i;
1209
1210 if (direction == CW || direction == CCW) { /* rotate ring */
1211 int newI;
1212 MballLoc temp1, temp2;
1213
1214 for (i = 0; i < w->mball.wedges; i++) {
1215 newI = (direction == CW) ? i : w->mball.wedges - 1 - i;
1216 if (newI == ((direction == CW) ? 0 : w->mball.wedges - 1)) {
1217 temp1 = w->mball.mballLoc[newI][ring];
1218 w->mball.mballLoc[newI][ring] = w->mball.mballLoc
1219 [((direction == CW) ? w->mball.wedges - 1 : 0)][ring];
1220 } else {
1221 temp2 = temp1;
1222 temp1 = w->mball.mballLoc[newI][ring];
1223 w->mball.mballLoc[newI][ring] = temp2;
1224 }
1225 DrawSector(w, newI, ring, FALSE);
1226 }
1227 } else { /* flip */
1228 int sphereDir = mapDirToWedge[(w->mball.wedges - MINWEDGES) / 2][direction];
1229 int offset = w->mball.wedges / 2;
1230 int wedge1, wedge2;
1231
1232 for (i = 0; i < w->mball.wedges / 2; i++)
1233 if (wedge == i + sphereDir)
1234 offset = 0;
1235 for (i = 0; i < (w->mball.wedges + 2) / 4; i++) {
1236 wedge1 = (i + sphereDir + offset) % w->mball.wedges;
1237 wedge2 = (w->mball.wedges / 2 - 1 - i + sphereDir + offset) %
1238 w->mball.wedges;
1239 SwapWedges(w, wedge1, wedge2);
1240 }
1241 }
1242 }
1243
1244 static void
DrawFrame(MballWidget w,GC gc)1245 DrawFrame(MballWidget w, GC gc)
1246 {
1247 int startx, starty, lengthx, lengthy;
1248
1249 startx = 1 + w->mball.puzzleOffset.x;
1250 starty = 1 + w->mball.puzzleOffset.y;
1251 lengthx = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.x;
1252 lengthy = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.y;
1253 DrawRadar(w, gc, startx, starty, lengthx - startx, lengthy - starty);
1254 if (w->mball.vertical) {
1255 XDrawLine(XtDisplay(w), XtWindow(w), gc, 0, lengthy + 1,
1256 (int) w->core.width - 1, lengthy + 1);
1257 DrawRadar(w, gc, startx, lengthy + 3, lengthx - startx, lengthy - starty);
1258 } else {
1259 XDrawLine(XtDisplay(w), XtWindow(w), gc, lengthx + 1, 0,
1260 lengthx + 1, (int) w->core.height - 1);
1261 DrawRadar(w, gc, lengthx + 3, starty, lengthx - startx, lengthy - starty);
1262 }
1263 }
1264
1265 void
DrawAllWedges(MballWidget w)1266 DrawAllWedges(MballWidget w)
1267 {
1268 int wedge;
1269
1270 for (wedge = 0; wedge < w->mball.wedges; wedge++)
1271 DrawWedge(w, wedge);
1272 }
1273
1274 static void
DrawWedge(MballWidget w,int wedge)1275 DrawWedge(MballWidget w, int wedge)
1276 {
1277 int ring;
1278
1279 for (ring = 0; ring < w->mball.rings; ring++)
1280 DrawSector(w, wedge, ring, FALSE);
1281 }
1282
1283 static void
LetterPosition(MballWidget w,int wedge,int ring,int lengthx,int lengthy,int * dx,int * dy)1284 LetterPosition(MballWidget w, int wedge, int ring, int lengthx, int lengthy, int *dx, int *dy)
1285 {
1286 double angle, radius;
1287
1288 angle = (double) (2 * wedge + 1) * M_PI / w->mball.wedges;
1289 if (w->mball.rings % 2 && ring == w->mball.rings / 2)
1290 radius = ((double) 4.0 * ring + 1.0) / ((double) 4.0 * w->mball.rings);
1291 else
1292 radius = ((double) 2.0 * ring + 1.0) / ((double) 2.0 * w->mball.rings);
1293 *dx = lengthx / 2 + (int) ((double) lengthx * radius * cos(angle - M_PI / 2));
1294 *dy = lengthy / 2 + (int) ((double) lengthy * radius * sin(angle - M_PI / 2));
1295 }
1296
1297 static void
OffsetSect(MballWidget w,int wedge,int * dx,int * dy)1298 OffsetSect(MballWidget w, int wedge, int *dx, int *dy)
1299 {
1300 double angle = (double) (2 * wedge + 1) * M_PI / w->mball.wedges;
1301
1302 *dx = (int) ((double) w->mball.dr * cos(angle - M_PI / 2));
1303 *dy = (int) ((double) w->mball.dr * sin(angle - M_PI / 2));
1304 }
1305
1306 static void
DrawSector(MballWidget w,int wedge,int ring,int offset)1307 DrawSector(MballWidget w, int wedge, int ring, int offset)
1308 {
1309 GC wedgeGC, borderGC;
1310 int startx, starty, lengthx, lengthy, i, l;
1311
1312 startx = 1 + w->mball.puzzleOffset.x;
1313 starty = 1 + w->mball.puzzleOffset.y;
1314 lengthx = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.x;
1315 lengthy = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.y;
1316 if (offset) {
1317 borderGC = w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge];
1318 if (w->mball.depth < 2 || w->mball.mono) {
1319 wedgeGC = w->mball.inverseGC;
1320 } else {
1321 wedgeGC = w->mball.borderGC;
1322 }
1323 } else {
1324 wedgeGC = w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge];
1325 borderGC = w->mball.borderGC;
1326 }
1327 /* if the number of rings is odd
1328 * the ring can straddle both hemispheres */
1329 if (ring < (w->mball.rings + 1) / 2)
1330 DrawSect(w, wedgeGC, borderGC, ring, wedge,
1331 startx, starty, lengthx - startx, lengthy - starty);
1332 if (ring + 1 > w->mball.rings / 2) {
1333 if (w->mball.vertical)
1334 DrawSect(w, wedgeGC, borderGC,
1335 w->mball.rings - 1 - ring,
1336 (3 * w->mball.wedges / 2 - 1 - wedge) % w->mball.wedges,
1337 startx, lengthy + 3, lengthx - startx, lengthy - starty);
1338 else
1339 DrawSect(w, wedgeGC, borderGC,
1340 w->mball.rings - 1 - ring,
1341 w->mball.wedges - 1 - wedge,
1342 lengthx + 3, starty, lengthx - startx, lengthy - starty);
1343 }
1344 if (w->mball.depth < 2 || w->mball.mono) {
1345 int letterX, letterY;
1346 char buf[3];
1347
1348 if (offset) {
1349 borderGC = w->mball.borderGC;
1350 } else {
1351 borderGC = w->mball.inverseGC;
1352 }
1353 if (ring < (w->mball.rings + 1) / 2) {
1354 LetterPosition(w, wedge, ring, lengthx - startx, lengthy - starty,
1355 &letterX, &letterY);
1356 letterX += startx + w->mball.letterOffset.x;
1357 letterY += starty + w->mball.letterOffset.y;
1358 if (w->mball.orient && !w->mball.mballLoc[wedge][ring].direction) {
1359 int last;
1360
1361 l = w->mball.mballLoc[wedge][ring].wedge;
1362 last = int2String(buf, l, w->mball.base, False);
1363 buf[last] = w->mball.wedgeName[l][0];
1364 buf[last + 1] = '\0';
1365 i = 0;
1366 if (l == 0)
1367 l = 1;
1368 l *= w->mball.base;
1369 while (l >= 1) {
1370 l /= w->mball.base;
1371 letterX += w->mball.letterOffset.x;
1372 i++;
1373 }
1374 } else {
1375 buf[0] = w->mball.wedgeName[w->mball.mballLoc[wedge][ring].wedge][0];
1376 buf[1] = '\0';
1377 i = 1;
1378 }
1379 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
1380 letterX, letterY, buf, i);
1381 }
1382 if (ring + 1 > w->mball.rings / 2) {
1383 if (w->mball.vertical) {
1384 LetterPosition(w,
1385 (3 * w->mball.wedges / 2 - 1 - wedge) % w->mball.wedges,
1386 w->mball.rings - 1 - ring,
1387 lengthx - startx, lengthy - starty,
1388 &letterX, &letterY);
1389 letterX += startx + w->mball.letterOffset.x;
1390 letterY += lengthy + 3 + w->mball.letterOffset.y;
1391 } else {
1392 LetterPosition(w,
1393 w->mball.wedges - 1 - wedge,
1394 w->mball.rings - 1 - ring,
1395 lengthx - startx, lengthy - starty,
1396 &letterX, &letterY);
1397 letterX += lengthx + 3 + w->mball.letterOffset.x;
1398 letterY += starty + w->mball.letterOffset.y;
1399 }
1400 if (w->mball.orient && w->mball.mballLoc[wedge][ring].direction) {
1401 int last;
1402
1403 l = w->mball.mballLoc[wedge][ring].wedge;
1404 last = int2String(buf, l, w->mball.base, False);
1405 buf[last] = w->mball.wedgeName[l][0];
1406 buf[last + 1] = '\0';
1407 i = 0;
1408 if (l == 0)
1409 l = 1;
1410 l *= w->mball.base;
1411 while (l >= 1) {
1412 l /= w->mball.base;
1413 letterX += w->mball.letterOffset.x;
1414 i++;
1415 }
1416 } else {
1417 buf[0] = w->mball.wedgeName[w->mball.mballLoc[wedge][ring].wedge][0];
1418 buf[1] = '\0';
1419 i = 1;
1420 }
1421 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
1422 letterX, letterY, buf, i);
1423 }
1424 } else if (w->mball.orient) {
1425 int letterX, letterY;
1426 char buf[2];
1427
1428 if (ring < (w->mball.rings + 1) / 2 &&
1429 !w->mball.mballLoc[wedge][ring].direction) {
1430 LetterPosition(w, wedge, ring, lengthx - startx, lengthy - starty,
1431 &letterX, &letterY);
1432 letterX += startx + w->mball.letterOffset.x;
1433 letterY += starty + w->mball.letterOffset.y;
1434 l = w->mball.mballLoc[wedge][ring].wedge;
1435 (void) int2String(buf, l, w->mball.base, True);
1436 i = 0;
1437 if (l == 0)
1438 l = 1;
1439 while (l >= 1) {
1440 l /= w->mball.base;
1441 letterX += w->mball.letterOffset.x;
1442 i++;
1443 }
1444 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
1445 letterX, letterY, buf, i);
1446 }
1447 if (ring + 1 > w->mball.rings / 2 &&
1448 w->mball.mballLoc[wedge][ring].direction) {
1449 if (w->mball.vertical) {
1450 LetterPosition(w,
1451 (3 * w->mball.wedges / 2 - 1 - wedge) % w->mball.wedges,
1452 w->mball.rings - 1 - ring,
1453 lengthx - startx, lengthy - starty,
1454 &letterX, &letterY);
1455 letterX += startx + w->mball.letterOffset.x;
1456 letterY += lengthy + 3 + w->mball.letterOffset.y;
1457 } else {
1458 LetterPosition(w,
1459 w->mball.wedges - 1 - wedge,
1460 w->mball.rings - 1 - ring,
1461 lengthx - startx, lengthy - starty,
1462 &letterX, &letterY);
1463 letterX += lengthx + 3 + w->mball.letterOffset.x;
1464 letterY += starty + w->mball.letterOffset.y;
1465 }
1466 l = w->mball.mballLoc[wedge][ring].wedge;
1467 (void) int2String(buf, l, w->mball.base, True);
1468 i = 0;
1469 if (l == 0)
1470 l = 1;
1471 while (l >= 1) {
1472 l /= w->mball.base;
1473 letterX += w->mball.letterOffset.x;
1474 i++;
1475 }
1476 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
1477 letterX, letterY, buf, i);
1478 }
1479 }
1480 }
1481
1482 static void
DrawRadar(MballWidget w,GC gc,int startx,int starty,int lengthx,int lengthy)1483 DrawRadar(MballWidget w, GC gc, int startx, int starty, int lengthx, int lengthy)
1484 {
1485 int r, i;
1486 double angle, increment;
1487
1488 XDrawArc(XtDisplay(w), XtWindow(w), gc, startx, starty,
1489 lengthx, lengthy, 0, CIRCLE);
1490 if (w->mball.rings % 2)
1491 for (r = 1; r < w->mball.rings / 2 + 1; r++)
1492 XDrawArc(XtDisplay(w), XtWindow(w), gc,
1493 startx - lengthx / (2 * w->mball.rings) +
1494 (w->mball.rings / 2 + 1 - r) * lengthx / w->mball.rings,
1495 starty - lengthy / (2 * w->mball.rings) +
1496 (w->mball.rings / 2 + 1 - r) * lengthy / w->mball.rings,
1497 r * 2 * lengthx / w->mball.rings,
1498 r * 2 * lengthy / w->mball.rings,
1499 0, CIRCLE);
1500 else
1501 for (r = 1; r < w->mball.rings / 2; r++)
1502 XDrawArc(XtDisplay(w), XtWindow(w), gc,
1503 startx + (w->mball.rings / 2 - r) * lengthx / w->mball.rings,
1504 starty + (w->mball.rings / 2 - r) * lengthy / w->mball.rings,
1505 r * 2 * lengthx / w->mball.rings,
1506 r * 2 * lengthy / w->mball.rings,
1507 0, CIRCLE);
1508 increment = RADIANS(NUM_DEGREES) / (double) w->mball.wedges;
1509 angle = RADIANS(RT_ANG);
1510 for (i = 0; i < w->mball.wedges; i++) {
1511 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1512 startx + lengthx / 2, starty + lengthy / 2,
1513 startx + lengthx / 2 + (int) ((double) lengthx * cos(angle) / 2.0),
1514 starty + lengthy / 2 + (int) ((double) lengthy * sin(angle) / 2.0));
1515 angle += increment;
1516 }
1517 }
1518
1519 static void
DrawSect(MballWidget w,GC wedgeGC,GC borderGC,int r,int wedge,int startx,int starty,int lengthx,int lengthy)1520 DrawSect(MballWidget w, GC wedgeGC, GC borderGC, int r, int wedge, int startx, int starty, int lengthx, int lengthy)
1521 {
1522 int dx, dy;
1523
1524 OffsetSect(w, wedge, &dx, &dy);
1525 if (w->mball.rings % 2) {
1526 if (r == w->mball.rings / 2) {
1527 XFillSector(XtDisplay(w), XtWindow(w), wedgeGC,
1528 startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
1529 r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1530 r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1531 (r + 1) * 2 * lengthx / (w->mball.rings + 1) - 2 * w->mball.dr,
1532 (r + 1) * 2 * lengthy / (w->mball.rings + 1) - 2 * w->mball.dr,
1533 CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
1534 -CIRCLE / w->mball.wedges);
1535 XDrawSector(XtDisplay(w), XtWindow(w), borderGC,
1536 startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
1537 r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1538 r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1539 (r + 1) * 2 * lengthx / (w->mball.rings + 1) - 2 * w->mball.dr,
1540 (r + 1) * 2 * lengthy / (w->mball.rings + 1) - 2 * w->mball.dr,
1541 CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
1542 -CIRCLE / w->mball.wedges);
1543 } else {
1544 XFillSector(XtDisplay(w), XtWindow(w), wedgeGC,
1545 startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
1546 r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1547 r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1548 (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1549 (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1550 CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
1551 -CIRCLE / w->mball.wedges);
1552 XDrawSector(XtDisplay(w), XtWindow(w), borderGC,
1553 startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
1554 r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1555 r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1556 (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1557 (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1558 CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
1559 -CIRCLE / w->mball.wedges);
1560 }
1561 } else {
1562 XFillSector(XtDisplay(w), XtWindow(w), wedgeGC,
1563 startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
1564 r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1565 r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1566 (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1567 (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1568 CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
1569 -CIRCLE / w->mball.wedges);
1570 XDrawSector(XtDisplay(w), XtWindow(w), borderGC,
1571 startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
1572 r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1573 r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1574 (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
1575 (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
1576 CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
1577 -CIRCLE / w->mball.wedges);
1578 }
1579 }
1580
1581 static void
XFillSector(Display * display,Drawable drawable,GC gc,int xo,int yo,int width1,int height1,int width2,int height2,int angle1,int angle2)1582 XFillSector(Display * display, Drawable drawable, GC gc, int xo, int yo, int width1, int height1, int width2, int height2, int angle1, int angle2)
1583 {
1584 int d, r1 = MIN(width1, height1) / 2, r2 = MIN(width2, height2) / 2;
1585 int w = MAX(r2 - r1 - 8, 1);
1586
1587 if (r1 > r2) {
1588 d = r1;
1589 r1 = r2;
1590 r2 = d;
1591 }
1592 if (r1 < 0)
1593 r1 = -3;
1594 d = MAX(r1 + r2 + 2, 2);
1595 XSetLineAttributes(display, gc, w, LineSolid, CapNotLast, JoinRound);
1596 XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
1597 angle1, angle2);
1598 XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinRound);
1599 }
1600
1601 static void
XDrawSector(Display * display,Drawable drawable,GC gc,int xo,int yo,int width1,int height1,int width2,int height2,int angle1,int angle2)1602 XDrawSector(Display * display, Drawable drawable, GC gc, int xo, int yo, int width1, int height1, int width2, int height2, int angle1, int angle2)
1603 {
1604 int d, r1 = MIN(width1, height1) / 2, r2 = MIN(width2, height2) / 2;
1605
1606 /*double ang, x, y; */
1607
1608 if (r1 > r2) {
1609 d = r1;
1610 r1 = r2;
1611 r2 = d;
1612 }
1613 if (r1 < 0)
1614 r1 = -3;
1615 d = MAX(2 * (r1 + 3), 1);
1616 XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
1617 angle1, angle2);
1618 d = MAX(2 * (r2 - 1), 3);
1619 XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
1620 angle1, angle2);
1621
1622 /*ang = RADIANS((double) angle1 / MULT);
1623 x = cos(ang);
1624 y = sin(ang);
1625 XDrawLine(display, drawable, gc,
1626 (int) ((double) r1 * x) + xo, (int) ((double) r1 * y) + yo,
1627 (int) ((double) r2 * x) + xo, (int) ((double) r2 * y) + yo);
1628 ang = RADIANS((double) angle2 / MULT);
1629 x = cos(ang);
1630 y = sin(ang);
1631 XDrawLine(display, drawable, gc,
1632 (int) ((double) r1 * x) + xo, (int) ((double) r1 * y) + yo,
1633 (int) ((double) r2 * x) + xo, (int) ((double) r2 * y) + yo); */
1634 }
1635
1636 #if 0
1637 static void
1638 XFillSector(display, drawable, gc,
1639 xo, yo, width1, height1, width2, height2, angle1, angle2)
1640 Display *display;
1641 Drawable drawable;
1642 GC gc;
1643 int xo, yo;
1644 int width1, height1, width2, height2;
1645 int angle1, angle2;
1646 {
1647 int d, r1 = MIN(width1, height1) / 2, r2 = MIN(width2, height2) / 2;
1648
1649 if (r1 > r2) {
1650 d = r1;
1651 r1 = r2;
1652 r2 = d;
1653 }
1654 if (r1 < 0)
1655 r1 = -3;
1656 for (d = 2 * (r1 + 3); d < 2 * (r2 - 1); d++)
1657 XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
1658 angle1, angle2);
1659 }
1660 #endif
1661
1662 static int
int2String(char * buf,int number,int base,Boolean capital)1663 int2String(char *buf, int number, int base, Boolean capital)
1664 {
1665 int digit, mult = base, last, position;
1666 int a, i, j, s, r;
1667
1668 if (capital) {
1669 a = 'A', i = 'I', j = 'J', s = 'S', r = 'R';
1670 } else {
1671 a = 'a', i = 'i', j = 'j', s = 's', r = 'r';
1672 }
1673 if (number < 0) {
1674 (void) printf("number %d < 0\n", number);
1675 return 0;
1676 }
1677 last = 1;
1678 while (number >= mult) {
1679 last++;
1680 mult *= base;
1681 }
1682 for (position = 0; position < last; position++) {
1683 mult /= base;
1684 digit = number / mult;
1685 number -= digit * mult;
1686 buf[position] = digit + '0';
1687 if (buf[position] > '9') { /* ASCII */
1688 buf[position] += (a - '9' - 1);
1689 } else if (buf[position] < '0') { /* EBCDIC */
1690 buf[position] += (a - '9' - 1);
1691 if (buf[position] > i)
1692 buf[position] += (j - i - 1);
1693 if (buf[position] > r)
1694 buf[position] += (s - r - 1);
1695 }
1696 }
1697 buf[last] = '\0';
1698 return last;
1699 }
1700 Boolean
CheckSolved(MballWidget w)1701 CheckSolved(MballWidget w)
1702 {
1703 int wedge, ring;
1704 MballLoc test;
1705
1706 if (w->mball.orient)
1707 for (wedge = 0; wedge < w->mball.wedges; wedge++) {
1708 if (wedge == 0) {
1709 test.wedge = w->mball.mballLoc[wedge][0].wedge;
1710 test.direction = w->mball.mballLoc[wedge][0].direction;
1711 }
1712 for (ring = 0; ring < w->mball.rings; ring++) {
1713 if (test.direction != w->mball.mballLoc[wedge][ring].direction)
1714 return False;
1715 if (test.direction) {
1716 if ((w->mball.wedges - w->mball.mballLoc[wedge][ring].wedge +
1717 test.wedge) % w->mball.wedges != wedge)
1718 return False;
1719 } else {
1720 if ((w->mball.wedges + w->mball.mballLoc[wedge][ring].wedge -
1721 test.wedge) % w->mball.wedges != wedge)
1722 return False;
1723 }
1724 }
1725 } else
1726 for (wedge = 0; wedge < w->mball.wedges; wedge++)
1727 for (ring = 0; ring < w->mball.rings; ring++)
1728 if (ring == 0) {
1729 test.wedge = w->mball.mballLoc[wedge][ring].wedge;
1730 test.direction = w->mball.mballLoc[wedge][ring].direction;
1731 } else if (test.wedge != w->mball.mballLoc[wedge][ring].wedge)
1732 return False;
1733 return True;
1734 }
1735
1736 #ifdef DEBUG
1737
1738 static void
PrintMball(MballWidget w)1739 PrintMball(MballWidget w)
1740 {
1741 int wedge, ring;
1742
1743 for (wedge = 0; wedge < w->mball.wedges; wedge++) {
1744 for (ring = 0; ring < w->mball.rings; ring++) {
1745 (void) printf("%d %d ", w->mball.mballLoc[wedge][ring].wedge,
1746 w->mball.mballLoc[wedge][ring].direction);
1747 }
1748 (void) printf("\n");
1749 }
1750 (void) printf("\n");
1751 }
1752
1753 #endif
1754