forgotten commit. disabled until egl is adapted.
[AROS-Contrib.git] / fish / mosaic / mosaic.c
blob6f23964b3cfb240bcb6ba3dfb0ecee5ffcb47029
1 /*
2 *
3 mosaic.c
4 * X version by kirk johnson october 1990
5 * Amiga version by Loren J. Rittle Sun Feb 24 06:17:30 1991
6 * Aris, this ones for you...
7 * ...when do I get my pizza :-)
9 * It only took 4-5 hours to port from X, I did it on a dare!
10 * No Copyright N© 1991 Loren J. Rittle. No rights reserved.
11 * Some code generated via PowerWindows 2.5.
12 * I also used their PD event shell as a starting point.
14 * Original UseNet post header:
15 * Path: news.larc.nasa.gov!elroy.jpl.nasa.gov!usc!cs.utexas.edu!sun-barr!newstop!exodus!kanchenjunga.LCS.MIT.EDU
16 * From: tuna@kanchenjunga.LCS.MIT.EDU (Kirk 'UhOh' Johnson)
17 * Newsgroups: comp.sources.x
18 * Subject: v11i083: mosaic, Part01/01
19 * Message-ID: <8101@exodus.Eng.Sun.COM>
20 * Date: 17 Feb 91 19:12:47 GMT
21 * Sender: news@exodus.Eng.Sun.COM
22 * Lines: 2409
23 * Approved: argv@sun.com
25 * Submitted-by: tuna@kanchenjunga.LCS.MIT.EDU (Kirk 'UhOh' Johnson)
26 * Posting-number: Volume 11, Issue 83
27 * Archive-name: mosaic/part01
29 * Thanks to Kirk for releasing such a nice simple game program with source...
30 * Hard Drive Installable and Multitasks, thus better than any psygnosis game...
33 #include <aros/oldprograms.h>
34 #include <exec/types.h>
35 #include <exec/io.h>
36 #include <exec/memory.h>
37 #include <libraries/dos.h>
38 #include <intuition/intuition.h>
39 #include <graphics/gfxmacros.h>
40 #include <stdlib.h>
41 #include <time.h>
42 #include <math.h>
43 #include <string.h>
44 #include "mosaic.h"
46 struct IntuitionBase *IntuitionBase = NULL;
47 struct GfxBase *GfxBase = NULL;
49 SHORT BorderVectors1[] =
51 0, 0,
52 65, 0,
53 65, 25,
54 0, 25,
55 0, 0
58 struct Border Border1 =
60 -1, -1,
61 3, 0, JAM1,
63 BorderVectors1,
64 NULL
67 struct IntuiText IText1 =
69 3, 0, JAM2,
70 5, 7,
71 NULL,
72 "Restart",
73 NULL
76 struct Gadget Gadget1 =
78 NULL,
79 366, 107,
80 64, 24,
82 RELVERIFY,
83 BOOLGADGET,
84 (APTR) & Border1,
85 NULL,
86 &IText1,
88 NULL,
90 NULL
93 struct IntuiText IText2 =
95 3, 0, JAM2,
96 366, 138,
97 NULL,
98 "Next:",
99 NULL
102 struct NewWindow NewWindowStructure1 =
104 20, 10,
105 440, 188,
106 0, 1,
107 MOUSEBUTTONS + MOUSEMOVE + GADGETUP + CLOSEWINDOW + RAWKEY,
108 WINDOWDRAG + WINDOWDEPTH + REPORTMOUSE + WINDOWCLOSE + ACTIVATE + NOCAREREFRESH,
109 &Gadget1,
110 NULL,
111 "Mosaic, Amiga Version by Loren J. Rittle\0Sun Feb 24 04:36:18 1991",
112 NULL,
113 NULL,
114 450, 188,
115 450, 188,
116 WBENCHSCREEN
119 struct NewWindow NewWindowStructure2 =
121 465, 10,
122 170, 120,
123 0, 1,
125 WINDOWDRAG + WINDOWDEPTH + NOCAREREFRESH,
126 NULL,
127 NULL,
128 "Mosaic Score",
129 NULL,
130 NULL,
131 450, 188,
132 450, 188,
133 WBENCHSCREEN
136 char *ScoreFile = "mosaic.scores";
138 Word tile[NTiles]; /* the board */
139 Word piece[NPieces]; /* the "deck" of pieces */
140 Word nextpiece; /* index into the deck */
142 Word size[NTiles]; /* score data structures */
143 Word parent[NTiles];
145 Word tscore[3]; /* total score */
146 Word pscore[3]; /* last piece score */
147 Word remain[3]; /* tiles remaining */
149 static char buf[256];
151 NameAndScore highscore[NHighScores];
153 int highlitX = 0;
154 int highlitY = 0;
156 int highlitXonDown;
157 int highlitYonDown;
159 BPTR SpeakFH = BNULL;
161 struct Window *wG = NULL;
162 struct RastPort *rpG;
164 struct Window *wS = NULL;
165 struct RastPort *rpS;
167 #define BoundVarVal(var, min, max) \
169 if ((var) < (min)) \
170 (var) = (min); \
171 else if ((var) > (max)) \
172 (var) = (max); \
175 UWORD backfill[8] =
176 {0x1111, 0x4444, 0x1111, 0x4444, 0x1111, 0x4444, 0x1111, 0x4444};
178 UWORD solid[8] =
179 {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
181 int main (int argc, char **argv)
183 UWORD code;
184 ULONG class;
185 APTR object;
186 int MouseX, MouseY;
187 int x, y;
189 struct IntuiMessage *message;
191 IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library", 0);
192 GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0);
193 if (!IntuitionBase || !GfxBase)
194 fatal ("Can't open Intuition and/or Graphics Library.");
196 wG = OpenWindow (&NewWindowStructure1);
197 if (wG == NULL)
198 fatal ("Can't open a window.");
199 rpG = wG->RPort;
201 wS = OpenWindow (&NewWindowStructure2);
202 if (wS == NULL)
203 fatal ("Can't open a window.");
204 rpS = wS->RPort;
207 /* struct Process* proc = (struct Process *)FindTask(0L); */
208 /* APTR temp = proc->pr_WindowPtr; */
210 /* proc->pr_WindowPtr = (APTR)-1L; */
211 SpeakFH = Open ("speak:", MODE_NEWFILE);
212 /* proc->pr_WindowPtr = temp; */
216 PrintIText (rpG, &IText2, 0, 0);
218 ReadHighScores ();
220 restart:
221 InitGame ();
222 drawScore ();
223 SetAPen (rpG, 2);
224 SetAfPt (rpG, (void *) backfill, 3);
225 RectFill (rpG, 20, 14, 24 * 14 + 20, 24 * 7 + 14);
227 SetAPen (rpG, 3);
228 for (x = 0; x < 25; x++)
230 Move (rpG, x * 14 + 20, 14);
231 Draw (rpG, x * 14 + 20, 24 * 7 + 14);
234 for (y = 0; y < 25; y++)
236 Move (rpG, 20, y * 7 + 14);
237 Draw (rpG, 24 * 14 + 20, y * 7 + 14);
240 while (1)
242 WaitPort (wG->UserPort);
243 while ((message = (struct IntuiMessage *) GetMsg (wG->UserPort)) != NULL)
245 code = message->Code;
246 object = message->IAddress;
247 class = message->Class;
248 MouseX = message->MouseX;
249 MouseY = message->MouseY;
250 ReplyMsg ((struct Message *) message);
251 if (class == CLOSEWINDOW)
252 QuitGame (0);
254 * This is very kludgy, don't follow this example of how to read
255 * keys... This is a quick hack to allow the 'a' for auto play
256 * feature to work. Try it, you may hate it! Because, the
257 * AutoPlay() function is not too smart. LJR
259 if ((class == RAWKEY) && (code == 32))
260 AutoPlay ();
261 /* Here again, quick hack to support open/closing of
262 * score window via 's'. LJR
264 if ((class == RAWKEY) && (code == 33))
266 if (wS == NULL)
268 wS = OpenWindow (&NewWindowStructure2);
269 if (wS == NULL)
270 fatal ("Can't open a window.");
271 rpS = wS->RPort;
272 drawScore ();
274 else
276 CloseWindow(wS);
277 wS = NULL;
280 if (class == MOUSEMOVE)
281 MoveBox (MouseX, MouseY);
282 if (class == MOUSEBUTTONS) {
283 if (code & 0x0080)
285 if ((highlitXonDown == highlitX) &&
286 (highlitYonDown == highlitY))
288 if ((nextpiece < NPieces) &&
289 (DropPiece (highlitY, highlitX, piece[nextpiece])))
291 nextpiece += 1;
292 drawNext ();
294 if (nextpiece == NPieces)
296 MoveBox (-1, -1);
297 CheckHighScore ();
300 else
301 if (SpeakFH)
302 Write (SpeakFH, "No Way!", 7);
303 else
304 /* DisplayBeep (NULL) */;
306 else
307 if (SpeakFH)
308 Write (SpeakFH, "Un-do!", 7);
309 else
310 /* DisplayBeep (NULL) */;
312 else
314 highlitXonDown = highlitX;
315 highlitYonDown = highlitY;
318 if ((class == GADGETUP) || (class == GADGETDOWN))
319 if (object == (void *) &Gadget1)
320 goto restart;
326 void
327 MoveBox (int MouseX, int MouseY)
329 int x, y;
330 int newX = (MouseX - 27) / 14;
331 int newY = (MouseY - 17) / 7;
333 BoundVarVal (newX, 0, 22);
334 BoundVarVal (newY, 0, 22);
336 if ((newX == highlitX) && (newY == highlitY))
337 return;
339 SetAPen (rpG, 3);
340 for (x = highlitX; x < highlitX + 3; x++)
342 Move (rpG, x * 14 + 20, highlitY * 7 + 14);
343 Draw (rpG, x * 14 + 20, highlitY * 7 + 14 + 14);
346 for (y = highlitY; y < highlitY + 3; y++)
348 Move (rpG, highlitX * 14 + 20, y * 7 + 14);
349 Draw (rpG, highlitX * 14 + 20 + 28, y * 7 + 14);
352 SetAfPt (rpG, (void *) backfill, 3);
353 SetAPen (rpG, 2);
354 if (!tile[highlitY * BoardSize + highlitX])
355 RectFill (rpG, highlitX * 14 + 21, highlitY * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+1) * 7 + 13);
356 if (!tile[highlitY * BoardSize + highlitX + 1])
357 RectFill (rpG, (highlitX+1) * 14 + 21, highlitY * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+1) * 7 + 13);
358 if (!tile[(highlitY + 1) * BoardSize + highlitX])
359 RectFill (rpG, highlitX * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+2) * 7 + 13);
360 if (!tile[(highlitY + 1) * BoardSize + highlitX + 1])
361 RectFill (rpG, (highlitX+1) * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+2) * 7 + 13);
363 if (nextpiece == NPieces)
365 highlitX = highlitY = 0;
366 return;
368 highlitX = newX;
369 highlitY = newY;
371 SetAPen (rpG, 1);
372 for (x = highlitX; x < highlitX + 3; x++)
374 Move (rpG, x * 14 + 20, highlitY * 7 + 14);
375 Draw (rpG, x * 14 + 20, highlitY * 7 + 14 + 14);
378 for (y = highlitY; y < highlitY + 3; y++)
380 Move (rpG, highlitX * 14 + 20, y * 7 + 14);
381 Draw (rpG, highlitX * 14 + 20 + 28, y * 7 + 14);
384 SetAfPt (rpG, (void *) solid, 3);
385 if (!tile[highlitY * BoardSize + highlitX])
387 SetAPen (rpG, piece[nextpiece] & 0x0003);
388 RectFill (rpG, highlitX * 14 + 21, highlitY * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+1) * 7 + 13);
390 if (!tile[highlitY * BoardSize + highlitX + 1])
392 SetAPen (rpG, (piece[nextpiece] & 0x000C)>>2);
393 RectFill (rpG, (highlitX+1) * 14 + 21, highlitY * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+1) * 7 + 13);
395 if (!tile[(highlitY + 1) * BoardSize + highlitX])
397 SetAPen (rpG, (piece[nextpiece] & 0x0030)>>4);
398 RectFill (rpG, highlitX * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+2) * 7 + 13);
400 if (!tile[(highlitY + 1) * BoardSize + highlitX + 1])
402 SetAPen (rpG, (piece[nextpiece] & 0x00C0)>>6);
403 RectFill (rpG, (highlitX+1) * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+2) * 7 + 13);
407 void
408 QuitGame (int rc)
410 if (wG)
411 CloseWindow (wG);
412 if (wS)
413 CloseWindow (wS);
414 if (SpeakFH)
415 Close (SpeakFH);
416 if (GfxBase != NULL)
417 CloseLibrary ((struct Library *)GfxBase);
418 if (IntuitionBase != NULL)
419 CloseLibrary ((struct Library *)IntuitionBase);
420 exit (0);
423 void
424 warning (char *msg)
426 fflush (stdout);
427 fprintf (stderr, "%s: warning! %s\n", AppName, msg);
428 fflush (stderr);
431 void
432 fatal (char *msg)
434 fflush (stdout);
435 fprintf (stderr, "%s: %s\n", AppName, msg);
436 QuitGame (1);
439 void
440 ReadHighScores (void)
442 int i;
443 FILE *s;
445 s = fopen (ScoreFile, "r");
446 if (s == NULL)
448 warning ("unable to open score file; creating new one");
450 for (i = 0; i < NHighScores; i++)
452 strcpy (highscore[i].uname, ".");
453 highscore[i].score = -1;
456 WriteHighScores ();
458 else
460 for (i = 0; i < NHighScores; i++)
462 fgets (buf, 30, s);
463 if (sscanf (buf, "%s %d",
464 highscore[i].uname, &highscore[i].score) != 2)
465 fatal ("incomplete score file read");
467 fclose (s);
472 void
473 WriteHighScores (void)
475 int i;
476 FILE *s;
478 s = fopen (ScoreFile, "w");
479 if (s == NULL)
480 fatal ("unable to open score file");
482 for (i = 0; i < NHighScores; i++)
483 fprintf (s, "%s %d\n", highscore[i].uname, highscore[i].score);
485 fclose (s);
488 void
489 CheckHighScore (void)
491 int i;
492 int score;
493 char *uname;
495 uname = NULL /* getenv ("USERNAME") */;
496 if (uname == NULL)
497 uname = "Unknown_Puzzle_Solver";
498 score = tscore[0] + tscore[1] + tscore[2];
501 * note that we don't actually try to do any locking of the high score
502 * file during this critical section ...
505 ReadHighScores ();
507 for (i = 0; i < NHighScores; i++)
508 if (strcmp (highscore[i].uname, uname) == 0)
509 break;
511 if (i == NHighScores)
512 i = NHighScores - 1;
514 if (score > highscore[i].score)
516 while ((i > 0) && (score > highscore[i - 1].score))
518 strcpy (highscore[i].uname, highscore[i - 1].uname);
519 highscore[i].score = highscore[i - 1].score;
520 i -= 1;
522 strcpy (highscore[i].uname, uname);
523 highscore[i].score = score;
525 WriteHighScores ();
527 if (SpeakFH)
529 Write (SpeakFH, "Congratulations!", 16);
530 Write (SpeakFH, "You got a hi score.", 19);
532 else
533 /* DisplayBeep (NULL) */;
535 drawHighScores ();
538 void
539 AutoPlay (void)
541 int r, c;
543 while (nextpiece < NPieces)
547 r = rand () % (BoardSize - 1);
548 c = rand () % (BoardSize - 1);
550 while (!DropPiece (r, c, piece[nextpiece]));
552 nextpiece += 1;
553 drawNext ();
555 if (nextpiece == NPieces)
557 MoveBox (-1, -1);
558 CheckHighScore ();
563 void
564 UpdateAndScore (int r, int c, Word score[])
566 int i;
568 i = r * BoardSize + c;
570 PossiblyMerge (i, i + 1);
571 PossiblyMerge (i + BoardSize, i + BoardSize + 1);
573 PossiblyMerge (i, i + BoardSize);
574 PossiblyMerge (i + 1, i + BoardSize + 1);
576 if (c >= 1)
578 PossiblyMerge (i, i - 1);
579 PossiblyMerge (i + BoardSize, i + BoardSize - 1);
581 if (r >= 1)
583 PossiblyMerge (i, i - BoardSize);
584 PossiblyMerge (i + 1, i - BoardSize + 1);
586 if (c <= (BoardSize - 3))
588 PossiblyMerge (i + 1, i + 2);
589 PossiblyMerge (i + BoardSize + 1, i + BoardSize + 2);
591 if (r <= (BoardSize - 3))
593 PossiblyMerge (i + BoardSize, i + (2 * BoardSize));
594 PossiblyMerge (i + BoardSize + 1, i + (2 * BoardSize) + 1);
596 /* compute the new score */
597 for (i = 0; i < 3; i++)
598 score[i] = 0;
599 for (i = 0; i < NTiles; i++)
600 if ((tile[i] != 0) && (parent[i] == i))
601 score[tile[i] - 1] += size[i] * size[i];
604 void
605 PossiblyMerge (int i, int j)
607 Word irep;
608 Word jrep;
609 Word scan;
611 /* tiles are not the same color */
612 if (tile[i] != tile[j])
613 return;
615 /* find i's rep */
616 irep = i;
617 while (parent[irep] != irep)
618 irep = parent[irep];
620 /* compress path from i to irep */
621 scan = i;
622 while (parent[scan] != scan)
624 scan = parent[scan];
625 parent[scan] = irep;
628 /* find j's rep */
629 jrep = j;
630 while (parent[jrep] != jrep)
631 jrep = parent[jrep];
633 /* compress path from j to jrep */
634 scan = j;
635 while (parent[scan] != scan)
637 scan = parent[scan];
638 parent[scan] = jrep;
641 /* tiles are already in the same set */
642 if (irep == jrep)
643 return;
645 /* merge the sets */
646 if (size[irep] > size[jrep])
648 parent[jrep] = irep;
649 size[irep] += size[jrep];
651 else
653 parent[irep] = jrep;
654 size[jrep] += size[irep];
659 DropPiece (int r, int c, Word p)
661 int idx;
662 Word type;
663 Word nscore[3];
665 idx = r * BoardSize + c;
667 /* check for illegal move */
668 if ((tile[idx] != 0) ||
669 (tile[idx + 1] != 0) ||
670 (tile[idx + BoardSize] != 0) ||
671 (tile[idx + BoardSize + 1] != 0))
672 return 0;
674 /* place the piece */
675 type = p & 0x03;
676 tile[idx] = type;
677 remain[type - 1] -= 1;
678 p >>= 2;
680 type = p & 0x03;
681 tile[idx + 1] = type;
682 remain[type - 1] -= 1;
683 p >>= 2;
685 type = p & 0x03;
686 tile[idx + BoardSize] = type;
687 remain[type - 1] -= 1;
688 p >>= 2;
690 type = p & 0x03;
691 tile[idx + BoardSize + 1] = p & 0x03;
692 remain[type - 1] -= 1;
694 /* update the score */
695 UpdateAndScore (r, c, nscore);
696 for (idx = 0; idx < 3; idx++)
698 pscore[idx] = nscore[idx] - tscore[idx];
699 tscore[idx] = nscore[idx];
702 /* redraw */
703 drawTile (r++, c);
704 drawTile (r, c++);
705 drawTile (r--, c);
706 drawTile (r, c);
707 drawScore ();
709 return 1;
712 void
713 InitGame (void)
715 int i, j, k, l;
716 int idx, swap;
718 /* randomize */
719 srand ((int) time (NULL));
721 /* clear the board */
722 for (i = 0; i < NTiles; i++)
723 tile[i] = 0;
725 /* set up deck */
726 idx = 0;
727 for (i = 1; i <= 3; i++)
728 for (j = 1; j <= 3; j++)
729 for (k = 1; k <= 3; k++)
730 for (l = 1; l <= 3; l++)
731 piece[idx++] = (i << 6) | (j << 4) | (k << 2) | (l << 0);
733 /* shuffle */
734 for (i = 0; i < 1000; i++)
736 idx = rand () % NPieces;
737 swap = piece[idx];
738 piece[idx] = piece[0];
739 piece[0] = swap;
741 nextpiece = 0;
743 /* clear score data structures */
744 for (i = 0; i < NTiles; i++)
746 size[i] = 1;
747 parent[i] = i;
750 for (i = 0; i < 3; i++)
752 tscore[i] = 0;
753 pscore[i] = 0;
754 remain[i] = (NPieces * 4) / 3;
756 drawNext ();
759 void
760 drawTile (int r, int c)
762 int x, y;
764 x = c * 14 + 20;
765 y = r * 7 + 14;
767 SetAfPt (rpG, (void *) solid, 3);
768 SetAPen (rpG, tile[r * BoardSize + c]);
769 RectFill (rpG, x + 1, y + 1, x + 13, y + 6);
772 void
773 drawHighScores (void)
775 int i;
777 SetAPen (rpG, 1);
778 for (i = 0; i < NHighScores; i++)
779 if (highscore[i].score > 0)
781 sprintf (buf, "%-24s %5d", highscore[i].uname, highscore[i].score);
782 Move (rpG, 50, 30 + i * 14);
783 Text (rpG, buf, strlen (buf));
787 void
788 drawNext (void)
790 int p = (nextpiece < NPieces) ? piece[nextpiece] : 0;
791 int x = 26 * 14 + 20;
792 int y = 20 * 7 + 14;
794 SetAfPt (rpG, (void *) solid, 3);
795 SetAPen (rpG, p & 0x03);
796 RectFill (rpG, x + 1, y + 1, x + 13, y + 6);
797 p >>= 2;
798 SetAPen (rpG, p & 0x03);
799 RectFill (rpG, x + 15, y + 1, x + 27, y + 6);
800 p >>= 2;
801 SetAPen (rpG, p & 0x03);
802 RectFill (rpG, x + 1, y + 8, x + 13, y + 13);
803 p >>= 2;
804 SetAPen (rpG, p & 0x03);
805 RectFill (rpG, x + 15, y + 8, x + 27, y + 13);
808 void
809 drawScore (void)
811 int i, total;
813 if (!wS)
814 return;
816 SetAPen(rpS, 3);
817 Move (rpS, 10, 20);
818 Text (rpS, "to play:", 8);
820 Move (rpS, 10, 30);
821 for (i = 0; i < 3; i++)
823 SetAPen(rpS, i+1);
824 sprintf (buf, "%5d ", remain[i]);
825 Text (rpS, buf, strlen (buf));
828 SetAPen(rpS, 3);
829 Move (rpS, 10, 50);
830 Text (rpS, "total:", 6);
832 total = 0;
833 Move (rpS, 10, 60);
834 for (i = 0; i < 3; i++)
836 SetAPen(rpS, i+1);
837 total += tscore[i];
838 sprintf (buf, "%5d ", tscore[i]);
839 Text (rpS, buf, strlen (buf));
842 SetAPen(rpS, 3);
843 sprintf (buf, "%5d", total);
844 Move (rpS, 10, 70);
845 Text (rpS, buf, strlen (buf));
847 Move (rpS, 10, 90);
848 Text (rpS, "piece:", 6);
850 total = 0;
851 Move (rpS, 10, 100);
852 for (i = 0; i < 3; i++)
854 SetAPen(rpS, i+1);
855 total += pscore[i];
856 sprintf (buf, "%5d ", pscore[i]);
857 Text (rpS, buf, strlen (buf));
860 SetAPen(rpS, 3);
861 sprintf (buf, "%5d", total);
862 Move (rpS, 10, 110);
863 Text (rpS, buf, strlen (buf));