ftp://ftp.sunet.se/pub/os/Linux/distributions/ultrapenguin/ultrapenguin-1.1/SRPMS...
[xscreensaver] / hacks / maze.c
1 /******************************************************************************
2  * [ maze ] ...
3  *
4  * modified:  [ 4-10-97 ]  Johannes Keukelaar <johannes@nada.kth.se>
5  *              Added multiple maze creators. Robustified solver.
6  *              Added bridge option.
7  * modified:  [ 8-11-95 ] Ed James <james@mml.mmc.com>
8  *              added fill of dead-end box to solve_maze while loop.
9  * modified:  [ 3-7-93 ]  Jamie Zawinski <jwz@netscape.com>
10  *              added the XRoger logo, cleaned up resources, made
11  *              grid size a parameter.
12  * modified:  [ 3-3-93 ]  Jim Randell <jmr@mddjmr.fc.hp.com>
13  *              Added the colour stuff and integrated it with jwz's
14  *              screenhack stuff.  There's still some work that could
15  *              be done on this, particularly allowing a resource to
16  *              specify how big the squares are.
17  * modified:  [ 10-4-88 ]  Richard Hess    ...!uunet!cimshop!rhess  
18  *              [ Revised primary execution loop within main()...
19  *              [ Extended X event handler, check_events()...
20  * modified:  [ 1-29-88 ]  Dave Lemke      lemke@sun.com  
21  *              [ Hacked for X11...
22  *              [  Note the word "hacked" -- this is extremely ugly, but at 
23  *              [   least it does the job.  NOT a good programming example 
24  *              [   for X.
25  * original:  [ 6/21/85 ]  Martin Weiss    Sun Microsystems  [ SunView ]
26  *
27  ******************************************************************************
28  Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
29   
30  All Rights Reserved
31   
32  Permission to use, copy, modify, and distribute this software and its
33  documentation for any purpose and without fee is hereby granted, 
34  provided that the above copyright notice appear in all copies and that
35  both that copyright notice and this permission notice appear in 
36  supporting documentation, and that the names of Sun or MIT not be
37  used in advertising or publicity pertaining to distribution of the
38  software without specific prior written permission. Sun and M.I.T. 
39  make no representations about the suitability of this software for 
40  any purpose. It is provided "as is" without any express or implied warranty.
41  
42  SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
43  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44  PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT
45  OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
46  OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
47  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
48  OR PERFORMANCE OF THIS SOFTWARE.
49  *****************************************************************************/
50
51 #include "screenhack.h"
52
53 #define XROGER
54
55 static int solve_delay, pre_solve_delay, post_solve_delay;
56
57 #include  <stdio.h>
58 #include  <X11/Xlib.h>
59 #include  <X11/Xutil.h>
60 #ifndef VMS
61 # include  <X11/bitmaps/gray1>
62 #else  /* VMS */
63 # include "sys$common:[decw$include.bitmaps]gray1.xbm"
64 #endif /* VMS */
65
66 #define MAX_MAZE_SIZE_X 500
67 #define MAX_MAZE_SIZE_Y 500
68
69 #define MOVE_LIST_SIZE  (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
70
71 #define WALL_TOP        0x8000
72 #define WALL_RIGHT      0x4000
73 #define WALL_BOTTOM     0x2000
74 #define WALL_LEFT       0x1000
75
76 #define DOOR_IN_TOP     0x800
77 #define DOOR_IN_RIGHT   0x400
78 #define DOOR_IN_BOTTOM  0x200
79 #define DOOR_IN_LEFT    0x100
80 #define DOOR_IN_ANY     0xF00
81
82 #define DOOR_OUT_TOP    0x80
83 #define DOOR_OUT_RIGHT  0x40
84 #define DOOR_OUT_BOTTOM 0x20
85 #define DOOR_OUT_LEFT   0x10
86
87 #define SOLVER_VISIT    0x4
88 #define START_SQUARE    0x2
89 #define END_SQUARE      0x1
90
91 #define border_x        (0)
92 #define border_y        (0)
93
94 #define get_random(x)   (random() % (x))
95   
96 static int logo_x, logo_y;
97
98 #ifdef XROGER
99 # define logo_width  128
100 # define logo_height 128
101 #else
102 # include  <X11/bitmaps/xlogo64>
103 # define logo_width xlogo64_width
104 # define logo_height xlogo64_height
105 # define logo_bits xlogo64_bits
106 #endif
107
108 static unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
109
110 static struct {
111   unsigned char x;
112   unsigned char y;
113   unsigned char dir;
114 } move_list[MOVE_LIST_SIZE], save_path[MOVE_LIST_SIZE], path[MOVE_LIST_SIZE];
115
116 static int maze_size_x, maze_size_y;
117 static int sqnum, cur_sq_x, cur_sq_y, path_length;
118 static int start_x, start_y, start_dir, end_x, end_y, end_dir;
119 static int grid_width, grid_height;
120 static int bw;
121
122 static Display  *dpy;
123 static Window   win;
124 static GC       gc, cgc, tgc, logo_gc, erase_gc;
125 static Pixmap   logo_map;
126
127 static int      x = 0, y = 0, restart = 0, stop = 1, state = 1, max_length;
128 static int      sync_p, bridge_p;
129
130 static int
131 check_events (void)                        /* X event handler [ rhess ] */
132 {
133   XEvent        e;
134
135   if (XPending(dpy)) {
136     XNextEvent(dpy, &e);
137     switch (e.type) {
138
139     case ButtonPress:
140       switch (e.xbutton.button) {
141       case 3:
142         exit (0);
143         break;
144       case 2:
145         stop = !stop ;
146         if (state == 5) state = 4 ;
147         else {
148           restart = 1;
149           stop = 0;
150         }
151         break;
152       default:
153         restart = 1 ;
154         stop = 0 ;
155         break;
156       }
157       break;
158
159     case ConfigureNotify:
160       restart = 1;
161       break;
162     case UnmapNotify:
163       stop = 1;
164       XClearWindow (dpy, win);
165       XSync (dpy, False);
166       break;
167     case Expose:
168       restart = 1;
169       break;
170     }
171     return(1);
172   }
173   return(0);
174 }
175
176
177 static void
178 set_maze_sizes (int width, int height)
179 {
180   maze_size_x = width / grid_width;
181   maze_size_y = height / grid_height;
182 }
183
184
185 static void
186 initialize_maze (void) /* draw the surrounding wall and start/end squares */
187 {
188   register int i, j, wall;
189   int logow = 1 + logo_width / grid_width;
190   int logoh = 1 + logo_height / grid_height;
191   
192   /* initialize all squares */
193   for ( i=0; i<maze_size_x; i++) {
194     for ( j=0; j<maze_size_y; j++) {
195       maze[i][j] = 0;
196     }
197   }
198   
199   /* top wall */
200   for ( i=0; i<maze_size_x; i++ ) {
201     maze[i][0] |= WALL_TOP;
202   }
203   
204   /* right wall */
205   for ( j=0; j<maze_size_y; j++ ) {
206     maze[maze_size_x-1][j] |= WALL_RIGHT;
207   }
208   
209   /* bottom wall */
210   for ( i=0; i<maze_size_x; i++ ) {
211     maze[i][maze_size_y-1] |= WALL_BOTTOM;
212   }
213   
214   /* left wall */
215   for ( j=0; j<maze_size_y; j++ ) {
216     maze[0][j] |= WALL_LEFT;
217   }
218   
219   /* set start square */
220   wall = get_random(4);
221   switch (wall) {
222   case 0:       
223     i = get_random(maze_size_x);
224     j = 0;
225     break;
226   case 1:       
227     i = maze_size_x - 1;
228     j = get_random(maze_size_y);
229     break;
230   case 2:       
231     i = get_random(maze_size_x);
232     j = maze_size_y - 1;
233     break;
234   case 3:       
235     i = 0;
236     j = get_random(maze_size_y);
237     break;
238   }
239   maze[i][j] |= START_SQUARE;
240   maze[i][j] |= ( DOOR_IN_TOP >> wall );
241   maze[i][j] &= ~( WALL_TOP >> wall );
242   cur_sq_x = i;
243   cur_sq_y = j;
244   start_x = i;
245   start_y = j;
246   start_dir = wall;
247   sqnum = 0;
248   
249   /* set end square */
250   wall = (wall + 2)%4;
251   switch (wall) {
252   case 0:
253     i = get_random(maze_size_x);
254     j = 0;
255     break;
256   case 1:
257     i = maze_size_x - 1;
258     j = get_random(maze_size_y);
259     break;
260   case 2:
261     i = get_random(maze_size_x);
262     j = maze_size_y - 1;
263     break;
264   case 3:
265     i = 0;
266     j = get_random(maze_size_y);
267     break;
268   }
269   maze[i][j] |= END_SQUARE;
270   maze[i][j] |= ( DOOR_OUT_TOP >> wall );
271   maze[i][j] &= ~( WALL_TOP >> wall );
272   end_x = i;
273   end_y = j;
274   end_dir = wall;
275   
276   /* set logo */
277   if ((maze_size_x-logow >= 6) && (maze_size_y-logoh >= 6))
278     {
279       /* not closer than 3 grid units from a wall */
280       logo_x = get_random (maze_size_x - logow - 5) + 3;
281       logo_y = get_random (maze_size_y - logoh - 5) + 3;
282       for (i=0; i<logow; i++)
283         for (j=0; j<logoh; j++)
284           maze[logo_x + i][logo_y + j] |= DOOR_IN_TOP;
285     }
286   else
287     logo_y = logo_x = -1;
288 }
289
290 static int choose_door (void);
291 static int backup (void);
292 static void draw_wall (int, int, int, GC);
293 static void draw_solid_square (int, int, int, GC);
294 /*static void enter_square (int);*/
295 static void build_wall (int, int, int);
296 /*static void break_wall (int, int, int);*/
297
298 static void join_sets(int, int);
299
300 /* For set_create_maze. */
301 /* The sets that our squares are in. */
302 static int *sets = 0;
303 /* The `list' of hedges. */
304 static int *hedges = 0;
305
306 #define DEBUG_SETS 0
307
308 /* Initialise the sets. */
309 static void 
310 init_sets(void)
311 {
312   int i, t, r, x, y;
313
314   if(sets)
315     free(sets);
316   sets = (int *)malloc(maze_size_x*maze_size_y*sizeof(int));
317   if(!sets)
318     abort();
319   for(i = 0; i < maze_size_x*maze_size_y; i++)
320     {
321       sets[i] = i;
322     }
323   
324   if(hedges)
325     free(hedges);
326   hedges = (int *)malloc(maze_size_x*maze_size_y*2*sizeof(int));
327   if(!hedges)
328     abort();
329   for(i = 0; i < maze_size_x*maze_size_y*2; i++)
330     {
331       hedges[i] = i;
332     }
333   /* Mask out outside walls. */
334   for(i = 0; i < maze_size_y; i++)
335     {
336       hedges[2*((maze_size_x)*i+maze_size_x-1)+1] = -1;
337     }
338   for(i = 0; i < maze_size_x; i++)
339     {
340       hedges[2*((maze_size_y-1)*maze_size_x+i)] = -1;
341     }
342   /* Mask out a possible logo. */
343   if(logo_x!=-1)
344     {
345       int logow = 1 + logo_width / grid_width;
346       int logoh = 1 + logo_height / grid_height;
347       int bridge_dir, bridge_c;
348
349       if(bridge_p && logoh>=3 && logow>=3)
350         {
351           bridge_dir = 1+random()%2;
352           if(bridge_dir==1)
353             {
354               bridge_c = logo_y+random()%(logoh-2)+1;
355             }
356           else
357             {
358               bridge_c = logo_x+random()%(logow-2)+1;
359             }
360         }
361       else
362         {
363           bridge_dir = 0;
364           bridge_c = -1;
365         }
366
367       for(x = logo_x; x < logo_x+logow; x++)
368         for(y = logo_y; y < logo_y+logoh; y++)
369           {
370             /* I should check for the bridge here, except that I join the
371              * bridge together below.
372              */
373             hedges[2*(x+maze_size_x*y)+1] = -1;
374             hedges[2*(x+maze_size_x*y)] = -1;
375           }
376       for(x = logo_x; x < logo_x+logow; x++)
377         {
378           if(!(bridge_dir==2 && x==bridge_c))
379             {
380               build_wall(x, logo_y, 0);
381               build_wall(x, logo_y+logoh, 0);
382             }
383           hedges[2*(x+maze_size_x*(logo_y-1))] = -1;
384           if(bridge_dir==1)
385             {
386               build_wall(x, bridge_c, 0);
387               build_wall(x, bridge_c, 2);
388             }
389         }
390       for(y = logo_y; y < logo_y+logoh; y++)
391         {
392           if(!(bridge_dir==1 && y==bridge_c))
393             {
394               build_wall(logo_x, y, 3);
395               build_wall(logo_x+logow, y, 3);
396             }
397           hedges[2*(logo_x-1+maze_size_x*y)+1] = -1;
398           if(bridge_dir==2)
399             {
400               build_wall(bridge_c, y, 1);
401               build_wall(bridge_c, y, 3);
402             }
403         }
404       /* Join the whole bridge together. */
405       if(bridge_p)
406         {
407           if(bridge_dir==1)
408             {
409               x = logo_x-1;
410               y = bridge_c;
411               for(i = logo_x; i < logo_x+logow+1; i++)
412                 join_sets(x+y*maze_size_x, i+y*maze_size_x);
413             }
414           else
415             {
416               y = logo_y-1;
417               x = bridge_c;
418               for(i = logo_y; i < logo_y+logoh+1; i++)
419                 join_sets(x+y*maze_size_x, x+i*maze_size_x);
420             }
421         }
422     }
423
424   for(i = 0; i < maze_size_x*maze_size_y*2; i++)
425     {
426       t = hedges[i];
427       r = random()%(maze_size_x*maze_size_y*2);
428       hedges[i] = hedges[r];
429       hedges[r] = t;
430     }
431 }
432
433 /* Get the representative of a set. */
434 static int
435 get_set(int num)
436 {
437   int s;
438
439   if(sets[num]==num)
440     return num;
441   else
442     {
443       s = get_set(sets[num]);
444       sets[num] = s;
445       return s;
446     }
447 }
448
449 /* Join two sets together. */
450 static void
451 join_sets(num1, num2)
452      int num1, num2;
453 {
454   int s1, s2;
455
456   s1 = get_set(num1);
457   s2 = get_set(num2);
458   
459   if(s1<s2)
460     sets[s2] = s1;
461   else
462     sets[s1] = s2;
463 }
464
465 /* Exitialise the sets. */
466 static void
467 exit_sets(void)
468 {
469   if(hedges)
470     free(hedges);
471   hedges = 0;
472   if(sets)
473     free(sets);
474   sets = 0;
475 }
476
477 #if DEBUG_SETS
478 /* Temporary hack. */
479 static void
480 show_set(int num, GC gc)
481 {
482   int x, y, set;
483
484   set = get_set(num);
485
486   for(x = 0; x < maze_size_x; x++)
487     for(y = 0; y < maze_size_y; y++)
488       {
489         if(get_set(x+y*maze_size_x)==set)
490           {
491             XFillRectangle(dpy, win, gc,  border_x + bw + grid_width * x, 
492                          border_y + bw + grid_height * y, 
493                          grid_width-2*bw , grid_height-2*bw);
494           }
495       }
496 }
497 #endif
498
499 /* Second alternative maze creator: Put each square in the maze in a 
500  * separate set. Also, make a list of all the hedges. Randomize that list.
501  * Walk through the list. If, for a certain hedge, the two squares on both
502  * sides of it are in different sets, union the sets and remove the hedge.
503  * Continue until all hedges have been processed or only one set remains.
504  */
505 static void
506 set_create_maze(void)
507 {
508   int i, h, x, y, dir, v, w;
509 #if DEBUG_SETS
510   int cont = 0;
511   char c;
512 #endif
513
514   /* Do almost all the setup. */
515   init_sets();
516
517   /* Start running through the hedges. */
518   for(i = 0; i < 2*maze_size_x*maze_size_y; i++)
519     { 
520       h = hedges[i];
521
522       /* This one is in the logo or outside border. */
523       if(h==-1)
524         continue;
525
526       dir = h%2?1:2;
527       x = (h>>1)%maze_size_x;
528       y = (h>>1)/maze_size_x;
529
530       v = x;
531       w = y;
532       switch(dir)
533         {
534         case 1:
535           v++;
536           break;
537         case 2:
538           w++;
539           break;
540         }
541
542 #if DEBUG_SETS
543       show_set(x+y*maze_size_x, logo_gc);
544       show_set(v+w*maze_size_x, tgc);
545 #endif
546       if(get_set(x+y*maze_size_x)!=get_set(v+w*maze_size_x))
547         {
548 #if DEBUG_SETS
549           printf("Join!");
550 #endif
551           join_sets(x+y*maze_size_x, v+w*maze_size_x);
552           /* Don't draw the wall. */
553         }
554       else
555         {
556 #if DEBUG_SETS
557           printf("Build.");
558 #endif
559           /* Don't join the sets. */
560           build_wall(x, y, dir); 
561         }
562 #if DEBUG_SETS
563       if(!cont)
564         {
565           XSync(dpy, False);
566           c = getchar();
567           if(c=='c')
568             cont = 1;
569         }
570       show_set(x+y*maze_size_x, erase_gc);
571       show_set(v+w*maze_size_x, erase_gc);
572 #endif
573     }
574
575   /* Free some memory. */
576   exit_sets();
577 }
578
579 /* First alternative maze creator: Pick a random, empty corner in the maze.
580  * Pick a random direction. Draw a wall in that direction, from that corner
581  * until we hit a wall. Option: Only draw the wall if it's going to be 
582  * shorter than a certain length. Otherwise we get lots of long walls.
583  */
584 static void
585 alt_create_maze(void)
586 {
587   char *corners;
588   int *c_idx;
589   int i, j, height, width, open_corners, k, dir, x, y;
590
591   height = maze_size_y+1;
592   width = maze_size_x+1;
593
594   /* Allocate and clear some mem. */
595   corners = (char *)calloc(height*width, 1);
596   if(!corners)
597     return;
598
599   /* Set up the indexing array. */
600   c_idx = (int *)malloc(sizeof(int)*height*width);
601   if(!c_idx)
602     {
603       free(corners);
604       return;
605     }
606   for(i = 0; i < height*width; i++)
607     c_idx[i] = i;
608   for(i = 0; i < height*width; i++)
609     {
610       j = c_idx[i];
611       k = random()%(height*width);
612       c_idx[i] = c_idx[k];
613       c_idx[k] = j;
614     }
615
616   /* Set up some initial walls. */
617   /* Outside walls. */
618   for(i = 0; i < width; i++)
619     {
620       corners[i] = 1;
621       corners[i+width*(height-1)] = 1;
622     }
623   for(i = 0; i < height; i++)
624     {
625       corners[i*width] = 1;
626       corners[i*width+width-1] = 1;
627     }
628   /* Walls around logo. In fact, inside the logo, too. */
629   /* Also draw the walls. */
630   if(logo_x!=-1)
631     {
632       int logow = 1 + logo_width / grid_width;
633       int logoh = 1 + logo_height / grid_height;
634       int bridge_dir, bridge_c;
635
636       if(bridge_p && logoh>=3 && logow>=3)
637         {
638           bridge_dir = 1+random()%2;
639           if(bridge_dir==1)
640             {
641               bridge_c = logo_y+random()%(logoh-2)+1;
642             }
643           else
644             {
645               bridge_c = logo_x+random()%(logow-2)+1;
646             }
647         }
648       else
649         {
650           bridge_dir = 0;
651           bridge_c = -1;
652         }
653       for(i = logo_x; i <= logo_x + logow; i++)
654         {
655           for(j = logo_y; j <= logo_y + logoh; j++)
656             {
657               corners[i+width*j] = 1;
658             }
659         }
660       for(x = logo_x; x < logo_x+logow; x++)
661         {
662           if(!(bridge_dir==2 && x==bridge_c))
663             {
664               build_wall(x, logo_y, 0);
665               build_wall(x, logo_y+logoh, 0);
666             }
667           if(bridge_dir==1)
668             {
669               build_wall(x, bridge_c, 0);
670               build_wall(x, bridge_c, 2);
671             }
672         }
673       for(y = logo_y; y < logo_y+logoh; y++)
674         {
675           if(!(bridge_dir==1 && y==bridge_c))
676             {
677               build_wall(logo_x, y, 3);
678               build_wall(logo_x+logow, y, 3);
679             }
680           if(bridge_dir==2)
681             {
682               build_wall(bridge_c, y, 1);
683               build_wall(bridge_c, y, 3);
684             }
685         }
686       /* Connect one wall of the logo with an outside wall. */
687       if(bridge_p)
688         dir = (bridge_dir+1)%4;
689       else
690         dir = random()%4;
691       switch(dir)
692         {
693         case 0:
694           x = logo_x+(random()%(logow+1));
695           y = logo_y;
696           break;
697         case 1:
698           x = logo_x+logow;
699           y = logo_y+(random()%(logoh+1));
700           break;
701         case 2:
702           x = logo_x+(random()%(logow+1));
703           y = logo_y+logoh;
704           break;
705         case 3:
706           x = logo_x;
707           y = logo_y+(random()%(logoh+1));
708           break;
709         }
710       do
711         {
712           corners[x+width*y] = 1;
713           switch(dir)
714             {
715             case 0:
716               build_wall(x-1, y-1, 1);
717               y--;
718               break;
719             case 1:
720               build_wall(x, y, 0);
721               x++;
722               break;
723             case 2:
724               build_wall(x, y, 3);
725               y++;
726               break;
727             case 3:
728               build_wall(x-1, y-1, 2);
729               x--;
730               break;      
731             }
732         }
733       while(!corners[x+width*y]);
734       if(bridge_p)
735         {
736           dir = (dir+2)%4;
737           switch(dir)
738             {
739             case 0:
740               x = logo_x+(random()%(logow+1));
741               y = logo_y;
742               break;
743             case 1:
744               x = logo_x+logow;
745               y = logo_y+(random()%(logoh+1));
746               break;
747             case 2:
748               x = logo_x+(random()%(logow+1));
749               y = logo_y+logoh;
750               break;
751             case 3:
752               x = logo_x;
753               y = logo_y+(random()%(logoh+1));
754               break;
755             }
756           do
757             {
758               corners[x+width*y] = 1;
759               switch(dir)
760                 {
761                 case 0:
762                   build_wall(x-1, y-1, 1);
763                   y--;
764                   break;
765                 case 1:
766                   build_wall(x, y, 0);
767                   x++;
768                   break;
769                 case 2:
770                   build_wall(x, y, 3);
771                   y++;
772                   break;
773                 case 3:
774                   build_wall(x-1, y-1, 2);
775                   x--;
776                   break;          
777                 }
778             }
779           while(!corners[x+width*y]);
780         }
781     }
782
783   /* Count open gridpoints. */
784   open_corners = 0;
785   for(i = 0; i < width; i++)
786     for(j = 0; j < height; j++)
787       if(!corners[i+width*j])
788         open_corners++;
789
790   /* Now do actual maze generation. */
791   while(open_corners>0)
792     {
793       for(i = 0; i < width*height; i++)
794         {
795           if(!corners[c_idx[i]])
796             {
797               x = c_idx[i]%width;
798               y = c_idx[i]/width;
799               /* Choose a random direction. */
800               dir = random()%4;
801               
802               k = 0;
803               /* Measure the length of the wall we'd draw. */
804               while(!corners[x+width*y])
805                 {
806                   k++;
807                   switch(dir)
808                     {
809                     case 0:
810                       y--;
811                       break;
812                     case 1:
813                       x++;
814                       break;
815                     case 2:
816                       y++;
817                       break;
818                     case 3:
819                       x--;
820                       break;
821                     }
822                 }
823               
824               if(k<=max_length)
825                 {
826                   x = c_idx[i]%width;
827                   y = c_idx[i]/width;
828                   
829                   /* Draw a wall until we hit something. */
830                   while(!corners[x+width*y])
831                     {
832                       open_corners--;
833                       corners[x+width*y] = 1;
834                       switch(dir)
835                         {
836                         case 0:
837                           build_wall(x-1, y-1, 1);
838                           y--;
839                           break;
840                         case 1:
841                           build_wall(x, y, 0);
842                           x++;
843                           break;
844                         case 2:
845                           build_wall(x, y, 3);
846                           y++;
847                           break;
848                         case 3:
849                           build_wall(x-1, y-1, 2);
850                           x--;
851                           break;
852                         }
853                     }
854                 }
855             }
856         }
857     }
858
859   /* Free some memory we used. */
860   free(corners);
861   free(c_idx);
862 }
863
864 /* The original maze creator. Start somewhere. Take a step in a random 
865  * direction. Keep doing this until we hit a wall. Then, backtrack until
866  * we find a point where we can go in another direction.
867  */
868 static void
869 create_maze (void)    /* create a maze layout given the initialized maze */
870 {
871   register int i, newdoor = 0;
872   int logow = 1 + logo_width / grid_width;
873   int logoh = 1 + logo_height / grid_height;
874   
875   /* Maybe we should make a bridge? */
876   if(bridge_p && logo_x>=0 && logow>=3 && logoh>=3)
877     {
878       int bridge_dir, bridge_c;
879
880       bridge_dir = 1+random()%2;
881       if(bridge_dir==1)
882         {
883           if(logoh>=3)
884             bridge_c = logo_y+random()%(logoh-2)+1;
885           else
886             bridge_c = logo_y+random()%logoh;
887         }
888       else
889         {
890           if(logow>=3)
891             bridge_c = logo_x+random()%(logow-2)+1;
892           else
893             bridge_c = logo_x+random()%logow;
894         }
895
896       if(bridge_dir==1)
897         {
898           for(i = logo_x; i < logo_x+logow; i++)
899             {
900               maze[i][bridge_c] &= ~DOOR_IN_TOP;
901             }
902         }
903       else
904         {
905           for(i = logo_y; i < logo_y+logoh; i++)
906             {
907               maze[bridge_c][i] &= ~DOOR_IN_TOP;
908             }
909         }
910     }
911
912   do {
913     move_list[sqnum].x = cur_sq_x;
914     move_list[sqnum].y = cur_sq_y;
915     move_list[sqnum].dir = newdoor;
916     while ( ( newdoor = choose_door() ) == -1 ) { /* pick a door */
917       if ( backup() == -1 ) { /* no more doors ... backup */
918         return; /* done ... return */
919       }
920     }
921     
922     /* mark the out door */
923     maze[cur_sq_x][cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor );
924     
925     switch (newdoor) {
926     case 0: cur_sq_y--;
927       break;
928     case 1: cur_sq_x++;
929       break;
930     case 2: cur_sq_y++;
931       break;
932     case 3: cur_sq_x--;
933       break;
934     }
935     sqnum++;
936     
937     /* mark the in door */
938     maze[cur_sq_x][cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) );
939     
940     /* if end square set path length and save path */
941     if ( maze[cur_sq_x][cur_sq_y] & END_SQUARE ) {
942       path_length = sqnum;
943       for ( i=0; i<path_length; i++) {
944         save_path[i].x = move_list[i].x;
945         save_path[i].y = move_list[i].y;
946         save_path[i].dir = move_list[i].dir;
947       }
948     }
949     
950   } while (1);
951   
952 }
953
954
955 static int
956 choose_door (void)                                   /* pick a new path */
957 {
958   int candidates[3];
959   register int num_candidates;
960   
961   num_candidates = 0;
962   
963   /* top wall */
964   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_TOP )
965     goto rightwall;
966   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_TOP )
967     goto rightwall;
968   if ( maze[cur_sq_x][cur_sq_y] & WALL_TOP )
969     goto rightwall;
970   if ( maze[cur_sq_x][cur_sq_y - 1] & DOOR_IN_ANY ) {
971     maze[cur_sq_x][cur_sq_y] |= WALL_TOP;
972     maze[cur_sq_x][cur_sq_y - 1] |= WALL_BOTTOM;
973     draw_wall(cur_sq_x, cur_sq_y, 0, gc);
974     goto rightwall;
975   }
976   candidates[num_candidates++] = 0;
977   
978  rightwall:
979   /* right wall */
980   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_RIGHT )
981     goto bottomwall;
982   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_RIGHT )
983     goto bottomwall;
984   if ( maze[cur_sq_x][cur_sq_y] & WALL_RIGHT )
985     goto bottomwall;
986   if ( maze[cur_sq_x + 1][cur_sq_y] & DOOR_IN_ANY ) {
987     maze[cur_sq_x][cur_sq_y] |= WALL_RIGHT;
988     maze[cur_sq_x + 1][cur_sq_y] |= WALL_LEFT;
989     draw_wall(cur_sq_x, cur_sq_y, 1, gc);
990     goto bottomwall;
991   }
992   candidates[num_candidates++] = 1;
993   
994  bottomwall:
995   /* bottom wall */
996   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_BOTTOM )
997     goto leftwall;
998   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_BOTTOM )
999     goto leftwall;
1000   if ( maze[cur_sq_x][cur_sq_y] & WALL_BOTTOM )
1001     goto leftwall;
1002   if ( maze[cur_sq_x][cur_sq_y + 1] & DOOR_IN_ANY ) {
1003     maze[cur_sq_x][cur_sq_y] |= WALL_BOTTOM;
1004     maze[cur_sq_x][cur_sq_y + 1] |= WALL_TOP;
1005     draw_wall(cur_sq_x, cur_sq_y, 2, gc);
1006     goto leftwall;
1007   }
1008   candidates[num_candidates++] = 2;
1009   
1010  leftwall:
1011   /* left wall */
1012   if ( maze[cur_sq_x][cur_sq_y] & DOOR_IN_LEFT )
1013     goto donewall;
1014   if ( maze[cur_sq_x][cur_sq_y] & DOOR_OUT_LEFT )
1015     goto donewall;
1016   if ( maze[cur_sq_x][cur_sq_y] & WALL_LEFT )
1017     goto donewall;
1018   if ( maze[cur_sq_x - 1][cur_sq_y] & DOOR_IN_ANY ) {
1019     maze[cur_sq_x][cur_sq_y] |= WALL_LEFT;
1020     maze[cur_sq_x - 1][cur_sq_y] |= WALL_RIGHT;
1021     draw_wall(cur_sq_x, cur_sq_y, 3, gc);
1022     goto donewall;
1023   }
1024   candidates[num_candidates++] = 3;
1025   
1026  donewall:
1027   if (num_candidates == 0)
1028     return ( -1 );
1029   if (num_candidates == 1)
1030     return ( candidates[0] );
1031   return ( candidates[ get_random(num_candidates) ] );
1032   
1033 }
1034
1035
1036 static int
1037 backup (void)                                          /* back up a move */
1038 {
1039   sqnum--;
1040   cur_sq_x = move_list[sqnum].x;
1041   cur_sq_y = move_list[sqnum].y;
1042   return ( sqnum );
1043 }
1044
1045
1046 static void
1047 draw_maze_border (void)                         /* draw the maze outline */
1048 {
1049   register int i, j;
1050   
1051   
1052   for ( i=0; i<maze_size_x; i++) {
1053     if ( maze[i][0] & WALL_TOP ) {
1054       XDrawLine(dpy, win, gc,
1055                 border_x + grid_width * i,
1056                 border_y,
1057                 border_x + grid_width * (i+1) - 1,
1058                 border_y);
1059     }
1060     if ((maze[i][maze_size_y - 1] & WALL_BOTTOM)) {
1061       XDrawLine(dpy, win, gc,
1062                 border_x + grid_width * i,
1063                 border_y + grid_height * (maze_size_y) - 1,
1064                 border_x + grid_width * (i+1) - 1,
1065                 border_y + grid_height * (maze_size_y) - 1);
1066     }
1067   }
1068   for ( j=0; j<maze_size_y; j++) {
1069     if ( maze[maze_size_x - 1][j] & WALL_RIGHT ) {
1070       XDrawLine(dpy, win, gc,
1071                 border_x + grid_width * maze_size_x - 1,
1072                 border_y + grid_height * j,
1073                 border_x + grid_width * maze_size_x - 1,
1074                 border_y + grid_height * (j+1) - 1);
1075     }
1076     if ( maze[0][j] & WALL_LEFT ) {
1077       XDrawLine(dpy, win, gc,
1078                 border_x,
1079                 border_y + grid_height * j,
1080                 border_x,
1081                 border_y + grid_height * (j+1) - 1);
1082     }
1083   }
1084   
1085   if (logo_x != -1)
1086     {
1087       Window r;
1088       int x, y;
1089       unsigned int w, h, bw, d;
1090       XGetGeometry (dpy, logo_map, &r, &x, &y, &w, &h, &bw, &d);
1091       XCopyPlane (dpy, logo_map, win, logo_gc,
1092                   0, 0, w, h,
1093                   border_x + 3 + grid_width * logo_x,
1094                   border_y + 3 + grid_height * logo_y, 1);
1095     }
1096   draw_solid_square (start_x, start_y, start_dir, tgc);
1097   draw_solid_square (end_x, end_y, end_dir, tgc);
1098 }
1099
1100
1101 static void
1102 draw_wall(int i, int j, int dir, GC gc)                /* draw a single wall */
1103 {
1104   switch (dir) {
1105   case 0:
1106     XDrawLine(dpy, win, gc,
1107               border_x + grid_width * i, 
1108               border_y + grid_height * j,
1109               border_x + grid_width * (i+1), 
1110               border_y + grid_height * j);
1111     break;
1112   case 1:
1113     XDrawLine(dpy, win, gc,
1114               border_x + grid_width * (i+1), 
1115               border_y + grid_height * j,
1116               border_x + grid_width * (i+1), 
1117               border_y + grid_height * (j+1));
1118     break;
1119   case 2:
1120     XDrawLine(dpy, win, gc,
1121               border_x + grid_width * i, 
1122               border_y + grid_height * (j+1),
1123               border_x + grid_width * (i+1), 
1124               border_y + grid_height * (j+1));
1125     break;
1126   case 3:
1127     XDrawLine(dpy, win, gc,
1128               border_x + grid_width * i, 
1129               border_y + grid_height * j,
1130               border_x + grid_width * i, 
1131               border_y + grid_height * (j+1));
1132     break;
1133   }
1134   if(sync_p)
1135     XSync(dpy, False);
1136 }
1137
1138 /* Actually build a wall. */
1139 static void
1140 build_wall(i, j, dir)
1141      int i, j, dir;
1142 {
1143   /* Draw it on the screen. */
1144   draw_wall(i, j, dir, gc);
1145   /* Put it in the maze. */
1146   switch(dir)
1147     {
1148     case 0:
1149       maze[i][j] |= WALL_TOP;
1150       if(j>0)
1151         maze[i][j-1] |= WALL_BOTTOM;
1152       break;
1153     case 1:
1154       maze[i][j] |= WALL_RIGHT;
1155       if(i<maze_size_x-1)
1156         maze[i+1][j] |= WALL_LEFT;
1157       break;
1158     case 2:
1159       maze[i][j] |= WALL_BOTTOM;
1160       if(j<maze_size_y-1)
1161         maze[i][j+1] |= WALL_TOP;
1162       break;
1163     case 3:
1164       maze[i][j] |= WALL_LEFT;
1165       if(i>0)
1166         maze[i-1][j] |= WALL_RIGHT;
1167       break;
1168     }
1169 }
1170
1171 /* Break out a wall. */
1172 #if 0
1173 static void
1174 break_wall(i, j, dir)
1175      int i, j, dir;
1176 {
1177   /* Draw it on the screen. */
1178   draw_wall(i, j, dir, erase_gc);
1179   /* Put it in the maze. */
1180   switch(dir)
1181     {
1182     case 0:
1183       maze[i][j] &= ~WALL_TOP;
1184       if(j>0)
1185         maze[i][j-1] &= ~WALL_BOTTOM;
1186       break;
1187     case 1:
1188       maze[i][j] &= ~WALL_RIGHT;
1189       if(i<maze_size_x-1)
1190         maze[i+1][j] &= ~WALL_LEFT;
1191       break;
1192     case 2:
1193       maze[i][j] &= ~WALL_BOTTOM;
1194       if(j<maze_size_y-1)
1195         maze[i][j+1] &= ~WALL_BOTTOM;
1196       break;
1197     case 3:
1198       maze[i][j] &= ~WALL_LEFT;
1199       if(i>0)
1200         maze[i-1][j] &= ~WALL_RIGHT;
1201       break;
1202     }
1203 }
1204 #endif /* 0 */
1205
1206
1207 static void
1208 draw_solid_square(int i, int j,          /* draw a solid square in a square */
1209                   int dir, GC gc)
1210 {
1211   switch (dir) {
1212   case 0: XFillRectangle(dpy, win, gc,
1213                          border_x + bw + grid_width * i, 
1214                          border_y - bw + grid_height * j, 
1215                          grid_width - (bw+bw), grid_height);
1216     break;
1217   case 1: XFillRectangle(dpy, win, gc,
1218                          border_x + bw + grid_width * i, 
1219                          border_y + bw + grid_height * j, 
1220                          grid_width, grid_height - (bw+bw));
1221     break;
1222   case 2: XFillRectangle(dpy, win, gc,
1223                          border_x + bw + grid_width * i, 
1224                          border_y + bw + grid_height * j, 
1225                          grid_width - (bw+bw), grid_height);
1226     break;
1227   case 3: XFillRectangle(dpy, win, gc,
1228                          border_x - bw + grid_width * i, 
1229                          border_y + bw + grid_height * j, 
1230                          grid_width, grid_height - (bw+bw));
1231     break;
1232   }
1233   XSync (dpy, False);
1234 }
1235
1236
1237 static void
1238 solve_maze (void)                     /* solve it with graphical feedback */
1239 {
1240   int i;
1241   int step_x[4] = { 0, 1, 0, -1 };
1242   int step_y[4] = { -1, 0, 1, 0 };
1243     
1244   /* plug up the surrounding wall */
1245   maze[start_x][start_y] |= (WALL_TOP >> start_dir);
1246   maze[end_x][end_y] |= (WALL_TOP >> end_dir);
1247   
1248   /* initialize search path */
1249   i = 0;
1250   path[i].x = end_x;
1251   path[i].y = end_y;
1252   path[i].dir = -1;
1253   maze[end_x][end_y] |= SOLVER_VISIT;
1254   
1255   /* do it */
1256   while (1) {
1257     if ( ++path[i].dir >= 4 ) {
1258       XFillRectangle(dpy, win, cgc,
1259                      border_x + bw + grid_width * (int)(path[i].x),
1260                      border_y + bw + grid_height * (int)(path[i].y),
1261                      grid_width - (bw+bw), grid_height - (bw+bw));
1262       i--;
1263       if(i<0) /* Can't solve this maze. */
1264         {
1265           printf("Unsolvable maze.\n");
1266           return;
1267         }
1268       draw_solid_square( (int)(path[i].x), (int)(path[i].y), 
1269                         (int)(path[i].dir), cgc);
1270     }
1271     else if ( (! (maze[path[i].x][path[i].y] & (WALL_TOP >> path[i].dir))) && 
1272              (!( maze[path[i].x+step_x[path[i].dir]]
1273                     [path[i].y+step_y[path[i].dir]]&SOLVER_VISIT)) ) {
1274       path[i+1].x = path[i].x+step_x[path[i].dir];
1275       path[i+1].y = path[i].y+step_y[path[i].dir];
1276       path[i+1].dir = -1;
1277       draw_solid_square(path[i].x, path[i].y, path[i].dir, tgc);
1278       i++;
1279       maze[path[i].x][path[i].y] |= SOLVER_VISIT;
1280       if ( maze[path[i].x][path[i].y] & START_SQUARE ) {
1281         return;
1282       }
1283     } 
1284     if (check_events()) return;
1285     /* Abort solve on expose - cheapo repaint strategy */
1286     if (solve_delay) usleep (solve_delay);
1287   }
1288
1289
1290
1291 #if 0
1292 static void
1293 enter_square (int n)                      /* move into a neighboring square */
1294 {
1295   draw_solid_square( (int)path[n].x, (int)path[n].y, 
1296                     (int)path[n].dir, tgc);
1297   
1298   path[n+1].dir = -1;
1299   switch (path[n].dir) {
1300   case 0: path[n+1].x = path[n].x;
1301     path[n+1].y = path[n].y - 1;
1302     break;
1303   case 1: path[n+1].x = path[n].x + 1;
1304     path[n+1].y = path[n].y;
1305     break;
1306   case 2: path[n+1].x = path[n].x;
1307     path[n+1].y = path[n].y + 1;
1308     break;
1309   case 3: path[n+1].x = path[n].x - 1;
1310     path[n+1].y = path[n].y;
1311     break;
1312   }
1313 }
1314 #endif /* 0 */
1315
1316
1317 /*
1318  *  jmr additions for Jamie Zawinski's <jwz@netscape.com> screensaver stuff,
1319  *  note that the code above this has probably been hacked about in some
1320  *  arbitrary way.
1321  */
1322
1323 char *progclass = "Maze";
1324
1325 char *defaults[] = {
1326   "Maze.background:     black",         /* to placate SGI */
1327   "Maze.foreground:     white",         /* to placate SGI */
1328   "*gridSize:   0",
1329   "*solveDelay: 5000",
1330   "*preDelay:   2000000",
1331   "*postDelay:  4000000",
1332   "*liveColor:  green",
1333   "*deadColor:  red",
1334   "*generator:  -1",
1335   "*maxLength:  5",
1336   "*syncDraw:   False",
1337   "*bridge:     False",
1338 #ifdef XROGER
1339   "*logoColor:  red3",
1340 #endif
1341   0
1342 };
1343
1344 XrmOptionDescRec options[] = {
1345   { "-grid-size",       ".gridSize",    XrmoptionSepArg, 0 },
1346   { "-solve-delay",     ".solveDelay",  XrmoptionSepArg, 0 },
1347   { "-pre-delay",       ".preDelay",    XrmoptionSepArg, 0 },
1348   { "-post-delay",      ".postDelay",   XrmoptionSepArg, 0 },
1349   { "-live-color",      ".liveColor",   XrmoptionSepArg, 0 },
1350   { "-dead-color",      ".deadColor",   XrmoptionSepArg, 0 },
1351   { "-generator",       ".generator",   XrmoptionSepArg, 0 },
1352   { "-max-length",      ".maxLength",   XrmoptionSepArg, 0 },
1353   { "-bridge",          ".bridge",      XrmoptionNoArg, "True" },
1354   { "-no-bridge",       ".bridge",      XrmoptionNoArg, "False" },
1355   { 0, 0, 0, 0 }
1356 };
1357
1358 #ifdef XROGER
1359 extern void skull (Display *, Window, GC, GC, int, int, int, int);
1360 #endif
1361
1362 void
1363 screenhack(Display *display, Window window)
1364 {
1365   Pixmap gray;
1366   int size, root, generator, this_gen;
1367   XWindowAttributes xgwa;
1368   unsigned long bg, fg, pfg, pbg, lfg;
1369
1370   size = get_integer_resource ("gridSize", "Dimension");
1371   root = get_boolean_resource("root", "Boolean");
1372   solve_delay = get_integer_resource ("solveDelay", "Integer");
1373   pre_solve_delay = get_integer_resource ("preDelay", "Integer");
1374   post_solve_delay = get_integer_resource ("postDelay", "Integer");
1375   generator = get_integer_resource("generator", "Integer");
1376   max_length = get_integer_resource("maxLength", "Integer");
1377   bridge_p = get_boolean_resource("bridge", "Boolean");
1378
1379   if (size < 2) size = 7 + (random () % 30);
1380   grid_width = grid_height = size;
1381   bw = (size > 6 ? 3 : (size-1)/2);
1382
1383   dpy = display; win = window; /* the maze stuff uses global variables */
1384
1385   XGetWindowAttributes (dpy, win, &xgwa);
1386
1387   x = 0;
1388   y = 0;
1389
1390   set_maze_sizes (xgwa.width, xgwa.height);
1391
1392   if (! root)
1393     XSelectInput (dpy, win, ExposureMask|ButtonPressMask|StructureNotifyMask);
1394   
1395   gc = XCreateGC(dpy, win, 0, 0);
1396   cgc = XCreateGC(dpy, win, 0, 0);
1397   tgc = XCreateGC(dpy,win,0,0);
1398   logo_gc = XCreateGC(dpy, win, 0, 0);
1399   erase_gc = XCreateGC(dpy, win, 0, 0);
1400   
1401   gray = XCreateBitmapFromData (dpy,win,gray1_bits,gray1_width,gray1_height);
1402
1403   bg  = get_pixel_resource ("background","Background", dpy, xgwa.colormap);
1404   fg  = get_pixel_resource ("foreground","Foreground", dpy, xgwa.colormap);
1405   lfg = get_pixel_resource ("logoColor", "Foreground", dpy, xgwa.colormap);
1406   pfg = get_pixel_resource ("liveColor", "Foreground", dpy, xgwa.colormap);
1407   pbg = get_pixel_resource ("deadColor", "Foreground", dpy, xgwa.colormap);
1408   if (mono_p) lfg = pfg = fg;
1409
1410   if (lfg == bg)
1411     lfg = ((bg == WhitePixel (dpy, DefaultScreen (dpy)))
1412            ? BlackPixel (dpy, DefaultScreen (dpy))
1413            : WhitePixel (dpy, DefaultScreen (dpy)));
1414
1415   XSetForeground (dpy, gc, fg);
1416   XSetBackground (dpy, gc, bg);
1417   XSetForeground (dpy, cgc, pbg);
1418   XSetBackground (dpy, cgc, bg);
1419   XSetForeground (dpy, tgc, pfg);
1420   XSetBackground (dpy, tgc, bg);
1421   XSetForeground (dpy, logo_gc, lfg);
1422   XSetBackground (dpy, logo_gc, bg);
1423   XSetForeground (dpy, erase_gc, bg);
1424   XSetBackground (dpy, erase_gc, bg);
1425
1426   XSetStipple (dpy, cgc, gray);
1427   XSetFillStyle (dpy, cgc, FillOpaqueStippled);
1428   
1429 #ifdef XROGER
1430   {
1431     int w, h;
1432     XGCValues gcv;
1433     GC draw_gc, erase_gc;
1434     /* round up to grid size */
1435     w = ((logo_width  / grid_width) + 1)  * grid_width;
1436     h = ((logo_height / grid_height) + 1) * grid_height;
1437     logo_map = XCreatePixmap (dpy, win, w, h, 1);
1438     gcv.foreground = 1L;
1439     draw_gc = XCreateGC (dpy, logo_map, GCForeground, &gcv);
1440     gcv.foreground = 0L;
1441     erase_gc= XCreateGC (dpy, logo_map, GCForeground, &gcv);
1442     XFillRectangle (dpy, logo_map, erase_gc, 0, 0, w, h);
1443     skull (dpy, logo_map, draw_gc, erase_gc, 5, 0, w-10, h-10);
1444     XFreeGC (dpy, draw_gc);
1445     XFreeGC (dpy, erase_gc);
1446   }
1447 #else
1448   if  (!(logo_map = XCreateBitmapFromData (dpy, win, logo_bits,
1449                                            logo_width, logo_height)))
1450     {
1451       fprintf (stderr, "Can't create logo pixmap\n");
1452       exit (1);
1453     }
1454 #endif
1455   XMapRaised(dpy, win);
1456
1457   restart = root;
1458
1459   sync_p = !(random() % 10);
1460
1461   while (1) {                            /* primary execution loop [ rhess ] */
1462     if (check_events()) continue ;
1463     if (restart || stop) goto pop;
1464     switch (state) {
1465     case 1:
1466       initialize_maze();
1467       break;
1468     case 2:
1469       XClearWindow(dpy, win);
1470       draw_maze_border();
1471       break;
1472     case 3:
1473       this_gen = generator;
1474       if(this_gen<0 || this_gen>2)
1475         this_gen = random()%3;
1476
1477       switch(this_gen)
1478         {
1479         case 0:
1480           create_maze();
1481           break;
1482         case 1:
1483           alt_create_maze();
1484           break;
1485         case 2:
1486           set_create_maze();
1487           break;
1488         }
1489       break;
1490     case 4:
1491       XSync (dpy, False);
1492       usleep (pre_solve_delay);
1493       break;
1494     case 5:
1495       solve_maze();
1496       break;
1497     case 6:
1498       XSync (dpy, False);
1499       usleep (post_solve_delay);
1500       state = 0 ;
1501       break;
1502     default:
1503       abort ();
1504     }
1505     ++state;
1506   pop:
1507     if (restart)
1508       {
1509         static XWindowAttributes wattr;
1510         restart = 0;
1511         stop = 0;
1512         state = 1;
1513         XGetWindowAttributes (dpy, win, &wattr);
1514         set_maze_sizes (wattr.width, wattr.height);
1515         XClearWindow (dpy, win);
1516         XSync (dpy, False);
1517         sync_p = !(random() % 10);
1518       }
1519   }
1520 }