git @ Cat's Eye Technologies The-Dipple / afd9b57
Add grotty, stackless C implementation of a maze generator. Cat's Eye Technologies 13 years ago
1 changed file(s) with 184 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 /*
1 * A classic maze-generator in C, by Chris Pressey, sometime late in 2011.
2 *
3 * The implementation does not use recursion, or indeed a stack; back-
4 * tracking information is stored right in the array in which we generate
5 * the maze. I encountered this idea in a BASIC maze-generator program
6 * which I dimly remember from the magazine "Enter" in the 80's, but I
7 * don't think I appreciated it until writing a recursive maze-generator
8 * in Pascal sometime in the early 90's. I did not try this in-place
9 * method until writing the program that now stands before you.
10 *
11 * The coding style is particularly inelegant (observe the heavy use of
12 * global variables!) because this source was meant to be an intermediate
13 * step towards implementing the algorithm in assembly.
14 */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <time.h>
19 #include <assert.h>
20
21 #define SIZE_X 40
22 #define SIZE_Y 21
23
24 /*
25 * top four bits is reverse
26 * bottom four bits is tried
27 */
28 unsigned char *maze;
29
30 #define UNSEEN 0x00
31 #define START 0x0f
32
33 #define NORTH 0x01
34 #define SOUTH 0x02
35 #define EAST 0x04
36 #define WEST 0x08
37 #define NONE 0x00
38 #define ALL 0x0f
39
40 unsigned char d, opp, x, y;
41 signed char dx, dy;
42 int pos;
43
44 void set_reverse(unsigned char reverse)
45 {
46 maze[pos] = (maze[pos] & 0x0f) | (reverse << 4);
47 }
48
49 unsigned char get_reverse(void)
50 {
51 return (maze[pos] & 0xf0) >> 4;
52 }
53
54 void mark_tried(unsigned char d)
55 {
56 maze[pos] |= d;
57 }
58
59 void set_tried(unsigned char d)
60 {
61 maze[pos] = (maze[pos] & 0xf0) | (d & 0x0f);
62 }
63
64 unsigned char get_tried(void)
65 {
66 return maze[pos] & 0x0f;
67 }
68
69 void calc_pos(void)
70 {
71 pos = y * SIZE_X + x;
72 }
73
74 void clear(void)
75 {
76 for (x = 0; x < SIZE_X; x++)
77 for (y = 0; y < SIZE_Y; y++) {
78 calc_pos();
79 maze[pos] = 0;
80 }
81 }
82
83 void draw(void)
84 {
85 for (y = 0; y < SIZE_Y; y++) {
86 for (x = 0; x < SIZE_X; x++) {
87 calc_pos();
88 if (x % 2 == 1 && y % 2 == 1)
89 assert(get_tried() == ALL);
90 if (get_tried() == ALL) {
91 printf(" ");
92 } else {
93 printf("#");
94 }
95 }
96 printf("#\n");
97 }
98 }
99
100 void get_delta(int d)
101 {
102 switch (d) {
103 case NORTH:
104 opp = SOUTH;
105 dx = 0;
106 dy = -1;
107 break;
108 case SOUTH:
109 opp = NORTH;
110 dx = 0;
111 dy = 1;
112 break;
113 case EAST:
114 opp = WEST;
115 dx = 1;
116 dy = 0;
117 break;
118 case WEST:
119 opp = EAST;
120 dx = -1;
121 dy = 0;
122 break;
123 }
124 }
125
126 int in_bounds(int nx, int ny)
127 {
128 return nx >= 0 && ny >= 0 && nx < SIZE_X && ny < SIZE_Y;
129 }
130
131 void make(void)
132 {
133
134 again:
135 calc_pos();
136
137 if (get_tried() == ALL) {
138 if (get_reverse() == START) {
139 assert(x == 1 && y == 1);
140 return;
141 }
142 get_delta(get_reverse());
143 x += (dx + dx);
144 y += (dy + dy);
145 goto again;
146 }
147
148 d = 1 << (random() & 0x03);
149 mark_tried(d);
150
151 get_delta(d);
152 if (!in_bounds(x + dx + dx, y + dy + dy))
153 goto again;
154 x += (dx + dx);
155 y += (dy + dy);
156 calc_pos();
157 if (get_tried() != NONE) {
158 x -= (dx + dx);
159 y -= (dy + dy);
160 goto again;
161 }
162 set_reverse(opp);
163 x -= dx;
164 y -= dy;
165 calc_pos();
166 set_tried(ALL);
167 x += dx;
168 y += dy;
169 goto again;
170 }
171
172 int main(int argc, char **argv)
173 {
174 srandom(time(NULL));
175 maze = malloc(SIZE_X * SIZE_Y * sizeof(unsigned char));
176 clear();
177 x = 1; y = 1;
178 calc_pos();
179 set_reverse(START);
180 make();
181 draw();
182 exit(0);
183 }