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