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