ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-1.25.tar.Z
[xscreensaver] / hacks / maze.c
1 /******************************************************************************
2  * [ maze ] ...
3  *
4  * modified:  [ 3-7-93 ]  Jamie Zawinski <jwz@mcom.com>
5  *              added the XRoger logo, cleaned up resources, made
6  *              grid size a parameter.
7  * modified:  [ 3-3-93 ]  Jim Randell <jmr@mddjmr.fc.hp.com>
8  *              Added the colour stuff and integrated it with jwz's
9  *              screenhack stuff.  There's still some work that could
10  *              be done on this, particularly allowing a resource to
11  *              specify how big the squares are.
12  * modified:  [ 10-4-88 ]  Richard Hess    ...!uunet!cimshop!rhess  
13  *              [ Revised primary execution loop within main()...
14  *              [ Extended X event handler, check_events()...
15  * modified:  [ 1-29-88 ]  Dave Lemke      lemke@sun.com  
16  *              [ Hacked for X11...
17  *              [  Note the word "hacked" -- this is extremely ugly, but at 
18  *              [   least it does the job.  NOT a good programming example 
19  *              [   for X.
20  * original:  [ 6/21/85 ]  Martin Weiss    Sun Microsystems  [ SunView ]
21  *
22  ******************************************************************************
23  Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
24   
25  All Rights Reserved
26   
27  Permission to use, copy, modify, and distribute this software and its
28  documentation for any purpose and without fee is hereby granted, 
29  provided that the above copyright notice appear in all copies and that
30  both that copyright notice and this permission notice appear in 
31  supporting documentation, and that the names of Sun or MIT not be
32  used in advertising or publicity pertaining to distribution of the
33  software without specific prior written permission. Sun and M.I.T. 
34  make no representations about the suitability of this software for 
35  any purpose. It is provided "as is" without any express or implied warranty.
36  
37  SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT
40  OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
41  OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
42  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
43  OR PERFORMANCE OF THIS SOFTWARE.
44  *****************************************************************************/
45
46 #include "screenhack.h"
47
48 #define XROGER
49
50 static int solve_delay, pre_solve_delay, post_solve_delay;
51
52 #include  <stdio.h>
53 #include  <X11/Xlib.h>
54 #include  <X11/Xutil.h>
55 #include  <X11/bitmaps/gray1>
56
57 #define MAX_MAZE_SIZE_X 500
58 #define MAX_MAZE_SIZE_Y 500
59
60 #define MOVE_LIST_SIZE  (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
61
62 #define WALL_TOP        0x8000
63 #define WALL_RIGHT      0x4000
64 #define WALL_BOTTOM     0x2000
65 #define WALL_LEFT       0x1000
66
67 #define DOOR_IN_TOP     0x800
68 #define DOOR_IN_RIGHT   0x400
69 #define DOOR_IN_BOTTOM  0x200
70 #define DOOR_IN_LEFT    0x100
71 #define DOOR_IN_ANY     0xF00
72
73 #define DOOR_OUT_TOP    0x80
74 #define DOOR_OUT_RIGHT  0x40
75 #define DOOR_OUT_BOTTOM 0x20
76 #define DOOR_OUT_LEFT   0x10
77
78 #define START_SQUARE    0x2
79 #define END_SQUARE      0x1
80
81 #define border_x        (0)
82 #define border_y        (0)
83
84 #define get_random(x)   (random() % (x))
85   
86 static int logo_x, logo_y;
87
88 #ifdef XROGER
89 # define logo_width  128
90 # define logo_height 128
91 #else
92 # include  <X11/bitmaps/xlogo64>
93 # define logo_width xlogo64_width
94 # define logo_height xlogo64_height
95 # define logo_bits xlogo64_bits
96 #endif
97
98 static unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
99
100 static struct {
101   unsigned char x;
102   unsigned char y;
103   unsigned char dir;
104 } move_list[MOVE_LIST_SIZE], save_path[MOVE_LIST_SIZE], path[MOVE_LIST_SIZE];
105
106 static int maze_size_x, maze_size_y;
107 static int sqnum, cur_sq_x, cur_sq_y, path_length;
108 static int start_x, start_y, start_dir, end_x, end_y, end_dir;
109 static int grid_width, grid_height;
110
111 static Display  *dpy;
112 static Window   win;
113 static GC       gc, cgc, tgc, logo_gc;
114 static Pixmap   logo_map;
115
116 static int      x = 0, y = 0, restart = 0, stop = 1, state = 1;
117
118 static int
119 check_events()                                  /* X event handler [ rhess ] */
120 {
121   XEvent        e;
122
123   if (XPending(dpy)) {
124     XNextEvent(dpy, &e);
125     switch (e.type) {
126
127     case ButtonPress:
128       switch (e.xbutton.button) {
129       case 3:
130         exit (0);
131         break;
132       case 2:
133         stop = !stop ;
134         if (state == 5) state = 4 ;
135         else {
136           restart = 1;
137           stop = 0;
138         }
139         break;
140       default:
141         restart = 1 ;
142         stop = 0 ;
143         break;
144       }
145       break;
146
147     case ConfigureNotify:
148       restart = 1;
149       break;
150     case UnmapNotify:
151       stop = 1;
152       XClearWindow (dpy, win);
153       XSync (dpy, False);
154       break;
155     case Expose:
156       restart = 1;
157       break;
158     }
159     return(1);
160   }
161   return(0);
162 }
163
164
165 static void
166 set_maze_sizes (width, height)
167      int width, height;
168 {
169   maze_size_x = width / grid_width;
170   maze_size_y = height / grid_height;
171 }
172
173
174 static void
175 initialize_maze()         /* draw the surrounding wall and start/end squares */
176 {
177   register int i, j, wall;
178   
179   /* initialize all squares */
180   for ( i=0; i<maze_size_x; i++) {
181     for ( j=0; j<maze_size_y; j++) {
182       maze[i][j] = 0;
183     }
184   }
185   
186   /* top wall */
187   for ( i=0; i<maze_size_x; i++ ) {
188     maze[i][0] |= WALL_TOP;
189   }
190   
191   /* right wall */
192   for ( j=0; j<maze_size_y; j++ ) {
193     maze[maze_size_x-1][j] |= WALL_RIGHT;
194   }
195   
196   /* bottom wall */
197   for ( i=0; i<maze_size_x; i++ ) {
198     maze[i][maze_size_y-1] |= WALL_BOTTOM;
199   }
200   
201   /* left wall */
202   for ( j=0; j<maze_size_y; j++ ) {
203     maze[0][j] |= WALL_LEFT;
204   }
205   
206   /* set start square */
207   wall = get_random(4);
208   switch (wall) {
209   case 0:       
210     i = get_random(maze_size_x);
211     j = 0;
212     break;
213   case 1:       
214     i = maze_size_x - 1;
215     j = get_random(maze_size_y);
216     break;
217   case 2:       
218     i = get_random(maze_size_x);
219     j = maze_size_y - 1;
220     break;
221   case 3:       
222     i = 0;
223     j = get_random(maze_size_y);
224     break;
225   }
226   maze[i][j] |= START_SQUARE;
227   maze[i][j] |= ( DOOR_IN_TOP >> wall );
228   maze[i][j] &= ~( WALL_TOP >> wall );
229   cur_sq_x = i;
230   cur_sq_y = j;
231   start_x = i;
232   start_y = j;
233   start_dir = wall;
234   sqnum = 0;
235   
236   /* set end square */
237   wall = (wall + 2)%4;
238   switch (wall) {
239   case 0:
240     i = get_random(maze_size_x);
241     j = 0;
242     break;
243   case 1:
244     i = maze_size_x - 1;
245     j = get_random(maze_size_y);
246     break;
247   case 2:
248     i = get_random(maze_size_x);
249     j = maze_size_y - 1;
250     break;
251   case 3:
252     i = 0;
253     j = get_random(maze_size_y);
254     break;
255   }
256   maze[i][j] |= END_SQUARE;
257   maze[i][j] |= ( DOOR_OUT_TOP >> wall );
258   maze[i][j] &= ~( WALL_TOP >> wall );
259   end_x = i;
260   end_y = j;
261   end_dir = wall;
262   
263   /* set logo */
264   if ((maze_size_x > 15) && (maze_size_y > 15))
265     {
266       int logow = 1 + logo_width / grid_width;
267       int logoh = 1 + logo_height / grid_height;
268       /* not closer than 3 grid units from a wall */
269       logo_x = get_random (maze_size_x - logow - 6) + 3;
270       logo_y = get_random (maze_size_y - logoh - 6) + 3;
271       for (i=0; i<logow; i++)
272         for (j=0; j<logoh; j++)
273           maze[logo_x + i][logo_y + j] |= DOOR_IN_TOP;
274     }
275   else
276     logo_y = logo_x = -1;
277 }
278
279 static int choose_door ();
280 static int backup ();
281 static void draw_wall ();
282 static void draw_solid_square ();
283 static void enter_square ();
284
285 static void
286 create_maze()             /* create a maze layout given the intiialized maze */
287 {
288   register int i, newdoor;
289   
290   do {
291     move_list[sqnum].x = cur_sq_x;
292     move_list[sqnum].y = cur_sq_y;
293     move_list[sqnum].dir = newdoor;
294     while ( ( newdoor = choose_door() ) == -1 ) { /* pick a door */
295       if ( backup() == -1 ) { /* no more doors ... backup */
296         return; /* done ... return */
297       }
298     }
299     
300     /* mark the out door */
301     maze[cur_sq_x][cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor );
302     
303     switch (newdoor) {
304     case 0: cur_sq_y--;
305       break;
306     case 1: cur_sq_x++;
307       break;
308     case 2: cur_sq_y++;
309       break;
310     case 3: cur_sq_x--;
311       break;
312     }
313     sqnum++;
314     
315     /* mark the in door */
316     maze[cur_sq_x][cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) );
317     
318     /* if end square set path length and save path */
319     if ( maze[cur_sq_x][cur_sq_y] & END_SQUARE ) {
320       path_length = sqnum;
321       for ( i=0; i<path_length; i++) {
322         save_path[i].x = move_list[i].x;
323         save_path[i].y = move_list[i].y;
324         save_path[i].dir = move_list[i].dir;
325       }
326     }
327     
328   } while (1);
329   
330 }
331
332
333 static int
334 choose_door()                                            /* pick a new path */
335 {
336   int candidates[3];
337   register int num_candidates;
338   
339   num_candidates = 0;
340   
341   /* top wall */
342   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_TOP )
343     goto rightwall;
344   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_TOP )
345     goto rightwall;
346   if ( maze[cur_sq_x][cur_sq_y] & WALL_TOP )
347     goto rightwall;
348   if ( maze[cur_sq_x][cur_sq_y - 1] & DOOR_IN_ANY ) {
349     maze[cur_sq_x][cur_sq_y] |= WALL_TOP;
350     maze[cur_sq_x][cur_sq_y - 1] |= WALL_BOTTOM;
351     draw_wall(cur_sq_x, cur_sq_y, 0);
352     goto rightwall;
353   }
354   candidates[num_candidates++] = 0;
355   
356  rightwall:
357   /* right wall */
358   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_RIGHT )
359     goto bottomwall;
360   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_RIGHT )
361     goto bottomwall;
362   if ( maze[cur_sq_x][cur_sq_y] & WALL_RIGHT )
363     goto bottomwall;
364   if ( maze[cur_sq_x + 1][cur_sq_y] & DOOR_IN_ANY ) {
365     maze[cur_sq_x][cur_sq_y] |= WALL_RIGHT;
366     maze[cur_sq_x + 1][cur_sq_y] |= WALL_LEFT;
367     draw_wall(cur_sq_x, cur_sq_y, 1);
368     goto bottomwall;
369   }
370   candidates[num_candidates++] = 1;
371   
372  bottomwall:
373   /* bottom wall */
374   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_BOTTOM )
375     goto leftwall;
376   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_BOTTOM )
377     goto leftwall;
378   if ( maze[cur_sq_x][cur_sq_y] & WALL_BOTTOM )
379     goto leftwall;
380   if ( maze[cur_sq_x][cur_sq_y + 1] & DOOR_IN_ANY ) {
381     maze[cur_sq_x][cur_sq_y] |= WALL_BOTTOM;
382     maze[cur_sq_x][cur_sq_y + 1] |= WALL_TOP;
383     draw_wall(cur_sq_x, cur_sq_y, 2);
384     goto leftwall;
385   }
386   candidates[num_candidates++] = 2;
387   
388  leftwall:
389   /* left wall */
390   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_LEFT )
391     goto donewall;
392   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_LEFT )
393     goto donewall;
394   if ( maze[cur_sq_x][cur_sq_y] & WALL_LEFT )
395     goto donewall;
396   if ( maze[cur_sq_x - 1][cur_sq_y] & DOOR_IN_ANY ) {
397     maze[cur_sq_x][cur_sq_y] |= WALL_LEFT;
398     maze[cur_sq_x - 1][cur_sq_y] |= WALL_RIGHT;
399     draw_wall(cur_sq_x, cur_sq_y, 3);
400     goto donewall;
401   }
402   candidates[num_candidates++] = 3;
403   
404  donewall:
405   if (num_candidates == 0)
406     return ( -1 );
407   if (num_candidates == 1)
408     return ( candidates[0] );
409   return ( candidates[ get_random(num_candidates) ] );
410   
411 }
412
413
414 static int
415 backup()                                                  /* back up a move */
416 {
417   sqnum--;
418   cur_sq_x = move_list[sqnum].x;
419   cur_sq_y = move_list[sqnum].y;
420   return ( sqnum );
421 }
422
423
424 static void
425 draw_maze_border()                                  /* draw the maze outline */
426 {
427   register int i, j;
428   
429   
430   for ( i=0; i<maze_size_x; i++) {
431     if ( maze[i][0] & WALL_TOP ) {
432       XDrawLine(dpy, win, gc,
433                 border_x + grid_width * i,
434                 border_y,
435                 border_x + grid_width * (i+1) - 1,
436                 border_y);
437     }
438     if ((maze[i][maze_size_y - 1] & WALL_BOTTOM)) {
439       XDrawLine(dpy, win, gc,
440                 border_x + grid_width * i,
441                 border_y + grid_height * (maze_size_y) - 1,
442                 border_x + grid_width * (i+1) - 1,
443                 border_y + grid_height * (maze_size_y) - 1);
444     }
445   }
446   for ( j=0; j<maze_size_y; j++) {
447     if ( maze[maze_size_x - 1][j] & WALL_RIGHT ) {
448       XDrawLine(dpy, win, gc,
449                 border_x + grid_width * maze_size_x - 1,
450                 border_y + grid_height * j,
451                 border_x + grid_width * maze_size_x - 1,
452                 border_y + grid_height * (j+1) - 1);
453     }
454     if ( maze[0][j] & WALL_LEFT ) {
455       XDrawLine(dpy, win, gc,
456                 border_x,
457                 border_y + grid_height * j,
458                 border_x,
459                 border_y + grid_height * (j+1) - 1);
460     }
461   }
462   
463   if (logo_x != -1)
464     {
465       Window r;
466       int x, y;
467       unsigned int w, h, bw, d;
468       XGetGeometry (dpy, logo_map, &r, &x, &y, &w, &h, &bw, &d);
469       XCopyPlane (dpy, logo_map, win, logo_gc,
470                   0, 0, w, h,
471                   border_x + 3 + grid_width * logo_x,
472                   border_y + 3 + grid_height * logo_y, 1);
473     }
474   draw_solid_square (start_x, start_y, start_dir, tgc);
475   draw_solid_square (end_x, end_y, end_dir, tgc);
476 }
477
478
479 static void
480 draw_wall(i, j, dir)                                   /* draw a single wall */
481      int i, j, dir;
482 {
483   switch (dir) {
484   case 0:
485     XDrawLine(dpy, win, gc,
486               border_x + grid_width * i, 
487               border_y + grid_height * j,
488               border_x + grid_width * (i+1), 
489               border_y + grid_height * j);
490     break;
491   case 1:
492     XDrawLine(dpy, win, gc,
493               border_x + grid_width * (i+1), 
494               border_y + grid_height * j,
495               border_x + grid_width * (i+1), 
496               border_y + grid_height * (j+1));
497     break;
498   case 2:
499     XDrawLine(dpy, win, gc,
500               border_x + grid_width * i, 
501               border_y + grid_height * (j+1),
502               border_x + grid_width * (i+1), 
503               border_y + grid_height * (j+1));
504     break;
505   case 3:
506     XDrawLine(dpy, win, gc,
507               border_x + grid_width * i, 
508               border_y + grid_height * j,
509               border_x + grid_width * i, 
510               border_y + grid_height * (j+1));
511     break;
512   }
513 }
514
515 int bw;
516
517 static void
518 draw_solid_square(i, j, dir, gc)          /* draw a solid square in a square */
519      register int i, j, dir;
520      GC gc;
521 {
522   switch (dir) {
523   case 0: XFillRectangle(dpy, win, gc,
524                          border_x + bw + grid_width * i, 
525                          border_y - bw + grid_height * j, 
526                          grid_width - (bw+bw), grid_height);
527     break;
528   case 1: XFillRectangle(dpy, win, gc,
529                          border_x + bw + grid_width * i, 
530                          border_y + bw + grid_height * j, 
531                          grid_width, grid_height - (bw+bw));
532     break;
533   case 2: XFillRectangle(dpy, win, gc,
534                          border_x + bw + grid_width * i, 
535                          border_y + bw + grid_height * j, 
536                          grid_width - (bw+bw), grid_height);
537     break;
538   case 3: XFillRectangle(dpy, win, gc,
539                          border_x - bw + grid_width * i, 
540                          border_y + bw + grid_height * j, 
541                          grid_width, grid_height - (bw+bw));
542     break;
543   }
544   XSync (dpy, False);
545 }
546
547
548 static void
549 solve_maze()                             /* solve it with graphical feedback */
550 {
551   int i;
552   
553   
554   /* plug up the surrounding wall */
555   maze[start_x][start_y] |= (WALL_TOP >> start_dir);
556   maze[end_x][end_y] |= (WALL_TOP >> end_dir);
557   
558   /* initialize search path */
559   i = 0;
560   path[i].x = end_x;
561   path[i].y = end_y;
562   path[i].dir = -1;
563   
564   /* do it */
565   while (1) {
566     if ( ++path[i].dir >= 4 ) {
567       i--;
568       draw_solid_square( (int)(path[i].x), (int)(path[i].y), 
569                         (int)(path[i].dir), cgc);
570     }
571     else if ( ! (maze[path[i].x][path[i].y] & 
572                  (WALL_TOP >> path[i].dir))  && 
573              ( (i == 0) || ( (path[i].dir != 
574                               (int)(path[i-1].dir+2)%4) ) ) ) {
575       enter_square(i);
576       i++;
577       if ( maze[path[i].x][path[i].y] & START_SQUARE ) {
578         return;
579       }
580     } 
581     if (check_events()) return;
582     /* Abort solve on expose - cheapo repaint strategy */
583     if (solve_delay) usleep (solve_delay);
584   }
585
586
587
588 static void
589 enter_square(n)                            /* move into a neighboring square */
590      int n;
591 {
592   draw_solid_square( (int)path[n].x, (int)path[n].y, 
593                     (int)path[n].dir, tgc);
594   
595   path[n+1].dir = -1;
596   switch (path[n].dir) {
597   case 0: path[n+1].x = path[n].x;
598     path[n+1].y = path[n].y - 1;
599     break;
600   case 1: path[n+1].x = path[n].x + 1;
601     path[n+1].y = path[n].y;
602     break;
603   case 2: path[n+1].x = path[n].x;
604     path[n+1].y = path[n].y + 1;
605     break;
606   case 3: path[n+1].x = path[n].x - 1;
607     path[n+1].y = path[n].y;
608     break;
609   }
610 }
611
612 /* ----<eof> */
613
614
615 /*
616  *  jmr additions for Jamie Zawinski's <jwz@mcom.com> screensaver stuff,
617  *  note that the code above this has probably been hacked about in some
618  *  arbitrary way.
619  */
620
621 char *progclass = "Maze";
622
623 char *defaults[] = {
624   "Maze.background:     black",         /* to placate SGI */
625   "Maze.foreground:     white",         /* to placate SGI */
626   "*gridSize:   0",
627   "*solveDelay: 5000",
628   "*preDelay:   2000000",
629   "*postDelay:  4000000",
630   "*liveColor:  green",
631   "*deadColor:  red",
632 #ifdef XROGER
633   "*logoColor:  red3",
634 #endif
635   0
636 };
637
638 XrmOptionDescRec options[] = {
639   { "-grid-size",       ".gridSize",    XrmoptionSepArg, 0 },
640   { "-solve-delay",     ".solveDelay",  XrmoptionSepArg, 0 },
641   { "-pre-delay",       ".preDelay",    XrmoptionSepArg, 0 },
642   { "-post-delay",      ".postDelay",   XrmoptionSepArg, 0 },
643   { "-live-color",      ".liveColor",   XrmoptionSepArg, 0 },
644   { "-dead-color",      ".deadColor",   XrmoptionSepArg, 0 }
645 };
646
647 int options_size = (sizeof(options)/sizeof(options[0]));
648
649 void screenhack(display,window)
650      Display *display;
651      Window window;
652 {
653   Pixmap gray;
654   int size, root;
655   XWindowAttributes xgwa;
656   unsigned long bg, fg, pfg, pbg, lfg;
657
658   size = get_integer_resource ("gridSize", "Dimension");
659   root = get_boolean_resource("root", "Boolean");
660   solve_delay = get_integer_resource ("solveDelay", "Integer");
661   pre_solve_delay = get_integer_resource ("preDelay", "Integer");
662   post_solve_delay = get_integer_resource ("postDelay", "Integer");
663
664   if (size < 2) size = 7 + (random () % 30);
665   grid_width = grid_height = size;
666   bw = (size > 6 ? 3 : (size-1)/2);
667
668   dpy = display; win = window; /* the maze stuff uses global variables */
669
670   XGetWindowAttributes (dpy, win, &xgwa);
671
672   x = 0;
673   y = 0;
674
675   set_maze_sizes (xgwa.width, xgwa.height);
676
677   if (! root)
678     XSelectInput (dpy, win, ExposureMask|ButtonPressMask|StructureNotifyMask);
679   
680   gc = XCreateGC(dpy, win, 0, 0);
681   cgc = XCreateGC(dpy, win, 0, 0);
682   tgc = XCreateGC(dpy,win,0,0);
683   logo_gc = XCreateGC(dpy, win, 0, 0);
684   
685   gray = XCreateBitmapFromData (dpy,win,gray1_bits,gray1_width,gray1_height);
686
687   bg  = get_pixel_resource ("background","Background", dpy, xgwa.colormap);
688   fg  = get_pixel_resource ("foreground","Foreground", dpy, xgwa.colormap);
689   lfg = get_pixel_resource ("logoColor", "Foreground", dpy, xgwa.colormap);
690   pfg = get_pixel_resource ("liveColor", "Foreground", dpy, xgwa.colormap);
691   pbg = get_pixel_resource ("deadColor", "Foreground", dpy, xgwa.colormap);
692   if (mono_p) lfg = pfg = fg;
693
694   if (lfg == bg)
695     lfg = ((bg == WhitePixel (dpy, DefaultScreen (dpy)))
696            ? BlackPixel (dpy, DefaultScreen (dpy))
697            : WhitePixel (dpy, DefaultScreen (dpy)));
698
699   XSetForeground (dpy, gc, fg);
700   XSetBackground (dpy, gc, bg);
701   XSetForeground (dpy, cgc, pbg);
702   XSetBackground (dpy, cgc, bg);
703   XSetForeground (dpy, tgc, pfg);
704   XSetBackground (dpy, tgc, bg);
705   XSetForeground (dpy, logo_gc, lfg);
706   XSetBackground (dpy, logo_gc, bg);
707
708   XSetStipple (dpy, cgc, gray);
709   XSetFillStyle (dpy, cgc, FillOpaqueStippled);
710   
711 #ifdef XROGER
712   {
713     int w, h;
714     XGCValues gcv;
715     GC draw_gc, erase_gc;
716     extern void skull ();
717     /* round up to grid size */
718     w = ((logo_width  / grid_width) + 1)  * grid_width;
719     h = ((logo_height / grid_height) + 1) * grid_height;
720     logo_map = XCreatePixmap (dpy, win, w, h, 1);
721     gcv.foreground = 1L;
722     draw_gc = XCreateGC (dpy, logo_map, GCForeground, &gcv);
723     gcv.foreground = 0L;
724     erase_gc= XCreateGC (dpy, logo_map, GCForeground, &gcv);
725     XFillRectangle (dpy, logo_map, erase_gc, 0, 0, w, h);
726     skull (dpy, logo_map, draw_gc, erase_gc, 5, 0, w-10, h-10);
727     XFreeGC (dpy, draw_gc);
728     XFreeGC (dpy, erase_gc);
729   }
730 #else
731   if  (!(logo_map = XCreateBitmapFromData (dpy, win, logo_bits,
732                                            logo_width, logo_height)))
733     {
734       fprintf (stderr, "Can't create logo pixmap\n");
735       exit (1);
736     }
737 #endif
738   XMapRaised(dpy, win);
739   srandom(getpid());
740
741   restart = root;
742
743   while (1) {                            /* primary execution loop [ rhess ] */
744     if (check_events()) continue ;
745     if (restart || stop) goto pop;
746     switch (state) {
747     case 1:
748       initialize_maze();
749       break;
750     case 2:
751       XClearWindow(dpy, win);
752       draw_maze_border();
753       break;
754     case 3:
755       create_maze();
756       break;
757     case 4:
758       XSync (dpy, False);
759       usleep (pre_solve_delay);
760       break;
761     case 5:
762       solve_maze();
763       break;
764     case 6:
765       XSync (dpy, False);
766       usleep (post_solve_delay);
767       state = 0 ;
768       break;
769     default:
770       abort ();
771     }
772     ++state;
773   pop:
774     if (restart)
775       {
776         static XWindowAttributes wattr;
777         restart = 0;
778         stop = 0;
779         state = 1;
780         XGetWindowAttributes (dpy, win, &wattr);
781         set_maze_sizes (wattr.width, wattr.height);
782         XClearWindow (dpy, win);
783         XSync (dpy, False);
784       }
785   }
786 }