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