1 /*-
2 # X-BASED HEXAGONS
3 #
4 # Hexagons.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 Hexagons */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef VMS
31 #include <unixlib.h>
32 #else
33 #if HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #endif
37 #include <X11/IntrinsicP.h>
38 #include <X11/Intrinsic.h>
39 #include <X11/StringDefs.h>
40 #include <X11/CoreP.h>
41 #include "HexagonsP.h"
42
43 #ifndef DATAFILE
44 #define DATAFILE "/usr/games/lib/hexagons.data"
45 #endif
46
47 static void InitializeHexagons(Widget request, Widget renew);
48 static void ExposeHexagons(Widget renew, XEvent * event, Region region);
49 static void ResizeHexagons(HexagonsWidget w);
50 static void DestroyHexagons(Widget old);
51 static Boolean SetValuesHexagons(Widget current, Widget request, Widget renew);
52 static void QuitHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
53 static void MoveHexagonsTl(HexagonsWidget w, XEvent * event, char **args, int nArgs);
54 static void MoveHexagonsTr(HexagonsWidget w, XEvent * event, char **args, int nArgs);
55 static void MoveHexagonsLeft(HexagonsWidget w, XEvent * event, char **args, int nArgs);
56 static void MoveHexagonsRight(HexagonsWidget w, XEvent * event, char **args, int nArgs);
57 static void MoveHexagonsBl(HexagonsWidget w, XEvent * event, char **args, int nArgs);
58 static void MoveHexagonsBr(HexagonsWidget w, XEvent * event, char **args, int nArgs);
59 static void SelectHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
60 static void ReleaseHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
61 static void RandomizeHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
62 static void RandomizeHexagonsMaybe(HexagonsWidget w, XEvent * event, char **args, int nArgs);
63 static void GetHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
64 static void WriteHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
65 static void UndoHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
66 static void SolveHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
67 static void IncrementHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
68 static void DecrementHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
69 static void CornerHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs);
70 static int MoveHexagons(HexagonsWidget w, int direction);
71
72 static int PositionToTile(HexagonsWidget w, int x, int y, int *row);
73 static int MovableCornerTile(HexagonsWidget w);
74 static int MovableNoCornTile(HexagonsWidget w);
75 static void SelectCornerTiles(HexagonsWidget w, int space);
76 static void SelectNoCornTiles(HexagonsWidget w);
77 static void SetAllColors(HexagonsWidget w, Boolean init);
78 static void CheckTiles(HexagonsWidget w);
79 static void ResetTiles(HexagonsWidget w);
80 static void ResizeTiles(HexagonsWidget w);
81 static int MovableCornerTiles(HexagonsWidget w, int direction, int *position, int *posRow, int *space);
82 static void MoveNoTiles(HexagonsWidget w);
83 static int MoveTilesDir(HexagonsWidget w, int direction);
84 static int MoveCornerTilesDir(HexagonsWidget w, int direction);
85 static int MoveNoCornTilesDir(HexagonsWidget w, int direction);
86 static void RandomizeTiles(HexagonsWidget w);
87 static void MoveCornerTiles(HexagonsWidget w, int from, int posRow, int space);
88 static void MoveNoCornTiles(HexagonsWidget w, int from, int posRow);
89 static int ExchangeTiles(HexagonsWidget w, int pos1, int pos2);
90
91 #ifdef DEBUG
92 static int WithinFrame(HexagonsWidget w, int x, int y, int dx, int dy);
93
94 #endif
95 static int NextToWall(HexagonsWidget w, int pos, int posRow, int spaceType);
96 static int TileNextToSpace(HexagonsWidget w, int rowType, int direction);
97 static int FindTileTriangle(HexagonsWidget w, int pI, int pJ, int pK, int rI, int rJ, int rK);
98 static int FindDir(HexagonsWidget w, int posTile, int posSpace, int rowTile, int rowSpace);
99 static int FindSpaceType(HexagonsWidget w, int pos1, int pos2, int row1, int row2);
100 static void FindMovableTile(HexagonsWidget w, int pos, int posRow, int spaceType, int side, int *tilePos, int *tileRow);
101 static void DrawFrame(HexagonsWidget w, GC gc);
102 static void DrawTile(HexagonsWidget w, int pos, Boolean blank, Boolean erase, int offset);
103
104 #ifdef DEBUG
105 static int PositionInRow();
106
107 #endif
108 static int PositionFromRow(HexagonsWidget w, int rowPosition, int posRow);
109 static int Sqrt(int i);
110 static int int2String(char *buf, int number, int base);
111 static void swap(int *a, int *b);
112
113 static char defaultTranslationsHexagons[] =
114 "<KeyPress>q: Quit()\n\
115 Ctrl<KeyPress>C: Quit()\n\
116 <KeyPress>Home: MoveTl()\n\
117 <KeyPress>KP_7: MoveTl()\n\
118 <KeyPress>R7: MoveTl()\n\
119 <KeyPress>Prior: MoveTr()\n\
120 <KeyPress>KP_9: MoveTr()\n\
121 <KeyPress>R9: MoveTr()\n\
122 <KeyPress>Left: MoveLeft()\n\
123 <KeyPress>KP_4: MoveLeft()\n\
124 <KeyPress>R10: MoveLeft()\n\
125 <KeyPress>Right: MoveRight()\n\
126 <KeyPress>KP_6: MoveRight()\n\
127 <KeyPress>R12: MoveRight()\n\
128 <KeyPress>End: MoveBl()\n\
129 <KeyPress>KP_1: MoveBl()\n\
130 <KeyPress>R13: MoveBl()\n\
131 <KeyPress>Next: MoveBr()\n\
132 <KeyPress>KP_3: MoveBr()\n\
133 <KeyPress>R15: MoveBr()\n\
134 <Btn1Down>: Select()\n\
135 <Btn1Up>: Release()\n\
136 <KeyPress>r: Randomize()\n\
137 <Btn3Down>(2+): Randomize()\n\
138 <Btn3Down>: RandomizeMaybe()\n\
139 <KeyPress>g: Get()\n\
140 <KeyPress>w: Write()\n\
141 <KeyPress>u: Undo()\n\
142 <KeyPress>s: Solve()\n\
143 <KeyPress>i: Increment()\n\
144 <KeyPress>d: Decrement()\n\
145 <KeyPress>c: Corner()";
146
147 static XtActionsRec actionsListHexagons[] =
148 {
149 {"Quit", (XtActionProc) QuitHexagons},
150 {"MoveTl", (XtActionProc) MoveHexagonsTl},
151 {"MoveTr", (XtActionProc) MoveHexagonsTr},
152 {"MoveLeft", (XtActionProc) MoveHexagonsLeft},
153 {"MoveRight", (XtActionProc) MoveHexagonsRight},
154 {"MoveBl", (XtActionProc) MoveHexagonsBl},
155 {"MoveBr", (XtActionProc) MoveHexagonsBr},
156 {"Select", (XtActionProc) SelectHexagons},
157 {"Release", (XtActionProc) ReleaseHexagons},
158 {"Randomize", (XtActionProc) RandomizeHexagons},
159 {"RandomizeMaybe", (XtActionProc) RandomizeHexagonsMaybe},
160 {"Get", (XtActionProc) GetHexagons},
161 {"Write", (XtActionProc) WriteHexagons},
162 {"Undo", (XtActionProc) UndoHexagons},
163 {"Solve", (XtActionProc) SolveHexagons},
164 {"Increment", (XtActionProc) IncrementHexagons},
165 {"Decrement", (XtActionProc) DecrementHexagons},
166 {"Corner", (XtActionProc) CornerHexagons}
167 };
168
169 static XtResource resourcesHexagons[] =
170 {
171 {XtNuserName, XtCUserName, XtRString, sizeof (String),
172 XtOffset(HexagonsWidget, hexagons.username), XtRString, "nobody"},
173 {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
174 XtOffset(HexagonsWidget, hexagons.foreground), XtRString, XtDefaultForeground},
175 {XtNtileColor, XtCColor, XtRPixel, sizeof (Pixel),
176 XtOffset(HexagonsWidget, hexagons.tileColor), XtRString, XtDefaultForeground},
177 {XtNtileBorder, XtCColor, XtRPixel, sizeof (Pixel),
178 XtOffset(HexagonsWidget, hexagons.borderColor), XtRString, XtDefaultBackground},
179 {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
180 XtOffset(HexagonsWidget, core.width), XtRString, "259"},
181 {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
182 XtOffset(HexagonsWidget, core.height), XtRString, "200"},
183 {XtNsize, XtCSize, XtRInt, sizeof (int),
184 XtOffset(HexagonsWidget, hexagons.size), XtRString, "3"}, /* DEFAULTHEXS */
185 {XtNcorners, XtCCorners, XtRBoolean, sizeof (Boolean),
186 XtOffset(HexagonsWidget, hexagons.corners), XtRString, "TRUE"}, /*DEFAULTCORN */
187 {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
188 XtOffset(HexagonsWidget, hexagons.mono), XtRString, "FALSE"},
189 {XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
190 XtOffset(HexagonsWidget, hexagons.reverse), XtRString, "FALSE"},
191 {XtNbase, XtCBase, XtRInt, sizeof (int),
192 XtOffset(HexagonsWidget, hexagons.base), XtRString, "10"},
193 {XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
194 XtOffset(HexagonsWidget, hexagons.started), XtRString, "FALSE"},
195 {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
196 XtOffset(HexagonsWidget, hexagons.select), XtRCallback, NULL}
197 };
198
199 HexagonsClassRec hexagonsClassRec =
200 {
201 {
202 (WidgetClass) & widgetClassRec, /* superclass */
203 "Hexagons", /* class name */
204 sizeof (HexagonsRec), /* widget size */
205 NULL, /* class initialize */
206 NULL, /* class part initialize */
207 FALSE, /* class inited */
208 (XtInitProc) InitializeHexagons, /* initialize */
209 NULL, /* initialize hook */
210 XtInheritRealize, /* realize */
211 actionsListHexagons, /* actions */
212 XtNumber(actionsListHexagons), /* num actions */
213 resourcesHexagons, /* resources */
214 XtNumber(resourcesHexagons), /* num resources */
215 NULLQUARK, /* xrm class */
216 TRUE, /* compress motion */
217 TRUE, /* compress exposure */
218 TRUE, /* compress enterleave */
219 TRUE, /* visible interest */
220 (XtWidgetProc) DestroyHexagons, /* destroy */
221 (XtWidgetProc) ResizeHexagons, /* resize */
222 (XtExposeProc) ExposeHexagons, /* expose */
223 (XtSetValuesFunc) SetValuesHexagons, /* set values */
224 NULL, /* set values hook */
225 XtInheritSetValuesAlmost, /* set values almost */
226 NULL, /* get values hook */
227 NULL, /* accept focus */
228 XtVersion, /* version */
229 NULL, /* callback private */
230 defaultTranslationsHexagons, /* tm table */
231 NULL, /* query geometry */
232 NULL, /* display accelerator */
233 NULL /* extension */
234 },
235 {
236 0 /* ignore */
237 }
238 };
239
240 WidgetClass hexagonsWidgetClass = (WidgetClass) & hexagonsClassRec;
241
242 static XPoint hexagonUnit[MAXORIENT][7] =
243 {
244 {
245 {0, 0},
246 {2, 0},
247 {1, 1},
248 {-1, 1},
249 {-2, 0},
250 {-1, -1},
251 {1, -1}},
252 {
253 {0, 0},
254 {1, 1},
255 {0, 2},
256 {-1, 1},
257 {-1, -1},
258 {0, -2},
259 {1, -1}}
260 };
261 static XPoint hexagonList[MAXORIENT][7];
262
263 #ifndef HAVE_USLEEP
264 #if !defined( VMS ) || defined( XVMSUTILS ) || ( __VMS_VER >= 70000000 )
265 #ifdef USE_XVMSUTILS
266 #include <X11/unix_time.h>
267 #endif
268 #if HAVE_SYS_TIME_H
269 #include <sys/time.h>
270 #else
271 #if HAVE_SYS_SELECT_H
272 #include <sys/select.h>
273 #endif
274 #endif
275 #endif
276 #if defined(SYSV) || defined(SVR4)
277 #ifdef LESS_THAN_AIX3_2
278 #include <sys/poll.h>
279 #else /* !LESS_THAN_AIX3_2 */
280 #include <poll.h>
281 #endif /* !LESS_THAN_AIX3_2 */
282 #endif /* defined(SYSV) || defined(SVR4) */
283
284 static int
usleep(unsigned int usec)285 usleep(unsigned int usec)
286 {
287 #if (defined (SYSV) || defined(SVR4)) && !defined(__hpux)
288 #if defined(HAVE_NANOSLEEP)
289 {
290 struct timespec rqt;
291
292 rqt.tv_nsec = 1000 * (usec % (unsigned int) 1000000);
293 rqt.tv_sec = usec / (unsigned int) 1000000;
294 return nanosleep(&rqt, NULL);
295 }
296 #else
297 (void) poll((void *) 0, (int) 0, usec / 1000); /* ms resolution */
298 #endif
299 #else
300 #ifdef VMS
301 long timadr[2];
302
303 if (usec != 0) {
304 timadr[0] = -usec * 10;
305 timadr[1] = -1;
306
307 sys$setimr(4, &timadr, 0, 0, 0);
308 sys$waitfr(4);
309 }
310 #else
311 struct timeval time_out;
312
313 #if 0
314 /* (!defined(AIXV3) && !defined(__hpux)) */
315 extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
316
317 #endif
318
319 time_out.tv_usec = usec % (unsigned int) 1000000;
320 time_out.tv_sec = usec / (unsigned int) 1000000;
321 (void) select(0, (void *) 0, (void *) 0, (void *) 0, &time_out);
322 #endif
323 #endif
324 return 0;
325 }
326 #endif
327
328 static void
Sleep(unsigned int cMilliseconds)329 Sleep(unsigned int cMilliseconds)
330 {
331 (void) usleep(cMilliseconds * 1000);
332 }
333
334 static void
InitializeHexagons(Widget request,Widget renew)335 InitializeHexagons(Widget request, Widget renew)
336 {
337 HexagonsWidget w = (HexagonsWidget) renew;
338
339 w->hexagons.tileOfPosition = NULL;
340 CheckTiles(w);
341 InitMoves();
342 ResetTiles(w);
343 (void) SRAND(getpid());
344 w->hexagons.depth = DefaultDepthOfScreen(XtScreen(w));
345 SetAllColors(w, True);
346 ResizeHexagons(w);
347 }
348
349 static void
DestroyHexagons(Widget old)350 DestroyHexagons(Widget old)
351 {
352 HexagonsWidget w = (HexagonsWidget) old;
353
354 XtReleaseGC(old, w->hexagons.tileGC);
355 XtReleaseGC(old, w->hexagons.borderGC);
356 XtReleaseGC(old, w->hexagons.puzzleGC);
357 XtReleaseGC(old, w->hexagons.inverseGC);
358 XtRemoveCallbacks(old, XtNselectCallback, w->hexagons.select);
359 }
360
361 static void
ResizeHexagons(HexagonsWidget w)362 ResizeHexagons(HexagonsWidget w)
363 {
364 double sqrt_3 = 1.73205080756887729352744634150587237;
365 XPoint tempSize;
366
367 w->hexagons.delta.x = 2;
368 w->hexagons.delta.y = 2;
369 w->hexagons.tileSize.x = MAX((2 * ((int) w->core.width +
370 2 * w->hexagons.delta.x - 1) - 4 * w->hexagons.size *
371 w->hexagons.delta.x) / (4 * w->hexagons.size - 1), 0);
372 w->hexagons.tileSize.y = MAX(((int) w->core.height - 1 -
373 2 * w->hexagons.size * w->hexagons.delta.y) /
374 (3 * w->hexagons.size - 1), 0);
375 w->hexagons.offset.x = w->hexagons.tileSize.x + w->hexagons.delta.x;
376 w->hexagons.offset.y = w->hexagons.tileSize.y + 2 * w->hexagons.delta.y;
377 tempSize.y = (int) ((double) w->hexagons.offset.x / sqrt_3);
378 tempSize.x = (int) ((double) w->hexagons.offset.y * sqrt_3);
379 if (tempSize.y < w->hexagons.offset.y) {
380 w->hexagons.offset.x = w->hexagons.tileSize.x + w->hexagons.delta.x;
381 w->hexagons.offset.y = tempSize.y;
382 } else { /* tempSize.x <= w->hexagons.offset.x */
383 w->hexagons.offset.x = tempSize.x;
384 w->hexagons.offset.y = w->hexagons.tileSize.y + 2 * w->hexagons.delta.y;
385 }
386 w->hexagons.tileSize.x = MAX(w->hexagons.offset.x - w->hexagons.delta.x, 0);
387 w->hexagons.tileSize.y = MAX(w->hexagons.offset.y - 2 * w->hexagons.delta.y,
388 0);
389 w->hexagons.puzzleSize.x = w->hexagons.size * 2 * w->hexagons.offset.x -
390 w->hexagons.tileSize.x / 2 - 2 * w->hexagons.delta.x + 1;
391 w->hexagons.puzzleSize.y = w->hexagons.size * (3 * w->hexagons.tileSize.y +
392 2 * w->hexagons.delta.y) - w->hexagons.tileSize.y + 2;
393 w->hexagons.puzzleOffset.x =
394 ((int) w->core.width - w->hexagons.puzzleSize.x + 2) / 2;
395 w->hexagons.puzzleOffset.y =
396 ((int) w->core.height - w->hexagons.puzzleSize.y + 2) / 2;
397 ResizeTiles(w);
398 }
399
400 static void
ExposeHexagons(Widget renew,XEvent * event,Region region)401 ExposeHexagons(Widget renew, XEvent * event, Region region)
402 {
403 HexagonsWidget w = (HexagonsWidget) renew;
404
405 if (w->core.visible) {
406 if (w->hexagons.reverse)
407 XFillRectangle(XtDisplay(w), XtWindow(w),
408 w->hexagons.inverseGC, 0, 0, w->core.width, w->core.height);
409
410 DrawFrame(w, w->hexagons.puzzleGC);
411 DrawAllTiles(w);
412 }
413 }
414
415 static Boolean
SetValuesHexagons(Widget current,Widget request,Widget renew)416 SetValuesHexagons(Widget current, Widget request, Widget renew)
417 {
418 HexagonsWidget c = (HexagonsWidget) current, w = (HexagonsWidget) renew;
419 Boolean redraw = FALSE;
420 Boolean redrawTiles = FALSE;
421
422 CheckTiles(w);
423 if (w->core.background_pixel != c->core.background_pixel ||
424 w->hexagons.foreground != c->hexagons.foreground ||
425 w->hexagons.borderColor != c->hexagons.borderColor ||
426 w->hexagons.tileColor != c->hexagons.tileColor ||
427 w->hexagons.reverse != c->hexagons.reverse ||
428 w->hexagons.mono != c->hexagons.mono) {
429 SetAllColors(w, False);
430 redrawTiles = TRUE;
431 }
432 if (w->hexagons.size != c->hexagons.size ||
433 w->hexagons.corners != c->hexagons.corners ||
434 w->hexagons.base != c->hexagons.base) {
435 ResetTiles(w);
436 ResizeHexagons(w);
437 redraw = TRUE;
438 } else if (w->hexagons.offset.x != c->hexagons.offset.x ||
439 w->hexagons.offset.y != c->hexagons.offset.y) {
440 ResizeHexagons(w);
441 redraw = TRUE;
442 }
443 if (redrawTiles && !redraw && XtIsRealized(renew) && renew->core.visible) {
444 DrawFrame(c, c->hexagons.inverseGC);
445 DrawFrame(w, w->hexagons.puzzleGC);
446 DrawAllTiles(w);
447 }
448 return (redraw);
449 }
450
451 static void
QuitHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)452 QuitHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
453 {
454 XtCloseDisplay(XtDisplay(w));
455 exit(0);
456 }
457
458 static void
SelectHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)459 SelectHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
460 {
461 int pos, row, rowType;
462
463 pos = PositionToTile(w, event->xbutton.x, event->xbutton.y, &row);
464 if (pos >= 0) {
465 if (CheckSolved(w)) {
466 MoveNoTiles(w);
467 w->hexagons.currentPosition = -1;
468 return;
469 }
470 w->hexagons.currentPosition = PositionFromRow(w, pos, row);
471 w->hexagons.currentRow[ROW] = row;
472 w->hexagons.currentRow[TRBL] = TrBl(w, w->hexagons.currentPosition, row);
473 w->hexagons.currentRow[TLBR] = TlBr(w, w->hexagons.currentPosition, row);
474 if (w->hexagons.corners)
475 rowType = MovableCornerTile(w);
476 else
477 rowType = MovableNoCornTile(w);
478 if (rowType < 0) {
479 hexagonsCallbackStruct cb;
480
481 DrawTile(w, w->hexagons.currentPosition, rowType == HEXAGONS_SPACE, False, TRUE);
482 XFlush(XtDisplay(w));
483 Sleep(100);
484 DrawTile(w, w->hexagons.currentPosition, True, True, TRUE);
485 if (rowType != HEXAGONS_SPACE)
486 DrawTile(w, w->hexagons.currentPosition, False, False, FALSE);
487 cb.reason = rowType;
488 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
489 w->hexagons.currentPosition = -1;
490 return;
491 }
492 DrawTile(w, w->hexagons.currentPosition, False, False, TRUE);
493 } else
494 w->hexagons.currentPosition = -1;
495 }
496
497 static void
ReleaseHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)498 ReleaseHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
499 {
500 int pos, row, space;
501
502 if (w->hexagons.currentPosition == -1)
503 return;
504 DrawTile(w, w->hexagons.currentPosition, True, True, TRUE);
505 DrawTile(w, w->hexagons.currentPosition, False, False, FALSE);
506 if (!w->hexagons.corners) {
507 SelectNoCornTiles(w);
508 w->hexagons.currentPosition = -1;
509 return;
510 }
511 pos = PositionToTile(w, event->xbutton.x, event->xbutton.y, &row);
512 if (pos >= 0) {
513 pos = PositionFromRow(w, pos, row);
514 if (w->hexagons.spacePosition[HIGH] == pos)
515 space = (w->hexagons.spacePosition[HIGH] >
516 w->hexagons.spacePosition[LOW]);
517 else if (w->hexagons.spacePosition[LOW] == pos)
518 space = (w->hexagons.spacePosition[HIGH] <
519 w->hexagons.spacePosition[LOW]);
520 else {
521 w->hexagons.currentPosition = -1;
522 return;
523 }
524 SelectCornerTiles(w, space);
525 }
526 w->hexagons.currentPosition = -1;
527 }
528
529 static void
RandomizeHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)530 RandomizeHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
531 {
532 RandomizeTiles(w);
533 }
534
535 static void
RandomizeHexagonsMaybe(HexagonsWidget w,XEvent * event,char ** args,int nArgs)536 RandomizeHexagonsMaybe(HexagonsWidget w, XEvent * event, char **args, int nArgs)
537 {
538 if (!w->hexagons.started)
539 RandomizeTiles(w);
540 }
541
542 static void
GetHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)543 GetHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
544 {
545 FILE *fp;
546 char c;
547 int i, size, corners, moves;
548 hexagonsCallbackStruct cb;
549
550 if ((fp = fopen(DATAFILE, "r")) == NULL)
551 (void) printf("Can not read %s for get.\n", DATAFILE);
552 else {
553 FlushMoves(w);
554 while ((c = getc(fp)) != EOF && c != SYMBOL);
555 (void) fscanf(fp, "%d", &size);
556 if (size >= MINHEXAGONS) {
557 for (i = w->hexagons.size; i < size; i++) {
558 cb.reason = HEXAGONS_INC;
559 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
560 }
561 for (i = w->hexagons.size; i > size; i--) {
562 cb.reason = HEXAGONS_DEC;
563 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
564 }
565 } else
566 (void) printf("%s corrupted: size %d should be between %d and MAXINT\n",
567 DATAFILE, size, MINHEXAGONS);
568 while ((c = getc(fp)) != EOF && c != SYMBOL);
569 (void) fscanf(fp, "%d", &corners);
570 if (w->hexagons.corners != (Boolean) corners) {
571 cb.reason = HEXAGONS_CORNERS;
572 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
573 }
574 while ((c = getc(fp)) != EOF && c != SYMBOL);
575 (void) fscanf(fp, "%d", &moves);
576 ScanStartPosition(fp, w);
577 cb.reason = HEXAGONS_RESTORE;
578 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
579 SetStartPosition(w);
580 ScanMoves(fp, w, moves);
581 (void) fclose(fp);
582 (void) printf("%s: size %d, corners %d, moves %d.\n",
583 DATAFILE, size, corners, moves);
584 }
585 }
586
587 static void
WriteHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)588 WriteHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
589 {
590 FILE *fp;
591
592 if ((fp = fopen(DATAFILE, "w")) == NULL)
593 (void) printf("Can not write to %s.\n", DATAFILE);
594 else {
595 (void) fprintf(fp, "size%c %d\n", SYMBOL, w->hexagons.size);
596 (void) fprintf(fp, "corners%c %d\n", SYMBOL, (w->hexagons.corners) ? 1 : 0);
597 (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
598 PrintStartPosition(fp, w);
599 PrintMoves(fp);
600 (void) fclose(fp);
601 (void) printf("Saved to %s.\n", DATAFILE);
602 }
603 }
604
605 static void
UndoHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)606 UndoHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
607 {
608 if (MadeMoves()) {
609 int direction;
610
611 GetMove(&direction);
612 direction = (direction + (COORD / 2)) % COORD;
613 if (MoveTilesDir(w, direction)) {
614 hexagonsCallbackStruct cb;
615
616 cb.reason = HEXAGONS_UNDO;
617 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
618 }
619 }
620 }
621
622 static void
SolveHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)623 SolveHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
624 {
625 #if 0
626 SolveTiles(w); /* Sorry, this is not implemented */
627 #endif
628 }
629
630 static void
IncrementHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)631 IncrementHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
632 {
633 hexagonsCallbackStruct cb;
634
635 cb.reason = HEXAGONS_INC;
636 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
637 }
638
639 static void
DecrementHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)640 DecrementHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
641 {
642 hexagonsCallbackStruct cb;
643
644 if (w->hexagons.size <= MINHEXAGONS)
645 return;
646 cb.reason = HEXAGONS_DEC;
647 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
648 }
649
650 static void
CornerHexagons(HexagonsWidget w,XEvent * event,char ** args,int nArgs)651 CornerHexagons(HexagonsWidget w, XEvent * event, char **args, int nArgs)
652 {
653 hexagonsCallbackStruct cb;
654
655 cb.reason = HEXAGONS_CORNERS;
656 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
657 }
658
659 static void
MoveHexagonsTl(HexagonsWidget w,XEvent * event,char ** args,int nArgs)660 MoveHexagonsTl(HexagonsWidget w, XEvent * event, char **args, int nArgs)
661 {
662 (void) MoveHexagons(w, TL);
663 }
664
665 static void
MoveHexagonsTr(HexagonsWidget w,XEvent * event,char ** args,int nArgs)666 MoveHexagonsTr(HexagonsWidget w, XEvent * event, char **args, int nArgs)
667 {
668 (void) MoveHexagons(w, TR);
669 }
670
671 static void
MoveHexagonsLeft(HexagonsWidget w,XEvent * event,char ** args,int nArgs)672 MoveHexagonsLeft(HexagonsWidget w, XEvent * event, char **args, int nArgs)
673 {
674 (void) MoveHexagons(w, LEFT);
675 }
676
677 static void
MoveHexagonsRight(HexagonsWidget w,XEvent * event,char ** args,int nArgs)678 MoveHexagonsRight(HexagonsWidget w, XEvent * event, char **args, int nArgs)
679 {
680 (void) MoveHexagons(w, RIGHT);
681 }
682
683 static void
MoveHexagonsBl(HexagonsWidget w,XEvent * event,char ** args,int nArgs)684 MoveHexagonsBl(HexagonsWidget w, XEvent * event, char **args, int nArgs)
685 {
686 (void) MoveHexagons(w, BL);
687 }
688
689 static void
MoveHexagonsBr(HexagonsWidget w,XEvent * event,char ** args,int nArgs)690 MoveHexagonsBr(HexagonsWidget w, XEvent * event, char **args, int nArgs)
691 {
692 (void) MoveHexagons(w, BR);
693 }
694
695 static int
MoveHexagons(HexagonsWidget w,int direction)696 MoveHexagons(HexagonsWidget w, int direction)
697 {
698 hexagonsCallbackStruct cb;
699
700 if (CheckSolved(w)) {
701 MoveNoTiles(w);
702 return FALSE;
703 }
704 if (!MoveHexagonsDir(w, direction)) {
705 cb.reason = HEXAGONS_BLOCKED;
706 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
707 return FALSE;
708 }
709 if (CheckSolved(w)) {
710 cb.reason = HEXAGONS_SOLVED;
711 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
712 }
713 return TRUE;
714 }
715
716 int
MoveHexagonsDir(HexagonsWidget w,int direction)717 MoveHexagonsDir(HexagonsWidget w, int direction)
718 {
719 hexagonsCallbackStruct cb;
720
721 if (MoveTilesDir(w, direction)) {
722 cb.reason = HEXAGONS_MOVED;
723 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
724 PutMove(direction);
725 return TRUE;
726 }
727 return FALSE;
728 }
729
730 static int
PositionToTile(HexagonsWidget w,int x,int y,int * row)731 PositionToTile(HexagonsWidget w, int x, int y, int *row)
732 {
733 int i, j, k, modI, modJ;
734
735 x -= w->hexagons.puzzleOffset.x;
736 y -= w->hexagons.puzzleOffset.y;
737 /* First convert x and y coordinates to hexagon grid. Keep in mind that
738 the starting hexagon x position changes with "w->hexagons.size % 2". */
739 if (x < w->hexagons.tileSize.x / 4)
740 return -1;
741 i = 2 * (x - w->hexagons.tileSize.x / 4) / w->hexagons.offset.x;
742 j = 3 * (y - w->hexagons.delta.y) /
743 (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y);
744 modI = 2 * (x - w->hexagons.tileSize.x / 4) % w->hexagons.offset.x;
745 modJ = 3 * (y - w->hexagons.delta.y) %
746 (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y);
747 *row = j / 3; /* Approximate to a rectangle just for now */
748 if (j % 3 == 0) { /* Then it is the triangle near bottom or top point */
749 if ((w->hexagons.size - 1 + *row + i) % 2) /* \ */
750 *row -= (modJ * w->hexagons.offset.x < modI *
751 (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y));
752 else /* / */
753 *row -= (modJ * w->hexagons.offset.x < (w->hexagons.offset.x - modI) *
754 (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y));
755 }
756 if (i < (w->hexagons.size - 1 + *row) % 2 || *row < 0 ||
757 *row > 2 * (w->hexagons.size - 1))
758 return -1;
759 k = (i - ((w->hexagons.size - 1 + *row) % 2)) / 2;
760 /* Map the hexagon grid to hexagon position in puzzle. */
761 i = (*row < w->hexagons.size) ?
762 k - (w->hexagons.size - 1 - *row) / 2 :
763 k + (w->hexagons.size - 1 - *row) / 2;
764 j = (*row < w->hexagons.size) ?
765 w->hexagons.size - 1 + *row : 3 * (w->hexagons.size - 1) - *row;
766 if (i < 0 || i > j)
767 return -1;
768 return i;
769 }
770
771 static int
MovableCornerTile(HexagonsWidget w)772 MovableCornerTile(HexagonsWidget w)
773 {
774 /* (Clicked on a space?). */
775 if (w->hexagons.currentPosition == w->hexagons.spacePosition[LOW] ||
776 w->hexagons.currentPosition == w->hexagons.spacePosition[HIGH]) {
777 return HEXAGONS_SPACE;
778 }
779 if (FindTileTriangle(w,
780 w->hexagons.currentPosition, w->hexagons.spacePosition[HIGH],
781 w->hexagons.spacePosition[LOW], w->hexagons.currentRow[ROW],
782 w->hexagons.spaceRow[HIGH], w->hexagons.spaceRow[LOW])) {
783 return 0;
784 }
785 return HEXAGONS_BLOCKED;
786 }
787
788 static int
MovableNoCornTile(HexagonsWidget w)789 MovableNoCornTile(HexagonsWidget w)
790 {
791 int rowType = HEXAGONS_BLOCKED, l;
792
793 /* Are the spaces in a "row" with the mouse click?
794 (If two, then one clicked on a space). */
795 for (l = 0; l < ROWTYPES; l++) {
796 if (w->hexagons.currentRow[l] == w->hexagons.spaceRow[l]) {
797 if (rowType == HEXAGONS_BLOCKED) {
798 rowType = l;
799 } else {
800 return HEXAGONS_SPACE;
801 }
802 }
803 }
804 return rowType;
805 }
806
807 static void
SelectCornerTiles(HexagonsWidget w,int space)808 SelectCornerTiles(HexagonsWidget w, int space)
809 {
810 int rowType, orient;
811 hexagonsCallbackStruct cb;
812
813 rowType = MovableCornerTile(w);
814 if (rowType < 0) {
815 (void) printf("SelectCornerTiles: rowType %d\n", rowType);
816 return;
817 }
818 orient = (w->hexagons.spacePosition[HIGH] <
819 w->hexagons.spacePosition[LOW]) ? !space : space;
820 PutMove(FindDir(w,
821 w->hexagons.currentPosition, w->hexagons.spacePosition[orient],
822 w->hexagons.currentRow[ROW], w->hexagons.spaceRow[orient]));
823 MoveCornerTiles(w, w->hexagons.currentPosition,
824 w->hexagons.currentRow[ROW], orient);
825 cb.reason = HEXAGONS_MOVED;
826 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
827 if (CheckSolved(w)) {
828 cb.reason = HEXAGONS_SOLVED;
829 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
830 }
831 }
832
833 static void
SelectNoCornTiles(HexagonsWidget w)834 SelectNoCornTiles(HexagonsWidget w)
835 {
836 hexagonsCallbackStruct cb;
837 int rowType, orient;
838
839 rowType = MovableNoCornTile(w);
840 if (rowType < 0) {
841 (void) printf("SelectNoCornTiles: rowType %d\n", rowType);
842 return;
843 }
844 if (w->hexagons.currentPosition < w->hexagons.spacePosition[HIGH]) {
845 while (w->hexagons.currentPosition < w->hexagons.spacePosition[HIGH]) {
846 orient = (rowType == ROW) ?
847 w->hexagons.spaceRow[ROW] : w->hexagons.spaceRow[ROW] - 1;
848 MoveNoCornTiles(w, TileNextToSpace(w, rowType, HIGH), orient);
849 cb.reason = HEXAGONS_MOVED;
850 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
851 switch (rowType) {
852 case TLBR:
853 PutMove(BR);
854 break;
855 case TRBL:
856 PutMove(BL);
857 break;
858 case ROW:
859 PutMove(RIGHT);
860 break;
861 default:
862 (void) printf("SelectNoCornTiles: rowType %d\n", rowType);
863 }
864 }
865 } else { /*w->hexagons.currentPosition > w->hexagons.spacePosition[HIGH] */
866 while (w->hexagons.currentPosition > w->hexagons.spacePosition[HIGH]) {
867 orient = (rowType == ROW) ?
868 w->hexagons.spaceRow[ROW] : w->hexagons.spaceRow[ROW] + 1;
869 MoveNoCornTiles(w, TileNextToSpace(w, rowType, LOW), orient);
870 cb.reason = HEXAGONS_MOVED;
871 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
872 switch (rowType) {
873 case TLBR:
874 PutMove(TL);
875 break;
876 case TRBL:
877 PutMove(TR);
878 break;
879 case ROW:
880 PutMove(LEFT);
881 break;
882 default:
883 (void) printf("SelectNoCornTiles: rowType %d\n", rowType);
884 }
885 }
886 }
887 if (CheckSolved(w)) {
888 cb.reason = HEXAGONS_SOLVED;
889 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
890 }
891 }
892
893 static void
SetAllColors(HexagonsWidget w,Boolean init)894 SetAllColors(HexagonsWidget w, Boolean init)
895 {
896 XGCValues values;
897 XtGCMask valueMask;
898
899 valueMask = GCForeground | GCBackground;
900 if (w->hexagons.reverse) {
901 values.foreground = w->hexagons.foreground;
902 values.background = w->core.background_pixel;
903 } else {
904 values.foreground = w->core.background_pixel;
905 values.background = w->hexagons.foreground;
906 }
907 if (!init)
908 XtReleaseGC((Widget) w, w->hexagons.inverseGC);
909 w->hexagons.inverseGC = XtGetGC((Widget) w, valueMask, &values);
910 if (w->hexagons.reverse) {
911 values.foreground = w->core.background_pixel;
912 values.background = w->hexagons.foreground;
913 } else {
914 values.foreground = w->hexagons.foreground;
915 values.background = w->core.background_pixel;
916 }
917 if (!init)
918 XtReleaseGC((Widget) w, w->hexagons.puzzleGC);
919 w->hexagons.puzzleGC = XtGetGC((Widget) w, valueMask, &values);
920 if (w->hexagons.depth < 2 || w->hexagons.mono) {
921 if (w->hexagons.reverse) {
922 values.foreground = w->core.background_pixel;
923 values.background = w->hexagons.foreground;
924 } else {
925 values.foreground = w->hexagons.foreground;
926 values.background = w->core.background_pixel;
927 }
928 } else {
929 values.foreground = w->hexagons.tileColor;
930 values.background = w->hexagons.borderColor;
931 }
932 if (!init)
933 XtReleaseGC((Widget) w, w->hexagons.tileGC);
934 w->hexagons.tileGC = XtGetGC((Widget) w, valueMask, &values);
935 if (w->hexagons.depth < 2 || w->hexagons.mono) {
936 if (w->hexagons.reverse) {
937 values.foreground = w->hexagons.foreground;
938 values.background = w->core.background_pixel;
939 } else {
940 values.foreground = w->core.background_pixel;
941 values.background = w->hexagons.foreground;
942 }
943 } else {
944 values.foreground = w->hexagons.borderColor;
945 values.background = w->hexagons.tileColor;
946 }
947 if (!init)
948 XtReleaseGC((Widget) w, w->hexagons.borderGC);
949 w->hexagons.borderGC = XtGetGC((Widget) w, valueMask, &values);
950 }
951
952 static void
CheckTiles(HexagonsWidget w)953 CheckTiles(HexagonsWidget w)
954 {
955 char buf[121];
956
957 if (w->hexagons.size < MINHEXAGONS) {
958 (void) sprintf(buf,
959 "Number of Hexagons on a edge out of bounds, use %d..MAXINT",
960 MINHEXAGONS);
961 XtWarning(buf);
962 w->hexagons.size = DEFAULTHEXAGONS;
963 }
964 if (w->hexagons.base > 36) {
965 /* 10 numbers + 26 letters (ASCII or EBCDIC) */
966 XtWarning("Base must be less than or equal to 36");
967 w->hexagons.base = 10;
968 } else if (w->hexagons.base <= 1) { /* Base 1 is rediculous :) */
969 XtWarning("Base must be greater than 1");
970 w->hexagons.base = 10;
971 }
972 }
973
974 static void
ResetTiles(HexagonsWidget w)975 ResetTiles(HexagonsWidget w)
976 {
977 int i;
978
979 w->hexagons.sizeSize = 3 * w->hexagons.size * (w->hexagons.size - 1) + 1;
980 w->hexagons.sizeCenter = (w->hexagons.sizeSize - 1) / 2;
981 if (w->hexagons.tileOfPosition)
982 (void) free((void *) w->hexagons.tileOfPosition);
983 if (!(w->hexagons.tileOfPosition = (int *)
984 malloc(sizeof (int) * w->hexagons.sizeSize)))
985 XtError("Not enough memory, exiting.");
986
987 if (startPosition)
988 (void) free((void *) startPosition);
989 if (!(startPosition = (int *)
990 malloc(sizeof (int) * w->hexagons.sizeSize)))
991 XtError("Not enough memory, exiting.");
992
993 w->hexagons.spacePosition[HIGH] = w->hexagons.sizeSize - 1;
994 if (w->hexagons.corners) {
995 w->hexagons.spaceRow[HIGH] = 2 * w->hexagons.size - 2;
996 if (w->hexagons.size > 1) {
997 w->hexagons.spacePosition[LOW] = w->hexagons.sizeSize - 2;
998 w->hexagons.spaceRow[LOW] = 2 * w->hexagons.size - 2;
999 w->hexagons.tileOfPosition[w->hexagons.sizeSize - 2] = -1;
1000 }
1001 } else {
1002 w->hexagons.spaceRow[ROW] = w->hexagons.spaceRow[TRBL] =
1003 2 * w->hexagons.size - 2;
1004 w->hexagons.spaceRow[TLBR] = w->hexagons.size - 1;
1005 }
1006 w->hexagons.tileOfPosition[w->hexagons.sizeSize - 1] = 0;
1007 for (i = 1; i < w->hexagons.sizeSize - ((w->hexagons.corners) ? 1 : 0);
1008 i++)
1009 w->hexagons.tileOfPosition[i - 1] = i;
1010 FlushMoves(w);
1011 w->hexagons.currentPosition = -1;
1012 w->hexagons.started = FALSE;
1013 }
1014
1015 static void
ResizeTiles(HexagonsWidget w)1016 ResizeTiles(HexagonsWidget w)
1017 {
1018 int i;
1019
1020 for (i = 0; i <= 6; i++) {
1021 hexagonList[NOCORN][i].x = w->hexagons.tileSize.x *
1022 hexagonUnit[NOCORN][i].x / 4;
1023 hexagonList[NOCORN][i].y = 3 * w->hexagons.tileSize.y *
1024 hexagonUnit[NOCORN][i].y / 4;
1025 hexagonList[CORNERS][i].x = w->hexagons.tileSize.x *
1026 hexagonUnit[CORNERS][i].x / 2;
1027 hexagonList[CORNERS][i].y = w->hexagons.tileSize.y *
1028 hexagonUnit[CORNERS][i].y / 2;
1029 }
1030 w->hexagons.digitOffset.x = 3;
1031 w->hexagons.digitOffset.y = 4;
1032 }
1033
1034 static int
MovableCornerTiles(HexagonsWidget w,int direction,int * position,int * posRow,int * space)1035 MovableCornerTiles(HexagonsWidget w, int direction, int *position, int *posRow, int *space)
1036 {
1037 int spaceType, highest, side = -1;
1038
1039 highest = (w->hexagons.spacePosition[HIGH] >
1040 w->hexagons.spacePosition[LOW]) ? HIGH : LOW;
1041 spaceType = FindSpaceType(w,
1042 w->hexagons.spacePosition[HIGH], w->hexagons.spacePosition[LOW],
1043 w->hexagons.spaceRow[HIGH], w->hexagons.spaceRow[LOW]);
1044 switch (spaceType) {
1045 case TRBL:
1046 if (direction == TR || direction == BL)
1047 return FALSE;
1048 side = NextToWall(w, w->hexagons.spacePosition[highest],
1049 w->hexagons.spaceRow[highest], spaceType);
1050 if (side != -1) {
1051 if ((side == HIGH && direction == RIGHT) ||
1052 (side == HIGH && direction == BR) ||
1053 (side == LOW && direction == LEFT) ||
1054 (side == LOW && direction == TL))
1055 return FALSE;
1056 } else
1057 side = (direction == TL || direction == LEFT);
1058 *space = (direction == BR || direction == LEFT);
1059 break;
1060 case TLBR:
1061 if (direction == TL || direction == BR)
1062 return FALSE;
1063 side = NextToWall(w, w->hexagons.spacePosition[highest],
1064 w->hexagons.spaceRow[highest], spaceType);
1065 if (side != -1) {
1066 if ((side == LOW && direction == TR) ||
1067 (side == LOW && direction == RIGHT) ||
1068 (side == HIGH && direction == BL) ||
1069 (side == HIGH && direction == LEFT))
1070 return FALSE;
1071 } else
1072 side = (direction == TR || direction == RIGHT);
1073 *space = (direction == RIGHT || direction == BL);
1074 break;
1075 case ROW:
1076 if (direction == LEFT || direction == RIGHT)
1077 return FALSE;
1078 side = NextToWall(w, w->hexagons.spacePosition[highest],
1079 w->hexagons.spaceRow[highest], spaceType);
1080 if (side != -1) {
1081 if ((side == LOW && direction == TR) ||
1082 (side == HIGH && direction == BR) ||
1083 (side == HIGH && direction == BL) ||
1084 (side == LOW && direction == TL))
1085 return FALSE;
1086 } else
1087 side = (direction == TR || direction == TL);
1088 *space = (direction == TR || direction == BR);
1089 break;
1090 }
1091 FindMovableTile(w, w->hexagons.spacePosition[highest],
1092 w->hexagons.spaceRow[highest], spaceType, side, position, posRow);
1093 return TRUE;
1094 }
1095
1096 static void
MoveNoTiles(HexagonsWidget w)1097 MoveNoTiles(HexagonsWidget w)
1098 {
1099 hexagonsCallbackStruct cb;
1100
1101 cb.reason = HEXAGONS_IGNORE;
1102 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1103 }
1104
1105 static int
MoveTilesDir(HexagonsWidget w,int direction)1106 MoveTilesDir(HexagonsWidget w, int direction)
1107 {
1108 if (w->hexagons.corners)
1109 return MoveCornerTilesDir(w, direction);
1110 else
1111 return MoveNoCornTilesDir(w, direction);
1112 }
1113
1114
1115 static int
MoveCornerTilesDir(HexagonsWidget w,int direction)1116 MoveCornerTilesDir(HexagonsWidget w, int direction)
1117 {
1118 int position, posRow, space;
1119
1120 if (MovableCornerTiles(w, direction, &position, &posRow, &space)) {
1121 MoveCornerTiles(w, position, posRow, (w->hexagons.spacePosition[HIGH] <
1122 w->hexagons.spacePosition[LOW]) ? !space : space);
1123 return TRUE;
1124 }
1125 return FALSE;
1126 }
1127
1128 static int
MoveNoCornTilesDir(HexagonsWidget w,int direction)1129 MoveNoCornTilesDir(HexagonsWidget w, int direction)
1130 {
1131 switch (direction) {
1132 case TR:
1133 if (w->hexagons.spaceRow[ROW] != 2 * w->hexagons.size - 2 &&
1134 w->hexagons.spaceRow[TLBR] != 2 * w->hexagons.size - 2) {
1135 MoveNoCornTiles(w, TileNextToSpace(w, TRBL, LOW),
1136 w->hexagons.spaceRow[ROW] + 1);
1137 return TRUE;
1138 }
1139 break;
1140 case RIGHT:
1141 if (w->hexagons.spaceRow[TRBL] != 0 &&
1142 w->hexagons.spaceRow[TLBR] != 2 * w->hexagons.size - 2) {
1143 MoveNoCornTiles(w, TileNextToSpace(w, ROW, HIGH),
1144 w->hexagons.spaceRow[ROW]);
1145 return TRUE;
1146 }
1147 break;
1148 case BR:
1149 if (w->hexagons.spaceRow[ROW] != 0 &&
1150 w->hexagons.spaceRow[TRBL] != 0) {
1151 MoveNoCornTiles(w, TileNextToSpace(w, TLBR, HIGH),
1152 w->hexagons.spaceRow[ROW] - 1);
1153 return TRUE;
1154 }
1155 break;
1156 case BL:
1157 if (w->hexagons.spaceRow[ROW] != 0 &&
1158 w->hexagons.spaceRow[TLBR] != 0) {
1159 MoveNoCornTiles(w, TileNextToSpace(w, TRBL, HIGH),
1160 w->hexagons.spaceRow[ROW] - 1);
1161 return TRUE;
1162 }
1163 break;
1164 case LEFT:
1165 if (w->hexagons.spaceRow[TLBR] != 0 &&
1166 w->hexagons.spaceRow[TRBL] != 2 * w->hexagons.size - 2) {
1167 MoveNoCornTiles(w, TileNextToSpace(w, ROW, LOW),
1168 w->hexagons.spaceRow[ROW]);
1169 return TRUE;
1170 }
1171 break;
1172 case TL:
1173 if (w->hexagons.spaceRow[ROW] != 2 * w->hexagons.size - 2 &&
1174 w->hexagons.spaceRow[TRBL] != 2 * w->hexagons.size - 2) {
1175 MoveNoCornTiles(w, TileNextToSpace(w, TLBR, LOW),
1176 w->hexagons.spaceRow[ROW] + 1);
1177 return TRUE;
1178 }
1179 break;
1180 default:
1181 (void) printf("MoveNoCornTilesDir: direction %d\n", direction);
1182 }
1183 return FALSE;
1184 }
1185
1186 static void
RandomizeTiles(HexagonsWidget w)1187 RandomizeTiles(HexagonsWidget w)
1188 {
1189 hexagonsCallbackStruct cb;
1190
1191 /* First interchange tiles an even number of times */
1192 if (w->hexagons.size > 1 + ((w->hexagons.corners) ? 1 : 0)) {
1193 int currentPos, randomPos;
1194 int count = 0;
1195
1196 for (currentPos = 0; currentPos < w->hexagons.sizeSize; currentPos++) {
1197 randomPos = currentPos;
1198 while (currentPos == randomPos)
1199 randomPos = NRAND(w->hexagons.sizeSize);
1200 count += ExchangeTiles(w, currentPos, randomPos);
1201 }
1202 if (count % 2 && w->hexagons.corners)
1203 if (!ExchangeTiles(w, 0, 1))
1204 if (!ExchangeTiles(w,
1205 w->hexagons.sizeSize - 2, w->hexagons.sizeSize - 1))
1206 (void) printf("RandomizeTiles: should not get here\n");
1207 DrawAllTiles(w);
1208 }
1209 /* Now move the spaces around randomly */
1210 if (w->hexagons.size > 1) {
1211 int big = w->hexagons.sizeSize + NRAND(2);
1212 int lastDirection = 0;
1213 int randomDirection;
1214
1215 cb.reason = HEXAGONS_RESET;
1216 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1217
1218 if (w->hexagons.corners && w->hexagons.size == 2)
1219 big *= big;
1220
1221 #ifdef DEBUG
1222 big = 3;
1223 #endif
1224
1225 if (big > 1000)
1226 big = 1000;
1227 while (big--) {
1228 randomDirection = NRAND(COORD);
1229
1230 #ifdef DEBUG
1231 sleep(1);
1232 #endif
1233
1234 if ((randomDirection + COORD / 2) % COORD != lastDirection) {
1235 if (MoveHexagonsDir(w, randomDirection))
1236 lastDirection = randomDirection;
1237 else
1238 big++;
1239 }
1240 }
1241 FlushMoves(w);
1242 cb.reason = HEXAGONS_RANDOMIZE;
1243 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1244 }
1245 if (CheckSolved(w)) {
1246 cb.reason = HEXAGONS_SOLVED;
1247 XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
1248 }
1249 }
1250
1251 static void
MoveCornerTiles(HexagonsWidget w,int from,int posRow,int space)1252 MoveCornerTiles(HexagonsWidget w, int from, int posRow, int space)
1253 {
1254 int tempTile;
1255
1256 tempTile = w->hexagons.tileOfPosition[from];
1257 w->hexagons.tileOfPosition[from] =
1258 w->hexagons.tileOfPosition[w->hexagons.spacePosition[space]];
1259 w->hexagons.tileOfPosition[w->hexagons.spacePosition[space]] =
1260 tempTile;
1261 DrawTile(w, w->hexagons.spacePosition[space], False, False, FALSE);
1262 w->hexagons.spacePosition[space] = from;
1263 w->hexagons.spaceRow[space] = posRow;
1264 DrawTile(w, w->hexagons.spacePosition[space], True, True, FALSE);
1265 }
1266
1267 static void
MoveNoCornTiles(HexagonsWidget w,int from,int posRow)1268 MoveNoCornTiles(HexagonsWidget w, int from, int posRow)
1269 {
1270 int tempTile;
1271
1272 tempTile = w->hexagons.tileOfPosition[from];
1273 w->hexagons.tileOfPosition[from] =
1274 w->hexagons.tileOfPosition[w->hexagons.spacePosition[HIGH]];
1275 w->hexagons.tileOfPosition[w->hexagons.spacePosition[HIGH]] = tempTile;
1276 DrawTile(w, w->hexagons.spacePosition[HIGH], False, False, FALSE);
1277 w->hexagons.spacePosition[HIGH] = from;
1278 w->hexagons.spaceRow[ROW] = posRow;
1279 w->hexagons.spaceRow[TRBL] = TrBl(w, from, posRow);
1280 w->hexagons.spaceRow[TLBR] = TlBr(w, from, posRow);
1281 DrawTile(w, w->hexagons.spacePosition[HIGH], True, True, FALSE);
1282 }
1283
1284 static int
ExchangeTiles(HexagonsWidget w,int pos1,int pos2)1285 ExchangeTiles(HexagonsWidget w, int pos1, int pos2)
1286 {
1287 int tempTile;
1288
1289 if (w->hexagons.tileOfPosition[pos1] <= 0 ||
1290 w->hexagons.tileOfPosition[pos2] <= 0)
1291 return FALSE;
1292 tempTile = w->hexagons.tileOfPosition[pos1];
1293 w->hexagons.tileOfPosition[pos1] = w->hexagons.tileOfPosition[pos2];
1294 w->hexagons.tileOfPosition[pos2] = tempTile;
1295 return TRUE;
1296 }
1297
1298 #ifdef DEBUG
1299 static int
WithinFrame(HexagonsWidget w,int x,int y,int dx,int dy)1300 WithinFrame(HexagonsWidget w, int x, int y, int dx, int dy)
1301 {
1302 return
1303 (x < dx + w->hexagons.tileSize.x / 2 &&
1304 x > dx - w->hexagons.tileSize.x / 2 &&
1305 w->hexagons.tileSize.y * (x - dx) < w->hexagons.tileSize.x * (y - dy) &&
1306 w->hexagons.tileSize.y * (dx - x) < w->hexagons.tileSize.x * (y - dy) &&
1307 w->hexagons.tileSize.y * (x - dx + 2 * w->hexagons.tileSize.x) >
1308 w->hexagons.tileSize.x * (y - dy) &&
1309 w->hexagons.tileSize.y * (dx - x + 2 * w->hexagons.tileSize.x) >
1310 w->hexagons.tileSize.x * (y - dy));
1311 }
1312 #endif
1313
1314 static int
NextToWall(HexagonsWidget w,int pos,int posRow,int spaceType)1315 NextToWall(HexagonsWidget w, int pos, int posRow, int spaceType)
1316 {
1317 switch (spaceType) {
1318 case TRBL:
1319 if (posRow < w->hexagons.size && pos ==
1320 w->hexagons.size * posRow + posRow * (posRow - 1) / 2)
1321 return (HIGH);
1322 else if (posRow >= w->hexagons.size && pos == w->hexagons.size *
1323 (posRow - w->hexagons.size) + 3 * w->hexagons.size - posRow -
1324 2 + 4 * w->hexagons.size * (w->hexagons.size - 1) / 2 -
1325 (2 * w->hexagons.size - posRow - 2) *
1326 (2 * w->hexagons.size - posRow - 1) / 2)
1327 return (LOW);
1328 else
1329 return (-1);
1330 case TLBR:
1331 if (posRow < w->hexagons.size && pos ==
1332 w->hexagons.size * (posRow + 1) + posRow * (posRow + 1) / 2 - 1)
1333 return (HIGH);
1334 else if (posRow >= w->hexagons.size && pos == w->hexagons.size *
1335 (posRow - w->hexagons.size) + 1 + 4 * w->hexagons.size *
1336 (w->hexagons.size - 1) / 2 - (2 * w->hexagons.size - posRow - 2) *
1337 (2 * w->hexagons.size - posRow - 1) / 2)
1338 return (LOW);
1339 else
1340 return (-1);
1341 case ROW:
1342 if (posRow == 0)
1343 return (HIGH);
1344 else if (posRow == 2 * (w->hexagons.size - 1))
1345 return (LOW);
1346 else
1347 return (-1);
1348 }
1349 return (-2); /*Unknown space formation. */
1350 }
1351
1352 static int
TileNextToSpace(HexagonsWidget w,int rowType,int direction)1353 TileNextToSpace(HexagonsWidget w, int rowType, int direction)
1354 {
1355 if (direction == HIGH) {
1356 if (rowType == TRBL)
1357 return ((w->hexagons.spaceRow[ROW] < w->hexagons.size) ?
1358 w->hexagons.spacePosition[HIGH] - w->hexagons.size -
1359 w->hexagons.spaceRow[ROW] + 1 :
1360 w->hexagons.spacePosition[HIGH] - 3 * w->hexagons.size +
1361 w->hexagons.spaceRow[ROW] + 2);
1362 else if (rowType == TLBR)
1363 return ((w->hexagons.spaceRow[ROW] < w->hexagons.size) ?
1364 w->hexagons.spacePosition[HIGH] - w->hexagons.size -
1365 w->hexagons.spaceRow[ROW] :
1366 w->hexagons.spacePosition[HIGH] - 3 * w->hexagons.size +
1367 w->hexagons.spaceRow[ROW] + 1);
1368 else /* rowType == ROW */
1369 return (w->hexagons.spacePosition[HIGH] - 1);
1370 } else { /* direction == LOW */
1371 if (rowType == TRBL)
1372 return ((w->hexagons.spaceRow[ROW] < w->hexagons.size - 1) ?
1373 w->hexagons.spacePosition[HIGH] + w->hexagons.size +
1374 w->hexagons.spaceRow[ROW] :
1375 w->hexagons.spacePosition[HIGH] + 3 * w->hexagons.size -
1376 w->hexagons.spaceRow[ROW] - 3);
1377 else if (rowType == TLBR)
1378 return ((w->hexagons.spaceRow[ROW] < w->hexagons.size - 1) ?
1379 w->hexagons.spacePosition[HIGH] + w->hexagons.size +
1380 w->hexagons.spaceRow[ROW] + 1 :
1381 w->hexagons.spacePosition[HIGH] + 3 * w->hexagons.size -
1382 w->hexagons.spaceRow[ROW] - 2);
1383 else /* rowType == ROW */
1384 return (w->hexagons.spacePosition[HIGH] + 1);
1385 }
1386 }
1387
1388 static int
FindTileTriangle(HexagonsWidget w,int pI,int pJ,int pK,int rI,int rJ,int rK)1389 FindTileTriangle(HexagonsWidget w, int pI, int pJ, int pK, int rI, int rJ, int rK)
1390 {
1391 int found = TRUE, temp = 0, k = 0, row1 = 0, row2 = 0, pos;
1392
1393 if (rI == rJ) {
1394 if (pI == pJ - 1)
1395 temp = pJ;
1396 else if (pI == pJ + 1)
1397 temp = pI;
1398 else
1399 found = FALSE;
1400 k = pK;
1401 row1 = rI;
1402 row2 = rK;
1403 } else if (rJ == rK) {
1404 if (pJ == pK - 1)
1405 temp = pK;
1406 else if (pJ == pK + 1)
1407 temp = pJ;
1408 else
1409 found = FALSE;
1410 k = pI;
1411 row1 = rJ;
1412 row2 = rI;
1413 } else if (rK == rI) {
1414 if (pK == pI - 1)
1415 temp = pI;
1416 else if (pK == pI + 1)
1417 temp = pK;
1418 else
1419 found = FALSE;
1420 k = pJ;
1421 row1 = rK;
1422 row2 = rJ;
1423 }
1424 if (found == FALSE)
1425 return (0);
1426 pos = -1;
1427 if (row1 == row2 + 1) {
1428 if (row1 <= w->hexagons.size - 1)
1429 pos = temp - w->hexagons.size - row1;
1430 else /* row1 > w->hexagons.size - 1 */
1431 pos = temp - 3 * w->hexagons.size + row1 + 1;
1432 } else if (row1 == row2 - 1) {
1433 if (row1 < w->hexagons.size - 1)
1434 pos = temp + w->hexagons.size + row1;
1435 else /* row1 >= w->hexagons.size - 1 */
1436 pos = temp + 3 * (w->hexagons.size - 1) - row1;
1437 }
1438 if (k == pos)
1439 return (1);
1440 return (0);
1441 }
1442
1443 static int
FindDir(HexagonsWidget w,int posTile,int posSpace,int rowTile,int rowSpace)1444 FindDir(HexagonsWidget w, int posTile, int posSpace, int rowTile, int rowSpace)
1445 {
1446 if (rowTile == rowSpace) {
1447 if (posTile > posSpace)
1448 return LEFT;
1449 else
1450 return RIGHT;
1451 } else if (TrBl(w, posTile, rowTile) == TrBl(w, posSpace, rowSpace)) {
1452 if (posTile > posSpace)
1453 return TR;
1454 else
1455 return BL;
1456 } else {
1457 /* if (TlBr(w, posTile, rowTile) == TlBr(w, posSpace, rowSpace)) */
1458 if (posTile > posSpace)
1459 return TL;
1460 else
1461 return BR;
1462 }
1463 }
1464
1465 static int
FindSpaceType(HexagonsWidget w,int pos1,int pos2,int row1,int row2)1466 FindSpaceType(HexagonsWidget w, int pos1, int pos2, int row1, int row2)
1467 {
1468 if (row1 == row2 && (pos1 == pos2 + 1 || pos1 == pos2 - 1))
1469 return (ROW);
1470 else if (row1 == row2 - 1) {
1471 swap(&row1, &row2);
1472 swap(&pos1, &pos2);
1473 }
1474 if (row1 == row2 + 1) {
1475 if (row1 <= w->hexagons.size - 1) {
1476 if (pos2 == pos1 - w->hexagons.size - row1)
1477 return (TLBR);
1478 else if (pos2 == pos1 - w->hexagons.size - row1 + 1)
1479 return (TRBL);
1480 } else { /* row1 > w->hexagons.size - 1 */
1481 if (pos2 == pos1 - 3 * w->hexagons.size + row1 + 1)
1482 return (TLBR);
1483 else if (pos2 == pos1 - 3 * w->hexagons.size + row1 + 2)
1484 return (TRBL);
1485 }
1486 }
1487 return (-1);
1488 }
1489
1490 static void
FindMovableTile(HexagonsWidget w,int pos,int posRow,int spaceType,int side,int * tilePos,int * tileRow)1491 FindMovableTile(HexagonsWidget w, int pos, int posRow, int spaceType, int side, int *tilePos, int *tileRow)
1492 {
1493 switch (spaceType) {
1494 case TRBL:
1495 if (side == HIGH) {
1496 *tileRow = posRow;
1497 *tilePos = pos + 1;
1498 } else { /* side == LOW */
1499 *tileRow = posRow - 1;
1500 *tilePos = (posRow <= w->hexagons.size - 1) ?
1501 pos - w->hexagons.size - posRow :
1502 pos - 3 * w->hexagons.size + posRow + 1;
1503 }
1504 break;
1505 case TLBR:
1506 if (side == HIGH) {
1507 *tileRow = posRow;
1508 *tilePos = pos - 1;
1509 } else { /* side == LOW */
1510 *tileRow = posRow - 1;
1511 *tilePos = (posRow <= w->hexagons.size - 1) ?
1512 pos - w->hexagons.size - posRow + 1 :
1513 pos - 3 * w->hexagons.size + posRow + 2;
1514 }
1515 break;
1516 case ROW:
1517 if (side == HIGH) {
1518 *tileRow = posRow + 1;
1519 *tilePos = (posRow < w->hexagons.size - 1) ?
1520 pos + w->hexagons.size + posRow :
1521 pos + 3 * w->hexagons.size - posRow - 3;
1522 } else { /* side == LOW */
1523 *tileRow = posRow - 1;
1524 *tilePos = (posRow <= w->hexagons.size - 1) ?
1525 pos - w->hexagons.size - posRow :
1526 pos - 3 * w->hexagons.size + posRow + 1;
1527 }
1528 break;
1529 default:
1530 (void) printf("FindMovableTile: spaceType %d.\n", spaceType);
1531 }
1532 }
1533
1534 static void
DrawFrame(HexagonsWidget w,GC gc)1535 DrawFrame(HexagonsWidget w, GC gc)
1536 {
1537 int sumX, sumY, sumX4, sum3X4, sumY2, offsetX, offsetY;
1538
1539 sumX = w->hexagons.size * (2 * w->hexagons.offset.x) -
1540 w->hexagons.tileSize.x / 2 - 2 * w->hexagons.delta.x - 1;
1541 sumY = w->hexagons.size * (3 * w->hexagons.tileSize.y + 2 *
1542 w->hexagons.delta.y) - w->hexagons.tileSize.y - 1;
1543 offsetX = w->hexagons.puzzleOffset.x - 1;
1544 offsetY = w->hexagons.puzzleOffset.y;
1545 sumX4 = sumX / 4 + offsetX;
1546 sum3X4 = 3 * sumX / 4 + offsetX + 2;
1547 sumY2 = sumY / 2 + offsetY;
1548 sumX += offsetX + 1 + w->hexagons.size / 2;
1549 sumY += offsetY;
1550 offsetX += 1 - w->hexagons.size / 2;
1551 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1552 sumX4, offsetY, sum3X4, offsetY);
1553 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1554 sum3X4, offsetY, sumX, sumY2);
1555 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1556 sumX, sumY2, sum3X4, sumY);
1557 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1558 sum3X4, sumY, sumX4, sumY);
1559 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1560 sumX4, sumY, offsetX, sumY2);
1561 XDrawLine(XtDisplay(w), XtWindow(w), gc,
1562 offsetX, sumY2, sumX4, offsetY);
1563 }
1564
1565 void
DrawAllTiles(HexagonsWidget w)1566 DrawAllTiles(HexagonsWidget w)
1567 {
1568 int k;
1569
1570 for (k = 0; k < w->hexagons.sizeSize; k++)
1571 DrawTile(w, k, (w->hexagons.tileOfPosition[k] <= 0), (w->hexagons.tileOfPosition[k] <= 0), False);
1572 }
1573
1574 static void
DrawTile(HexagonsWidget w,int pos,Boolean blank,Boolean erase,int offset)1575 DrawTile(HexagonsWidget w, int pos, Boolean blank, Boolean erase, int offset)
1576 {
1577 int dx, dy, k = Row(w, pos), orient = (w->hexagons.corners) ? 1 : 0;
1578 GC tileGC, borderGC;
1579
1580 if (erase) {
1581 tileGC = w->hexagons.inverseGC;
1582 borderGC = w->hexagons.inverseGC;
1583 } else if (offset) {
1584 tileGC = w->hexagons.borderGC;
1585 borderGC = w->hexagons.tileGC;
1586 } else {
1587 tileGC = w->hexagons.tileGC;
1588 borderGC = w->hexagons.borderGC;
1589 }
1590 dx = w->hexagons.tileSize.x / 4 - 1 + (2 * TrBl(w, pos, k) +
1591 w->hexagons.size - k) * w->hexagons.offset.x / 2 +
1592 w->hexagons.puzzleOffset.x + offset;
1593 dy = k * (3 * w->hexagons.tileSize.y / 2 + w->hexagons.delta.y) +
1594 w->hexagons.delta.y - 1 + w->hexagons.puzzleOffset.y + offset;
1595 if (orient) {
1596 hexagonList[orient][0].x = dx;
1597 hexagonList[orient][0].y = dy;
1598 } else {
1599 hexagonList[orient][0].x = dx - w->hexagons.offset.x / 4;
1600 hexagonList[orient][0].y = dy +
1601 (w->hexagons.tileSize.y + w->hexagons.delta.y) / 4;
1602 }
1603 XFillPolygon(XtDisplay(w), XtWindow(w), tileGC, hexagonList[orient], 6,
1604 Convex, CoordModePrevious);
1605 XDrawLines(XtDisplay(w), XtWindow(w), borderGC, hexagonList[orient], 7,
1606 CoordModePrevious);
1607 if (!blank) {
1608 int i = 0, offsetX = 0;
1609 int tile = w->hexagons.tileOfPosition[pos];
1610 char buf[5];
1611
1612 (void) int2String(buf, tile, w->hexagons.base);
1613 while (tile >= 1) {
1614 tile /= w->hexagons.base;
1615 offsetX += w->hexagons.digitOffset.x;
1616 i++;
1617 }
1618 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
1619 dx - offsetX,
1620 dy + w->hexagons.tileSize.y + w->hexagons.digitOffset.y, buf, i);
1621 }
1622 }
1623
1624 #ifdef DEBUG
1625 static int
PositionInRow(w,position,posRow)1626 PositionInRow(w, position, posRow)
1627 HexagonsWidget w;
1628 int position, posRow;
1629 {
1630 return (posRow <= w->hexagons.size - 1) ?
1631 (position - w->hexagons.size * posRow - posRow * (posRow - 1) / 2) :
1632 (position - w->hexagons.size * (posRow - w->hexagons.size) -
1633 4 * w->hexagons.size * (w->hexagons.size - 1) / 2 + (2 *
1634 w->hexagons.size - posRow - 2) * (2 * w->hexagons.size - posRow - 1) /
1635 2 - 1);
1636 }
1637 #endif
1638
1639 static int
PositionFromRow(HexagonsWidget w,int rowPosition,int posRow)1640 PositionFromRow(HexagonsWidget w, int rowPosition, int posRow)
1641 {
1642 return (posRow <= w->hexagons.size - 1) ?
1643 (w->hexagons.size * posRow + posRow * (posRow - 1) / 2 + rowPosition) :
1644 (w->hexagons.size * (posRow - w->hexagons.size) + 4 *
1645 w->hexagons.size * (w->hexagons.size - 1) / 2 - (2 * w->hexagons.size -
1646 posRow - 2) * (2 * w->hexagons.size - posRow - 1) / 2 + 1 + rowPosition);
1647 }
1648
1649 int
Row(HexagonsWidget w,int pos)1650 Row(HexagonsWidget w, int pos)
1651 {
1652 return (pos <= w->hexagons.sizeCenter) ?
1653 (1 + Sqrt(1 + 8 * (pos + w->hexagons.size *
1654 (w->hexagons.size - 1) / 2))) / 2 - w->hexagons.size :
1655 3 * w->hexagons.size - 2 - (1 + Sqrt(1 + 8 * (w->hexagons.sizeSize - 1 +
1656 w->hexagons.size * (w->hexagons.size - 1) / 2 - pos))) / 2;
1657 }
1658
1659 /* Passing row so there is no sqrt calculation again */
1660 int
TrBl(HexagonsWidget w,int pos,int posRow)1661 TrBl(HexagonsWidget w, int pos, int posRow)
1662 {
1663 return (pos <= w->hexagons.sizeCenter) ?
1664 (pos + w->hexagons.size * (w->hexagons.size - 1) / 2) -
1665 (posRow + w->hexagons.size) * (posRow + w->hexagons.size - 1) / 2 :
1666 2 * w->hexagons.size - 2 - (w->hexagons.sizeSize - 1 +
1667 w->hexagons.size * (w->hexagons.size - 1) / 2 - pos -
1668 (3 * w->hexagons.size - posRow - 2) * (3 * w->hexagons.size - posRow - 3) /
1669 2);
1670 }
1671
1672 int
TlBr(HexagonsWidget w,int pos,int posRow)1673 TlBr(HexagonsWidget w, int pos, int posRow)
1674 {
1675 return (pos <= w->hexagons.sizeCenter) ?
1676 -1 - ((pos + w->hexagons.size * (w->hexagons.size - 1) / 2) -
1677 (posRow + w->hexagons.size + 1) * (posRow + w->hexagons.size) / 2) :
1678 2 * w->hexagons.size - 1 + (w->hexagons.sizeSize - 1 +
1679 w->hexagons.size * (w->hexagons.size - 1) / 2 - pos -
1680 (3 * w->hexagons.size - posRow - 1) * (3 * w->hexagons.size - posRow - 2) /
1681 2);
1682 }
1683
1684 /* This is fast for small i, a -1 is returned for negative i. */
1685 static int
Sqrt(int i)1686 Sqrt(int i)
1687 {
1688 int j = 0;
1689
1690 while (j * j <= i)
1691 j++;
1692 return (j - 1);
1693 }
1694
1695 static int
int2String(char * buf,int number,int base)1696 int2String(char *buf, int number, int base)
1697 {
1698 int digit, mult = base, last, position;
1699
1700 if (number < 0) {
1701 (void) printf("number %d < 0\n", number);
1702 return 0;
1703 }
1704 last = 1;
1705 while (number >= mult) {
1706 last++;
1707 mult *= base;
1708 }
1709 for (position = 0; position < last; position++) {
1710 mult /= base;
1711 digit = number / mult;
1712 number -= digit * mult;
1713 buf[position] = digit + '0';
1714 if (buf[position] > '9') { /* ASCII */
1715 buf[position] += ('A' - '9' - 1);
1716 } else if (buf[position] < '0') { /* EBCDIC */
1717 buf[position] += ('A' - '9' - 1);
1718 if (buf[position] > 'I')
1719 buf[position] += ('J' - 'I' - 1);
1720 if (buf[position] > 'R')
1721 buf[position] += ('S' - 'R' - 1);
1722 }
1723 }
1724 buf[last] = '\0';
1725 return last;
1726 }
1727
1728 static void
swap(int * a,int * b)1729 swap(int *a, int *b)
1730 {
1731 int c;
1732
1733 c = *b;
1734 *b = *a;
1735 *a = c;
1736 }
1737
1738 Boolean
CheckSolved(HexagonsWidget w)1739 CheckSolved(HexagonsWidget w)
1740 {
1741 int i;
1742
1743 for (i = 1; i < w->hexagons.sizeSize - ((w->hexagons.corners) ? 1 : 0); i++)
1744 if (w->hexagons.tileOfPosition[i - 1] != i)
1745 return FALSE;
1746 return TRUE;
1747 }
1748