1 /******************************************************************************
4 * modified: [ 1-04-00 ] Johannes Keukelaar <johannes@nada.kth.se>
5 * Added -ignorant option (not the default) to remove knowlege
6 * of the direction in which the exit lies.
8 * modified: [ 6-28-98 ] Zack Weinberg <zack@rabi.phys.columbia.edu>
10 * Made the maze-solver somewhat more intelligent. There are
11 * three optimizations:
13 * - Straight-line lookahead: the solver does not enter dead-end
14 * corridors. This is a win with all maze generators.
16 * - First order direction choice: the solver knows where the
17 * exit is in relation to itself, and will try paths leading in
18 * that direction first. This is a major win on maze generator 1
19 * which tends to offer direct routes to the exit.
21 * - Dead region elimination: the solver already has a map of
22 * all squares visited. Whenever it starts to backtrack, it
23 * consults this map and marks off all squares that cannot be
24 * reached from the exit without crossing a square already
25 * visited. Those squares can never contribute to the path to
26 * the exit, so it doesn't bother checking them. This helps a
27 * lot with maze generator 2 and somewhat less with generator 1.
29 * Further improvements would require knowledge of the wall map
30 * as well as the position of the exit and the squares visited.
31 * I would consider that to be cheating. Generator 0 makes
32 * mazes which are remarkably difficult to solve mechanically --
33 * even with these optimizations the solver generally must visit
34 * at least two-thirds of the squares. This is partially
35 * because generator 0's mazes have longer paths to the exit.
37 * modified: [ 4-10-97 ] Johannes Keukelaar <johannes@nada.kth.se>
38 * Added multiple maze creators. Robustified solver.
39 * Added bridge option.
40 * modified: [ 8-11-95 ] Ed James <james@mml.mmc.com>
41 * added fill of dead-end box to solve_maze while loop.
42 * modified: [ 3-7-93 ] Jamie Zawinski <jwz@jwz.org>
43 * added the XRoger logo, cleaned up resources, made
44 * grid size a parameter.
45 * modified: [ 3-3-93 ] Jim Randell <jmr@mddjmr.fc.hp.com>
46 * Added the colour stuff and integrated it with jwz's
47 * screenhack stuff. There's still some work that could
48 * be done on this, particularly allowing a resource to
49 * specify how big the squares are.
50 * modified: [ 10-4-88 ] Richard Hess ...!uunet!cimshop!rhess
51 * [ Revised primary execution loop within main()...
52 * [ Extended X event handler, check_events()...
53 * modified: [ 1-29-88 ] Dave Lemke lemke@sun.com
55 * [ Note the word "hacked" -- this is extremely ugly, but at
56 * [ least it does the job. NOT a good programming example
58 * original: [ 6/21/85 ] Martin Weiss Sun Microsystems [ SunView ]
60 ******************************************************************************
61 Copyright 1988 by Sun Microsystems, Inc. Mountain View, CA.
65 Permission to use, copy, modify, and distribute this software and its
66 documentation for any purpose and without fee is hereby granted,
67 provided that the above copyright notice appear in all copies and that
68 both that copyright notice and this permission notice appear in
69 supporting documentation, and that the names of Sun or MIT not be
70 used in advertising or publicity pertaining to distribution of the
71 software without specific prior written permission. Sun and M.I.T.
72 make no representations about the suitability of this software for
73 any purpose. It is provided "as is" without any express or implied warranty.
75 SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
76 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
77 PURPOSE. IN NO EVENT SHALL SUN BE LIABLE FOR ANY SPECIAL, INDIRECT
78 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
79 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
80 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
81 OR PERFORMANCE OF THIS SOFTWARE.
82 *****************************************************************************/
84 #include "screenhack.h"
89 /* #include <X11/bitmaps/gray1> */
91 #define gray1_height 2
92 static const char gray1_bits[] = { 0x01, 0x02 };
95 #define MAX_MAZE_SIZE_X 1000
96 #define MAX_MAZE_SIZE_Y 1000
98 #define MOVE_LIST_SIZE (MAX_MAZE_SIZE_X * MAX_MAZE_SIZE_Y)
100 #define NOT_DEAD 0x8000
101 #define SOLVER_VISIT 0x4000
102 #define START_SQUARE 0x2000
103 #define END_SQUARE 0x1000
106 #define WALL_RIGHT 0x4
107 #define WALL_BOTTOM 0x2
108 #define WALL_LEFT 0x1
111 #define DOOR_IN_TOP 0x800
112 #define DOOR_IN_RIGHT 0x400
113 #define DOOR_IN_BOTTOM 0x200
114 #define DOOR_IN_LEFT 0x100
115 #define DOOR_IN_ANY 0xF00
117 #define DOOR_OUT_TOP 0x80
118 #define DOOR_OUT_RIGHT 0x40
119 #define DOOR_OUT_BOTTOM 0x20
120 #define DOOR_OUT_LEFT 0x10
126 #define get_random(x) (random() % (x))
129 struct move_list_struct {
132 unsigned char dir, ways;
145 GC gc, cgc, tgc, sgc, ugc, logo_gc, erase_gc;
147 int logo_width, logo_height; /* in pixels */
149 int solve_delay, pre_solve_delay, post_solve_delay;
152 unsigned short maze[MAX_MAZE_SIZE_X][MAX_MAZE_SIZE_Y];
154 struct move_list_struct move_list[MOVE_LIST_SIZE];
155 struct move_list_struct save_path[MOVE_LIST_SIZE];
156 struct move_list_struct path[MOVE_LIST_SIZE];
158 int maze_size_x, maze_size_y;
159 int sqnum, cur_sq_x, cur_sq_y, path_length;
160 int start_x, start_y, start_dir, end_x, end_y, end_dir;
161 int grid_width, grid_height;
164 int x, y, restart, stop, state, max_length;
165 int sync_p, sync_tick;
166 int bridge_p, ignorant_p;
168 struct solve_state *solve_state;
170 int *sets; /* The sets that our squares are in. */
171 int *hedges; /* The `list' of hedges. */
175 eraser_state *eraser;
184 set_maze_sizes (struct state *st, int width, int height)
186 st->maze_size_x = width / st->grid_width;
187 st->maze_size_y = height / st->grid_height;
189 if (st->maze_size_x < 4) st->maze_size_x = 4;
190 if (st->maze_size_y < 4) st->maze_size_y = 4;
195 initialize_maze (struct state *st) /* draw the surrounding wall and start/end squares */
197 register int i, j, wall;
198 int logow = 1 + st->logo_width / st->grid_width;
199 int logoh = 1 + st->logo_height / st->grid_height;
201 /* initialize all squares */
202 for ( i=0; i<st->maze_size_x; i++) {
203 for ( j=0; j<st->maze_size_y; j++) {
209 for ( i=0; i<st->maze_size_x; i++ ) {
210 st->maze[i][0] |= WALL_TOP;
214 for ( j=0; j<st->maze_size_y; j++ ) {
215 st->maze[st->maze_size_x-1][j] |= WALL_RIGHT;
219 for ( i=0; i<st->maze_size_x; i++ ) {
220 st->maze[i][st->maze_size_y-1] |= WALL_BOTTOM;
224 for ( j=0; j<st->maze_size_y; j++ ) {
225 st->maze[0][j] |= WALL_LEFT;
228 /* set start square */
229 wall = get_random(4);
232 i = get_random(st->maze_size_x);
236 i = st->maze_size_x - 1;
237 j = get_random(st->maze_size_y);
240 i = get_random(st->maze_size_x);
241 j = st->maze_size_y - 1;
245 j = get_random(st->maze_size_y);
248 st->maze[i][j] |= START_SQUARE;
249 st->maze[i][j] |= ( DOOR_IN_TOP >> wall );
250 st->maze[i][j] &= ~( WALL_TOP >> wall );
255 st->start_dir = wall;
262 i = get_random(st->maze_size_x);
266 i = st->maze_size_x - 1;
267 j = get_random(st->maze_size_y);
270 i = get_random(st->maze_size_x);
271 j = st->maze_size_y - 1;
275 j = get_random(st->maze_size_y);
278 st->maze[i][j] |= END_SQUARE;
279 st->maze[i][j] |= ( DOOR_OUT_TOP >> wall );
280 st->maze[i][j] &= ~( WALL_TOP >> wall );
286 if ((st->maze_size_x-logow >= 6) && (st->maze_size_y-logoh >= 6))
288 /* not closer than 3 grid units from a wall */
289 st->logo_x = get_random (st->maze_size_x - logow - 5) + 3;
290 st->logo_y = get_random (st->maze_size_y - logoh - 5) + 3;
291 for (i=0; i<logow; i++)
292 for (j=0; j<logoh; j++)
293 st->maze[st->logo_x + i][st->logo_y + j] |= DOOR_IN_TOP;
296 st->logo_y = st->logo_x = -1;
298 /* #### should mask out the cells covered by the FPS display if "doFPS"
299 is true. But that's hard, because the "logo_x" crap that does
300 that trick for the logo is scattered all around the code... */
303 static int choose_door (struct state *st);
304 static int backup (struct state *st);
305 static void draw_wall (struct state *, int, int, int, GC);
306 static void draw_solid_square (struct state *, int, int, int, GC);
307 /*static void enter_square (struct state *, int);*/
308 static void build_wall (struct state *, int, int, int);
309 /*static void break_wall (struct state *, int, int, int);*/
311 static void join_sets(struct state *, int, int);
315 /* Initialise the sets. */
317 init_sets(struct state *st)
323 st->sets = (int *)malloc(st->maze_size_x*st->maze_size_y*sizeof(int));
326 for(i = 0; i < st->maze_size_x*st->maze_size_y; i++)
333 st->hedges = (int *)malloc(st->maze_size_x*st->maze_size_y*2*sizeof(int));
336 for(i = 0; i < st->maze_size_x*st->maze_size_y*2; i++)
340 /* Mask out outside walls. */
341 for(i = 0; i < st->maze_size_y; i++)
343 st->hedges[2*((st->maze_size_x)*i+st->maze_size_x-1)+1] = -1;
345 for(i = 0; i < st->maze_size_x; i++)
347 st->hedges[2*((st->maze_size_y-1)*st->maze_size_x+i)] = -1;
349 /* Mask out a possible logo. */
352 int logow = 1 + st->logo_width / st->grid_width;
353 int logoh = 1 + st->logo_height / st->grid_height;
354 int bridge_dir, bridge_c;
356 if(st->bridge_p && logoh>=3 && logow>=3)
358 bridge_dir = 1+random()%2;
361 bridge_c = st->logo_y+random()%(logoh-2)+1;
365 bridge_c = st->logo_x+random()%(logow-2)+1;
374 for(xx = st->logo_x; xx < st->logo_x+logow; xx++)
375 for(yy = st->logo_y; yy < st->logo_y+logoh; yy++)
377 /* I should check for the bridge here, except that I join the
378 * bridge together below.
380 st->hedges[2*(xx+st->maze_size_x*yy)+1] = -1;
381 st->hedges[2*(xx+st->maze_size_x*yy)] = -1;
383 for(xx = st->logo_x; xx < st->logo_x+logow; xx++)
385 if(!(bridge_dir==2 && xx==bridge_c))
387 build_wall(st, xx, st->logo_y, 0);
388 build_wall(st, xx, st->logo_y+logoh, 0);
390 st->hedges[2*(xx+st->maze_size_x*(st->logo_y-1))] = -1;
393 build_wall(st, xx, bridge_c, 0);
394 build_wall(st, xx, bridge_c, 2);
397 for(yy = st->logo_y; yy < st->logo_y+logoh; yy++)
399 if(!(bridge_dir==1 && yy==bridge_c))
401 build_wall(st, st->logo_x, yy, 3);
402 build_wall(st, st->logo_x+logow, yy, 3);
404 st->hedges[2*(st->logo_x-1+st->maze_size_x*yy)+1] = -1;
407 build_wall(st, bridge_c, yy, 1);
408 build_wall(st, bridge_c, yy, 3);
411 /* Join the whole bridge together. */
418 for(i = st->logo_x; i < st->logo_x+logow+1; i++)
419 join_sets(st, xx+yy*st->maze_size_x, i+yy*st->maze_size_x);
425 for(i = st->logo_y; i < st->logo_y+logoh+1; i++)
426 join_sets(st, xx+yy*st->maze_size_x, xx+i*st->maze_size_x);
431 for(i = 0; i < st->maze_size_x*st->maze_size_y*2; i++)
434 r = random()%(st->maze_size_x*st->maze_size_y*2);
435 st->hedges[i] = st->hedges[r];
440 /* Get the representative of a set. */
442 get_set(struct state *st, int num)
446 if(st->sets[num]==num)
450 s = get_set(st, st->sets[num]);
456 /* Join two sets together. */
458 join_sets(struct state *st, int num1, int num2)
462 s1 = get_set(st, num1);
463 s2 = get_set(st, num2);
471 /* Exitialise the sets. */
473 exit_sets(struct state *st)
484 /* Temporary hack. */
486 show_set(int num, GC gc)
488 int st->x, st->y, set;
492 for(st->x = 0; st->x < st->maze_size_x; st->x++)
493 for(st->y = 0; st->y < st->maze_size_y; st->y++)
495 if(get_set(st->x+st->y*st->maze_size_x)==set)
497 XFillRectangle(st->dpy, st->window, st->gc, border_x + st->bw + st->grid_width * st->x,
498 border_y + st->bw + st->grid_height * st->y,
499 st->grid_width-2*st->bw , st->grid_height-2*st->bw);
505 /* Second alternative maze creator: Put each square in the maze in a
506 * separate set. Also, make a list of all the hedges. Randomize that list.
507 * Walk through the list. If, for a certain hedge, the two squares on both
508 * sides of it are in different sets, union the sets and remove the hedge.
509 * Continue until all hedges have been processed or only one set remains.
512 set_create_maze(struct state *st)
514 int i, h, xx, yy, dir, v, w;
520 /* Do almost all the setup. */
523 /* Start running through the hedges. */
524 for(i = 0; i < 2*st->maze_size_x*st->maze_size_y; i++)
528 /* This one is in the logo or outside border. */
533 xx = (h>>1)%st->maze_size_x;
534 yy = (h>>1)/st->maze_size_x;
549 show_set(st, xx+yy*st->maze_size_x, st->logo_gc);
550 show_set(st, v+w*st->maze_size_x, st->tgc);
552 if(get_set(st, xx+yy*st->maze_size_x)!=get_set(st, v+w*st->maze_size_x))
557 join_sets(st, xx+yy*st->maze_size_x, v+w*st->maze_size_x);
558 /* Don't draw the wall. */
565 /* Don't join the sets. */
566 build_wall(st, xx, yy, dir);
571 XSync(st->dpy, False);
576 show_set(xx+yy*st->maze_size_x, st->erase_gc);
577 show_set(v+w*st->maze_size_x, st->erase_gc);
581 /* Free some memory. */
585 /* First alternative maze creator: Pick a random, empty corner in the maze.
586 * Pick a random direction. Draw a wall in that direction, from that corner
587 * until we hit a wall. Option: Only draw the wall if it's going to be
588 * shorter than a certain length. Otherwise we get lots of long walls.
591 alt_create_maze(struct state *st)
595 int i, j, height, width, open_corners, k, dir, xx, yy;
597 height = st->maze_size_y+1;
598 width = st->maze_size_x+1;
600 /* Allocate and clear some mem. */
601 corners = (char *)calloc(height*width, 1);
605 /* Set up the indexing array. */
606 c_idx = (int *)malloc(sizeof(int)*height*width);
612 for(i = 0; i < height*width; i++)
614 for(i = 0; i < height*width; i++)
617 k = random()%(height*width);
622 /* Set up some initial walls. */
624 for(i = 0; i < width; i++)
627 corners[i+width*(height-1)] = 1;
629 for(i = 0; i < height; i++)
631 corners[i*width] = 1;
632 corners[i*width+width-1] = 1;
634 /* Walls around logo. In fact, inside the logo, too. */
635 /* Also draw the walls. */
638 int logow = 1 + st->logo_width / st->grid_width;
639 int logoh = 1 + st->logo_height / st->grid_height;
640 int bridge_dir, bridge_c;
642 if(st->bridge_p && logoh>=3 && logow>=3)
644 bridge_dir = 1+random()%2;
647 bridge_c = st->logo_y+random()%(logoh-2)+1;
651 bridge_c = st->logo_x+random()%(logow-2)+1;
659 for(i = st->logo_x; i <= st->logo_x + logow; i++)
661 for(j = st->logo_y; j <= st->logo_y + logoh; j++)
663 corners[i+width*j] = 1;
666 for(xx = st->logo_x; xx < st->logo_x+logow; xx++)
668 if(!(bridge_dir==2 && xx==bridge_c))
670 build_wall(st, xx, st->logo_y, 0);
671 build_wall(st, xx, st->logo_y+logoh, 0);
675 build_wall(st, xx, bridge_c, 0);
676 build_wall(st, xx, bridge_c, 2);
679 for(yy = st->logo_y; yy < st->logo_y+logoh; yy++)
681 if(!(bridge_dir==1 && yy==bridge_c))
683 build_wall(st, st->logo_x, yy, 3);
684 build_wall(st, st->logo_x+logow, yy, 3);
688 build_wall(st, bridge_c, yy, 1);
689 build_wall(st, bridge_c, yy, 3);
692 /* Connect one wall of the logo with an outside wall. */
694 dir = (bridge_dir+1)%4;
700 xx = st->logo_x+(random()%(logow+1));
704 xx = st->logo_x+logow;
705 yy = st->logo_y+(random()%(logoh+1));
708 xx = st->logo_x+(random()%(logow+1));
709 yy = st->logo_y+logoh;
713 yy = st->logo_y+(random()%(logoh+1));
718 corners[xx+width*yy] = 1;
722 build_wall(st, xx-1, yy-1, 1);
726 build_wall(st, xx, yy, 0);
730 build_wall(st, xx, yy, 3);
734 build_wall(st, xx-1, yy-1, 2);
739 while(!corners[xx+width*yy]);
746 xx = st->logo_x+(random()%(logow+1));
750 xx = st->logo_x+logow;
751 yy = st->logo_y+(random()%(logoh+1));
754 xx = st->logo_x+(random()%(logow+1));
755 yy = st->logo_y+logoh;
759 yy = st->logo_y+(random()%(logoh+1));
764 corners[xx+width*yy] = 1;
768 build_wall(st, xx-1, yy-1, 1);
772 build_wall(st, xx, yy, 0);
776 build_wall(st, xx, yy, 3);
780 build_wall(st, xx-1, yy-1, 2);
785 while(!corners[xx+width*yy]);
789 /* Count open gridpoints. */
791 for(i = 0; i < width; i++)
792 for(j = 0; j < height; j++)
793 if(!corners[i+width*j])
796 /* Now do actual maze generation. */
797 while(open_corners>0)
799 for(i = 0; i < width*height; i++)
801 if(!corners[c_idx[i]])
805 /* Choose a random direction. */
809 /* Measure the length of the wall we'd draw. */
810 while(!corners[xx+width*yy])
830 if(k<=st->max_length)
835 /* Draw a wall until we hit something. */
836 while(!corners[xx+width*yy])
839 corners[xx+width*yy] = 1;
843 build_wall(st, xx-1, yy-1, 1);
847 build_wall(st, xx, yy, 0);
851 build_wall(st, xx, yy, 3);
855 build_wall(st, xx-1, yy-1, 2);
865 /* Free some memory we used. */
870 /* The original maze creator. Start somewhere. Take a step in a random
871 * direction. Keep doing this until we hit a wall. Then, backtrack until
872 * we find a point where we can go in another direction.
875 create_maze (struct state *st) /* create a maze layout given the initialized maze */
877 register int i, newdoor = 0;
878 int logow = 1 + st->logo_width / st->grid_width;
879 int logoh = 1 + st->logo_height / st->grid_height;
881 /* Maybe we should make a bridge? */
882 if(st->bridge_p && st->logo_x >= 0 && logow>=3 && logoh>=3)
884 int bridge_dir, bridge_c;
886 bridge_dir = 1+random()%2;
890 bridge_c = st->logo_y+random()%(logoh-2)+1;
892 bridge_c = st->logo_y+random()%logoh;
897 bridge_c = st->logo_x+random()%(logow-2)+1;
899 bridge_c = st->logo_x+random()%logow;
904 for(i = st->logo_x; i < st->logo_x+logow; i++)
906 st->maze[i][bridge_c] &= ~DOOR_IN_TOP;
911 for(i = st->logo_y; i < st->logo_y+logoh; i++)
913 st->maze[bridge_c][i] &= ~DOOR_IN_TOP;
919 st->move_list[st->sqnum].x = st->cur_sq_x;
920 st->move_list[st->sqnum].y = st->cur_sq_y;
921 st->move_list[st->sqnum].dir = newdoor;
922 while ( ( newdoor = choose_door(st) ) == -1 ) { /* pick a door */
923 if ( backup(st) == -1 ) { /* no more doors ... backup */
924 return; /* done ... return */
928 /* mark the out door */
929 st->maze[st->cur_sq_x][st->cur_sq_y] |= ( DOOR_OUT_TOP >> newdoor );
932 case 0: st->cur_sq_y--;
934 case 1: st->cur_sq_x++;
936 case 2: st->cur_sq_y++;
938 case 3: st->cur_sq_x--;
943 /* mark the in door */
944 st->maze[st->cur_sq_x][st->cur_sq_y] |= ( DOOR_IN_TOP >> ((newdoor+2)%4) );
946 /* if end square set path length and save path */
947 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & END_SQUARE ) {
948 st->path_length = st->sqnum;
949 for ( i=0; i<st->path_length; i++) {
950 st->save_path[i].x = st->move_list[i].x;
951 st->save_path[i].y = st->move_list[i].y;
952 st->save_path[i].dir = st->move_list[i].dir;
962 choose_door (struct state *st) /* pick a new path */
965 register int num_candidates;
970 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_TOP )
972 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_TOP )
974 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_TOP )
976 if ( st->maze[st->cur_sq_x][st->cur_sq_y - 1] & DOOR_IN_ANY ) {
977 st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_TOP;
978 st->maze[st->cur_sq_x][st->cur_sq_y - 1] |= WALL_BOTTOM;
979 draw_wall(st, st->cur_sq_x, st->cur_sq_y, 0, st->gc);
982 candidates[num_candidates++] = 0;
986 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_RIGHT )
988 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_RIGHT )
990 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_RIGHT )
992 if ( st->maze[st->cur_sq_x + 1][st->cur_sq_y] & DOOR_IN_ANY ) {
993 st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_RIGHT;
994 st->maze[st->cur_sq_x + 1][st->cur_sq_y] |= WALL_LEFT;
995 draw_wall(st, st->cur_sq_x, st->cur_sq_y, 1, st->gc);
998 candidates[num_candidates++] = 1;
1002 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_BOTTOM )
1004 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_BOTTOM )
1006 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_BOTTOM )
1008 if ( st->maze[st->cur_sq_x][st->cur_sq_y + 1] & DOOR_IN_ANY ) {
1009 st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_BOTTOM;
1010 st->maze[st->cur_sq_x][st->cur_sq_y + 1] |= WALL_TOP;
1011 draw_wall(st, st->cur_sq_x, st->cur_sq_y, 2, st->gc);
1014 candidates[num_candidates++] = 2;
1018 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_IN_LEFT )
1020 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & DOOR_OUT_LEFT )
1022 if ( st->maze[st->cur_sq_x][st->cur_sq_y] & WALL_LEFT )
1024 if ( st->maze[st->cur_sq_x - 1][st->cur_sq_y] & DOOR_IN_ANY ) {
1025 st->maze[st->cur_sq_x][st->cur_sq_y] |= WALL_LEFT;
1026 st->maze[st->cur_sq_x - 1][st->cur_sq_y] |= WALL_RIGHT;
1027 draw_wall(st, st->cur_sq_x, st->cur_sq_y, 3, st->gc);
1030 candidates[num_candidates++] = 3;
1033 if (num_candidates == 0)
1035 if (num_candidates == 1)
1036 return ( candidates[0] );
1037 return ( candidates[ get_random(num_candidates) ] );
1043 backup (struct state *st) /* back up a move */
1046 st->cur_sq_x = st->move_list[st->sqnum].x;
1047 st->cur_sq_y = st->move_list[st->sqnum].y;
1048 return ( st->sqnum );
1053 draw_maze_border (struct state *st) /* draw the maze outline */
1058 for ( i=0; i<st->maze_size_x; i++) {
1059 if ( st->maze[i][0] & WALL_TOP ) {
1060 XDrawLine(st->dpy, st->window, st->gc,
1061 border_x + st->grid_width * i,
1063 border_x + st->grid_width * (i+1) - 1,
1066 if ((st->maze[i][st->maze_size_y - 1] & WALL_BOTTOM)) {
1067 XDrawLine(st->dpy, st->window, st->gc,
1068 border_x + st->grid_width * i,
1069 border_y + st->grid_height * (st->maze_size_y) - 1,
1070 border_x + st->grid_width * (i+1) - 1,
1071 border_y + st->grid_height * (st->maze_size_y) - 1);
1074 for ( j=0; j<st->maze_size_y; j++) {
1075 if ( st->maze[st->maze_size_x - 1][j] & WALL_RIGHT ) {
1076 XDrawLine(st->dpy, st->window, st->gc,
1077 border_x + st->grid_width * st->maze_size_x - 1,
1078 border_y + st->grid_height * j,
1079 border_x + st->grid_width * st->maze_size_x - 1,
1080 border_y + st->grid_height * (j+1) - 1);
1082 if ( st->maze[0][j] & WALL_LEFT ) {
1083 XDrawLine(st->dpy, st->window, st->gc,
1085 border_y + st->grid_height * j,
1087 border_y + st->grid_height * (j+1) - 1);
1091 if (st->logo_x != -1)
1095 unsigned int w, h, bbw, d;
1097 /* round up to grid size */
1098 int ww = ((st->logo_width / st->grid_width) + 1) * st->grid_width;
1099 int hh = ((st->logo_height / st->grid_height) + 1) * st->grid_height;
1102 XGetGeometry (st->dpy, st->logo_map, &r, &xx, &yy, &w, &h, &bbw, &d);
1104 /* kludge: if the logo "hole" is around the same size as the logo,
1105 don't center it (since the xscreensaver logo image is a little
1106 off center... But do center it if the hole/gridsize is large. */
1107 if (ww < st->logo_width + 5) ww = w;
1108 if (hh < st->logo_height + 5) hh = h;
1111 lx = border_x + 3 + st->grid_width * st->logo_x + ((ww - w) / 2);
1112 ly = border_y + 3 + st->grid_height * st->logo_y + ((hh - h) / 2);
1114 /* Fill the background of the logo box with the "unreachable" color */
1115 XFillRectangle (st->dpy, st->window, st->ugc,
1116 border_x + 3 + st->grid_width * st->logo_x,
1117 border_y + 3 + st->grid_height * st->logo_y,
1120 XSetClipOrigin (st->dpy, st->logo_gc, lx, ly);
1122 XCopyPlane (st->dpy, st->logo_map, st->window, st->logo_gc,
1123 0, 0, w, h, lx, ly, 1);
1125 XCopyArea (st->dpy, st->logo_map, st->window, st->logo_gc,
1126 0, 0, w, h, lx, ly);
1128 draw_solid_square (st, st->start_x, st->start_y, WALL_TOP >> st->start_dir, st->tgc);
1129 draw_solid_square (st, st->end_x, st->end_y, WALL_TOP >> st->end_dir, st->tgc);
1134 draw_wall(struct state *st, int i, int j, int dir, GC with_gc) /* draw a single wall */
1138 XDrawLine(st->dpy, st->window, with_gc,
1139 border_x + st->grid_width * i,
1140 border_y + st->grid_height * j,
1141 border_x + st->grid_width * (i+1),
1142 border_y + st->grid_height * j);
1145 XDrawLine(st->dpy, st->window, with_gc,
1146 border_x + st->grid_width * (i+1),
1147 border_y + st->grid_height * j,
1148 border_x + st->grid_width * (i+1),
1149 border_y + st->grid_height * (j+1));
1152 XDrawLine(st->dpy, st->window, with_gc,
1153 border_x + st->grid_width * i,
1154 border_y + st->grid_height * (j+1),
1155 border_x + st->grid_width * (i+1),
1156 border_y + st->grid_height * (j+1));
1159 XDrawLine(st->dpy, st->window, with_gc,
1160 border_x + st->grid_width * i,
1161 border_y + st->grid_height * j,
1162 border_x + st->grid_width * i,
1163 border_y + st->grid_height * (j+1));
1168 /* too slow if we sync on every wall, so only sync about ten times
1169 during the maze-creation process.
1172 if (st->sync_tick <= 0) {
1173 XSync(st->dpy, False);
1174 st->sync_tick = st->maze_size_x * st->maze_size_x / 10;
1179 /* Actually build a wall. */
1181 build_wall(struct state *st, int i, int j, int dir)
1183 /* Draw it on the screen. */
1184 draw_wall(st, i, j, dir, st->gc);
1185 /* Put it in the maze. */
1189 st->maze[i][j] |= WALL_TOP;
1191 st->maze[i][j-1] |= WALL_BOTTOM;
1194 st->maze[i][j] |= WALL_RIGHT;
1195 if(i<st->maze_size_x-1)
1196 st->maze[i+1][j] |= WALL_LEFT;
1199 st->maze[i][j] |= WALL_BOTTOM;
1200 if(j<st->maze_size_y-1)
1201 st->maze[i][j+1] |= WALL_TOP;
1204 st->maze[i][j] |= WALL_LEFT;
1206 st->maze[i-1][j] |= WALL_RIGHT;
1211 /* Break out a wall. */
1214 break_wall(i, j, dir)
1217 /* Draw it on the screen. */
1218 draw_wall(i, j, dir, st->erase_gc);
1219 /* Put it in the maze. */
1223 st->maze[i][j] &= ~WALL_TOP;
1225 maze[i][j-1] &= ~WALL_BOTTOM;
1228 st->maze[i][j] &= ~WALL_RIGHT;
1229 if(i<st->maze_size_x-1)
1230 maze[i+1][j] &= ~WALL_LEFT;
1233 st->maze[i][j] &= ~WALL_BOTTOM;
1234 if(j<st->maze_size_y-1)
1235 maze[i][j+1] &= ~WALL_BOTTOM;
1238 st->maze[i][j] &= ~WALL_LEFT;
1240 maze[i-1][j] &= ~WALL_RIGHT;
1248 draw_solid_square(struct state *st,
1249 int i, int j, /* draw a solid square in a square */
1250 int dir, GC with_gc)
1254 XFillRectangle(st->dpy, st->window, with_gc,
1255 border_x + st->bw+(st->bw==0?1:0) + st->grid_width * i,
1256 border_y - st->bw-(st->bw==0?1:0) + st->grid_height * j,
1257 st->grid_width - (st->bw+st->bw+(st->bw==0?1:0)), st->grid_height);
1260 XFillRectangle(st->dpy, st->window, with_gc,
1261 border_x + st->bw+(st->bw==0?1:0) + st->grid_width * i,
1262 border_y + st->bw+(st->bw==0?1:0) + st->grid_height * j,
1263 st->grid_width, st->grid_height - (st->bw+st->bw+(st->bw==0?1:0)));
1266 XFillRectangle(st->dpy, st->window, with_gc,
1267 border_x + st->bw+(st->bw==0?1:0) + st->grid_width * i,
1268 border_y + st->bw+(st->bw==0?1:0) + st->grid_height * j,
1269 st->grid_width - (st->bw+st->bw+(st->bw==0?1:0)), st->grid_height);
1272 XFillRectangle(st->dpy, st->window, with_gc,
1273 border_x - st->bw-(st->bw==0?1:0) + st->grid_width * i,
1274 border_y + st->bw+(st->bw==0?1:0) + st->grid_height * j,
1275 st->grid_width, st->grid_height - (st->bw+st->bw+(st->bw==0?1:0)));
1281 longdeadend_p(struct state *st, int x1, int y1, int x2, int y2, int endwall)
1283 int dx = x2 - x1, dy = y2 - y1;
1286 sidewalls = endwall | (endwall >> 2 | endwall << 2);
1287 sidewalls = ~sidewalls & WALL_ANY;
1289 while((st->maze[x2][y2] & WALL_ANY) == sidewalls)
1291 if (x2 + dx < 0 || x2 + dx >= st->maze_size_x ||
1292 y2 + dy < 0 || y2 + dy >= st->maze_size_y)
1298 if((st->maze[x2][y2] & WALL_ANY) == (sidewalls | endwall))
1300 endwall = (endwall >> 2 | endwall << 2) & WALL_ANY;
1301 while(x1 != x2 || y1 != y2)
1305 draw_solid_square(st, x1, y1, endwall, st->sgc);
1306 st->maze[x1][y1] |= SOLVER_VISIT;
1314 /* Find all dead regions -- areas from which the goal cannot be reached --
1315 and mark them visited. */
1317 find_dead_regions(struct state *st)
1319 int xx, yy, flipped;
1321 /* Find all not SOLVER_VISIT squares bordering NOT_DEAD squares
1322 and mark them NOT_DEAD also. Repeat until no more such squares. */
1323 st->maze[st->start_x][st->start_y] |= NOT_DEAD;
1328 for(xx = 0; xx < st->maze_size_x; xx++)
1329 for(yy = 0; yy < st->maze_size_y; yy++)
1330 if(!(st->maze[xx][yy] & (SOLVER_VISIT | NOT_DEAD))
1331 && ( (xx && (st->maze[xx-1][yy] & NOT_DEAD))
1332 || (yy && (st->maze[xx][yy-1] & NOT_DEAD))))
1335 st->maze[xx][yy] |= NOT_DEAD;
1337 for(xx = st->maze_size_x-1; xx >= 0; xx--)
1338 for(yy = st->maze_size_y-1; yy >= 0; yy--)
1339 if(!(st->maze[xx][yy] & (SOLVER_VISIT | NOT_DEAD))
1340 && ( (xx != st->maze_size_x-1 && (st->maze[xx+1][yy] & NOT_DEAD))
1341 || (yy != st->maze_size_y-1 && (st->maze[xx][yy+1] & NOT_DEAD))))
1344 st->maze[xx][yy] |= NOT_DEAD;
1349 for (yy = 0; yy < st->maze_size_y; yy++)
1350 for (xx = 0; xx < st->maze_size_x; xx++)
1352 if (st->maze[xx][yy] & NOT_DEAD)
1353 st->maze[xx][yy] &= ~NOT_DEAD;
1354 else if (!(st->maze[xx][yy] & SOLVER_VISIT))
1356 st->maze[xx][yy] |= SOLVER_VISIT;
1357 if((xx < st->logo_x || xx > st->logo_x + st->logo_width / st->grid_width) ||
1358 (yy < st->logo_y || yy > st->logo_y + st->logo_height / st->grid_height))
1360 /* if we are completely surrounded by walls, just draw the
1362 if ((st->maze[xx][yy] & WALL_ANY) == WALL_ANY)
1363 XFillRectangle(st->dpy, st->window, st->ugc,
1364 border_x + st->bw + st->grid_width * xx,
1365 border_y + st->bw + st->grid_height * yy,
1366 st->grid_width - (st->bw+st->bw), st->grid_height - (st->bw+st->bw));
1369 if (! (st->maze[xx][yy] & WALL_LEFT))
1370 draw_solid_square(st, xx, yy, WALL_LEFT, st->ugc);
1371 if (! (st->maze[xx][yy] & WALL_RIGHT))
1372 draw_solid_square(st, xx, yy, WALL_RIGHT, st->ugc);
1373 if (! (st->maze[xx][yy] & WALL_TOP))
1374 draw_solid_square(st, xx, yy, WALL_TOP, st->ugc);
1375 if (! (st->maze[xx][yy] & WALL_BOTTOM))
1376 draw_solid_square(st, xx, yy, WALL_BOTTOM, st->ugc);
1384 solve_maze (struct state *st) /* solve it with graphical feedback */
1386 struct solve_state *ss = st->solve_state;
1388 ss = st->solve_state = (struct solve_state *) calloc (1, sizeof(*ss));
1391 /* plug up the surrounding wall */
1392 st->maze[st->end_x][st->end_y] |= (WALL_TOP >> st->end_dir);
1394 /* initialize search path */
1396 st->path[ss->i].x = st->end_x;
1397 st->path[ss->i].y = st->end_y;
1398 st->path[ss->i].dir = 0;
1399 st->maze[st->end_x][st->end_y] |= SOLVER_VISIT;
1407 int dir, from, ways;
1409 if ( st->maze[st->path[ss->i].x][st->path[ss->i].y] & START_SQUARE )
1415 if(!st->path[ss->i].dir)
1418 /* First visit this square. Which adjacent squares are open? */
1419 for(dir = WALL_TOP; dir & WALL_ANY; dir >>= 1)
1421 if(st->maze[st->path[ss->i].x][st->path[ss->i].y] & dir)
1424 ss->y = st->path[ss->i].y - !!(dir & WALL_TOP) + !!(dir & WALL_BOTTOM);
1425 ss->x = st->path[ss->i].x + !!(dir & WALL_RIGHT) - !!(dir & WALL_LEFT);
1427 if(st->maze[ss->x][ss->y] & SOLVER_VISIT)
1430 from = (dir << 2 & WALL_ANY) | (dir >> 2 & WALL_ANY);
1431 /* don't enter obvious dead ends */
1432 if(((st->maze[ss->x][ss->y] & WALL_ANY) | from) != WALL_ANY)
1434 if(!longdeadend_p(st, st->path[ss->i].x, st->path[ss->i].y, ss->x, ss->y, dir))
1439 draw_solid_square(st, ss->x, ss->y, from, st->sgc);
1440 st->maze[ss->x][ss->y] |= SOLVER_VISIT;
1445 ways = st->path[ss->i].ways;
1446 /* ways now has a bitmask of open paths. */
1451 if (!st->ignorant_p)
1453 ss->x = st->path[ss->i].x - st->start_x;
1454 ss->y = st->path[ss->i].y - st->start_y;
1456 if(abs(ss->y) <= abs(ss->x))
1457 dir = (ss->x > 0) ? WALL_LEFT : WALL_RIGHT;
1459 dir = (ss->y > 0) ? WALL_TOP : WALL_BOTTOM;
1469 dir = (ss->y > 0) ? WALL_TOP : WALL_BOTTOM; break;
1472 dir = (ss->x > 0) ? WALL_LEFT : WALL_RIGHT;
1480 dir = (dir << 2 & WALL_ANY) | (dir >> 2 & WALL_ANY);
1495 else if(ways&WALL_LEFT)
1497 else if(ways&WALL_BOTTOM)
1499 else if(ways&WALL_RIGHT)
1505 ways &= ~dir; /* tried this one */
1507 ss->y = st->path[ss->i].y - !!(dir & WALL_TOP) + !!(dir & WALL_BOTTOM);
1508 ss->x = st->path[ss->i].x + !!(dir & WALL_RIGHT) - !!(dir & WALL_LEFT);
1510 /* advance in direction dir */
1511 st->path[ss->i].dir = dir;
1512 st->path[ss->i].ways = ways;
1513 draw_solid_square(st, st->path[ss->i].x, st->path[ss->i].y, dir, st->tgc);
1516 st->path[ss->i].dir = 0;
1517 st->path[ss->i].ways = 0;
1518 st->path[ss->i].x = ss->x;
1519 st->path[ss->i].y = ss->y;
1520 st->maze[ss->x][ss->y] |= SOLVER_VISIT;
1527 printf("Unsolvable maze.\n");
1532 if(!ss->bt && !st->ignorant_p)
1533 find_dead_regions(st);
1535 from = st->path[ss->i-1].dir;
1536 from = (from << 2 & WALL_ANY) | (from >> 2 & WALL_ANY);
1538 draw_solid_square(st, st->path[ss->i].x, st->path[ss->i].y, from, st->cgc);
1547 enter_square (int n) /* move into a neighboring square */
1549 draw_solid_square( (int)st->path[n].x, (int)st->path[n].y,
1550 (int)st->path[n].dir, st->tgc);
1552 st->path[n+1].dir = -1;
1553 switch (st->path[n].dir) {
1554 case 0: st->path[n+1].x = st->path[n].x;
1555 st->path[n+1].y = st->path[n].y - 1;
1557 case 1: st->path[n+1].x = st->path[n].x + 1;
1558 st->path[n+1].y = st->path[n].y;
1560 case 2: st->path[n+1].x = st->path[n].x;
1561 st->path[n+1].y = st->path[n].y + 1;
1563 case 3: st->path[n+1].x = st->path[n].x - 1;
1564 st->path[n+1].y = st->path[n].y;
1572 * jmr additions for Jamie Zawinski's <jwz@jwz.org> screensaver stuff,
1573 * note that the code above this has probably been hacked about in some
1577 static const char *maze_defaults[] = {
1578 ".background: black",
1579 ".foreground: white",
1587 "*solveDelay: 10000",
1588 "*preDelay: 2000000",
1589 "*postDelay: 4000000",
1591 "*liveColor: #00FF00",
1592 "*deadColor: #880000",
1593 "*skipColor: #8B5A00",
1594 "*surroundColor: #220055",
1599 static XrmOptionDescRec maze_options[] = {
1600 { "-ignorant", ".ignorant", XrmoptionNoArg, "True" },
1601 { "-no-ignorant", ".ignorant", XrmoptionNoArg, "False" },
1602 { "-grid-size", ".gridSize", XrmoptionSepArg, 0 },
1603 { "-solve-delay", ".solveDelay", XrmoptionSepArg, 0 },
1604 { "-pre-delay", ".preDelay", XrmoptionSepArg, 0 },
1605 { "-post-delay", ".postDelay", XrmoptionSepArg, 0 },
1606 { "-bg-color", ".background", XrmoptionSepArg, 0 },
1607 { "-fg-color", ".foreground", XrmoptionSepArg, 0 },
1608 { "-live-color", ".liveColor", XrmoptionSepArg, 0 },
1609 { "-dead-color", ".deadColor", XrmoptionSepArg, 0 },
1610 { "-skip-color", ".skipColor", XrmoptionSepArg, 0 },
1611 { "-surround-color", ".surroundColor",XrmoptionSepArg, 0 },
1612 { "-generator", ".generator", XrmoptionSepArg, 0 },
1613 { "-max-length", ".maxLength", XrmoptionSepArg, 0 },
1614 { "-bridge", ".bridge", XrmoptionNoArg, "True" },
1615 { "-no-bridge", ".bridge", XrmoptionNoArg, "False" },
1619 static int generator = 0;
1622 maze_init (Display *dpy_arg, Window window_arg)
1624 struct state *st = (struct state *) calloc (1, sizeof(*st));
1629 XWindowAttributes xgwa;
1630 unsigned long bg, fg, pfg, pbg, sfg, ufg;
1633 st->window = window_arg;
1642 size = get_integer_resource (st->dpy, "gridSize", "Dimension");
1643 st->solve_delay = get_integer_resource (st->dpy, "solveDelay", "Integer");
1644 st->pre_solve_delay = get_integer_resource (st->dpy, "preDelay", "Integer");
1645 st->post_solve_delay = get_integer_resource (st->dpy, "postDelay", "Integer");
1646 generator = get_integer_resource(st->dpy, "generator", "Integer");
1647 st->max_length = get_integer_resource(st->dpy, "maxLength", "Integer");
1648 st->bridge_p = get_boolean_resource(st->dpy, "bridge", "Boolean");
1649 st->ignorant_p = get_boolean_resource(st->dpy, "ignorant", "Boolean");
1651 if (!size) st->ifrandom = 1;
1653 if (size < 2) size = 7 + (random () % 30);
1654 st->grid_width = st->grid_height = size;
1655 st->bw = (size > 6 ? 3 : (size-1)/2);
1657 XGetWindowAttributes (st->dpy, st->window, &xgwa);
1662 set_maze_sizes (st, xgwa.width, xgwa.height);
1664 st->gc = XCreateGC(st->dpy, st->window, 0, 0);
1665 st->cgc = XCreateGC(st->dpy, st->window, 0, 0);
1666 st->tgc = XCreateGC(st->dpy, st->window, 0, 0);
1667 st->sgc = XCreateGC(st->dpy, st->window, 0, 0);
1668 st->ugc = XCreateGC(st->dpy, st->window, 0, 0);
1669 st->logo_gc = XCreateGC(st->dpy, st->window, 0, 0);
1670 st->erase_gc = XCreateGC(st->dpy, st->window, 0, 0);
1673 gray = XCreateBitmapFromData (st->dpy,st->window,gray1_bits,gray1_width,gray1_height);
1676 bg = get_pixel_resource (st->dpy, xgwa.colormap, "background","Background");
1677 fg = get_pixel_resource (st->dpy, xgwa.colormap, "foreground","Foreground");
1678 pfg = get_pixel_resource (st->dpy, xgwa.colormap, "liveColor", "Foreground");
1679 pbg = get_pixel_resource (st->dpy, xgwa.colormap, "deadColor", "Foreground");
1680 sfg = get_pixel_resource (st->dpy, xgwa.colormap, "skipColor", "Foreground");
1681 ufg = get_pixel_resource (st->dpy, xgwa.colormap, "surroundColor", "Foreground");
1683 XSetForeground (st->dpy, st->gc, fg);
1684 XSetBackground (st->dpy, st->gc, bg);
1685 XSetForeground (st->dpy, st->cgc, pbg);
1686 XSetBackground (st->dpy, st->cgc, bg);
1687 XSetForeground (st->dpy, st->tgc, pfg);
1688 XSetBackground (st->dpy, st->tgc, bg);
1689 XSetForeground (st->dpy, st->sgc, sfg);
1690 XSetBackground (st->dpy, st->sgc, bg);
1691 XSetForeground (st->dpy, st->ugc, ufg);
1692 XSetBackground (st->dpy, st->ugc, bg);
1693 XSetForeground (st->dpy, st->logo_gc, fg);
1694 XSetBackground (st->dpy, st->logo_gc, bg);
1695 XSetForeground (st->dpy, st->erase_gc, bg);
1696 XSetBackground (st->dpy, st->erase_gc, bg);
1699 XSetStipple (st->dpy, st->cgc, gray);
1700 XSetFillStyle (st->dpy, st->cgc, FillOpaqueStippled);
1701 XSetStipple (st->dpy, st->sgc, gray);
1702 XSetFillStyle (st->dpy, st->sgc, FillOpaqueStippled);
1703 XSetStipple (st->dpy, st->ugc, gray);
1704 XSetFillStyle (st->dpy, st->ugc, FillOpaqueStippled);
1710 unsigned int w, h, bbw, d;
1711 unsigned long *pixels;
1713 Pixmap logo_mask = 0;
1714 st->logo_map = xscreensaver_logo (xgwa.screen, xgwa.visual, st->window,
1716 &pixels, &npixels, &logo_mask,
1719 XSetClipMask (st->dpy, st->logo_gc, logo_mask);
1720 XFreePixmap (st->dpy, logo_mask);
1722 if (pixels) free (pixels);
1723 XGetGeometry (st->dpy, st->logo_map, &r, &x, &y, &w, &h, &bbw, &d);
1725 st->logo_height = h;
1737 maze_reshape (Display *dpy, Window window, void *closure,
1738 unsigned int w, unsigned int h)
1740 struct state *st = (struct state *) closure;
1745 static unsigned long
1746 maze_draw (Display *dpy, Window window, void *closure)
1748 struct state *st = (struct state *) closure;
1749 int this_delay = st->solve_delay;
1751 if (st->eraser || st->erase_window)
1753 st->erase_window = 0;
1754 st->eraser = erase_window (st->dpy, st->window, st->eraser);
1758 this_delay = 1000000;
1759 if (this_delay > st->pre_solve_delay)
1760 this_delay = st->pre_solve_delay;
1765 if (st->restart || st->stop) goto pop;
1766 switch (st->state) {
1768 initialize_maze(st);
1769 if (st->ifrandom && st->ifinit)
1772 size = 7 + (random () % 30);
1773 st->grid_width = st->grid_height = size;
1774 st->bw = (size > 6 ? 3 : (size-1)/2);
1780 XClearWindow(st->dpy, st->window);
1781 draw_maze_border(st);
1784 st->this_gen = generator;
1785 if(st->this_gen<0 || st->this_gen>2)
1786 st->this_gen = random()%3;
1788 switch(st->this_gen)
1794 alt_create_maze(st);
1797 set_create_maze(st);
1802 this_delay = st->pre_solve_delay;
1805 if (! solve_maze(st))
1806 --st->state; /* stay in state 5 */
1809 st->erase_window = 1;
1810 this_delay = st->post_solve_delay;
1821 XWindowAttributes xgwa;
1828 st->sync_p = ((random() % 4) != 0);
1830 size = get_integer_resource (st->dpy, "gridSize", "Dimension");
1831 if (size < 2) size = 7 + (random () % 30);
1832 st->grid_width = st->grid_height = size;
1833 st->bw = (size > 6 ? 3 : (size-1)/2);
1835 XGetWindowAttributes (st->dpy, st->window, &xgwa);
1836 set_maze_sizes (st, xgwa.width, xgwa.height);
1845 maze_event (Display *dpy, Window window, void *closure, XEvent *event)
1847 struct state *st = (struct state *) closure;
1848 switch (event->type)
1851 switch (event->xbutton.button)
1854 st->stop = !st->stop ;
1855 if (st->state == 5) st->state = 4 ;
1881 maze_free (Display *dpy, Window window, void *closure)
1883 struct state *st = (struct state *) closure;
1887 XSCREENSAVER_MODULE ("Maze", maze)