September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -4,36 +4,17 @@ grid_maze(data b, integer N)
|
|||
data d;
|
||||
integer i, j;
|
||||
|
||||
j = N;
|
||||
while (j) {
|
||||
b_suffix(d, "+---");
|
||||
j -= 1;
|
||||
}
|
||||
{
|
||||
b_suffix(d, "+\n");
|
||||
}
|
||||
call_n(N, b_suffix, d, "+---");
|
||||
b_suffix(d, "+\n");
|
||||
|
||||
j = N;
|
||||
while (j) {
|
||||
b_suffix(d, "| * ");
|
||||
j -= 1;
|
||||
}
|
||||
{
|
||||
b_suffix(d, "|\n");
|
||||
}
|
||||
call_n(N, b_suffix, d, "| * ");
|
||||
b_suffix(d, "|\n");
|
||||
|
||||
i = N;
|
||||
while (i) {
|
||||
b_extend(b, d);
|
||||
|
||||
i -= 1;
|
||||
}
|
||||
call_n(N, b_extend, b, d);
|
||||
|
||||
b_size(d, N * 4 + 2);
|
||||
|
||||
{
|
||||
b_extend(b, d);
|
||||
}
|
||||
b_extend(b, d);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -50,17 +31,18 @@ walk_cell(data b, integer N, integer line_size, integer x, integer y,
|
|||
while (i < 4) {
|
||||
integer p, q;
|
||||
|
||||
p = x + l_q_integer(x_offsets, (r + i) & 3);
|
||||
q = y + l_q_integer(y_offsets, (r + i) & 3);
|
||||
p = x + (p = x_offsets[(r + i) & 3]);
|
||||
q = y_offsets[(r + i) & 3];
|
||||
q += y;
|
||||
|
||||
if (-1 < p && p < line_size
|
||||
&& -1 < q && q < line_size * (N * 2 + 1)) {
|
||||
if (b_text(b, q + p) == '*') {
|
||||
if (b[q + p] == '*') {
|
||||
walk_cell(b, N, line_size, p, q, x_offsets, y_offsets);
|
||||
b_replace(b, (q + y) / 2 + (p + x) / 2, ' ');
|
||||
if (p == x) {
|
||||
b_replace(b, (q + y) / 2 + p - 1, ' ');
|
||||
b_replace(b, (q + y) / 2 + p + 1, ' ');
|
||||
b[(q + y) / 2 + (p + x) / 2] = ' ';
|
||||
if (p == x) {
|
||||
b[(q + y) / 2 + p - 1] = ' ';
|
||||
b[(q + y) / 2 + p + 1] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -77,14 +59,8 @@ walk_maze(data b, integer N)
|
|||
|
||||
line_size = N * 4 + 1 + 1;
|
||||
|
||||
lb_p_integer(x_offsets, 4);
|
||||
lb_p_integer(y_offsets, 0);
|
||||
lb_p_integer(x_offsets, 0);
|
||||
lb_p_integer(y_offsets, line_size * 2);
|
||||
lb_p_integer(x_offsets, -4);
|
||||
lb_p_integer(y_offsets, 0);
|
||||
lb_p_integer(x_offsets, 0);
|
||||
lb_p_integer(y_offsets, line_size * -2);
|
||||
l_bill(x_offsets, 0, 4, 0, -4, 0);
|
||||
l_bill(y_offsets, 0, 0, line_size * 2, 0, line_size * -2);
|
||||
|
||||
x = drand(N - 1) * 4 + 2;
|
||||
y = line_size * (drand(N - 1) * 2 + 1);
|
||||
|
|
@ -101,10 +77,9 @@ main(void)
|
|||
N = 10;
|
||||
|
||||
grid_maze(b, N);
|
||||
|
||||
walk_maze(b, N);
|
||||
|
||||
o_text(b_string(b));
|
||||
o_(b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,146 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
|
||||
#define DOUBLE_SPACE 1
|
||||
|
||||
#if DOUBLE_SPACE
|
||||
# define SPC " "
|
||||
#else
|
||||
# define SPC " "
|
||||
#endif
|
||||
|
||||
wchar_t glyph[] = L""SPC"│││─┘┐┤─└┌├─┴┬┼"SPC"┆┆┆┄╯╮ ┄╰╭ ┄";
|
||||
|
||||
typedef unsigned char byte;
|
||||
enum { N = 1, S = 2, W = 4, E = 8, V = 16 };
|
||||
|
||||
byte **cell;
|
||||
int w, h, avail;
|
||||
#define each(i, x, y) for (i = x; i <= y; i++)
|
||||
|
||||
int irand(int n)
|
||||
{
|
||||
int r, rmax = n * (RAND_MAX / n);
|
||||
while ((r = rand()) >= rmax);
|
||||
return r / (RAND_MAX/n);
|
||||
}
|
||||
|
||||
void show()
|
||||
{
|
||||
int i, j, c;
|
||||
each(i, 0, 2 * h) {
|
||||
each(j, 0, 2 * w) {
|
||||
c = cell[i][j];
|
||||
if (c > V) printf("\033[31m");
|
||||
printf("%lc", glyph[c]);
|
||||
if (c > V) printf("\033[m");
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
inline int max(int a, int b) { return a >= b ? a : b; }
|
||||
inline int min(int a, int b) { return b >= a ? a : b; }
|
||||
|
||||
static int dirs[4][2] = {{-2, 0}, {0, 2}, {2, 0}, {0, -2}};
|
||||
void walk(int x, int y)
|
||||
{
|
||||
int i, t, x1, y1, d[4] = { 0, 1, 2, 3 };
|
||||
|
||||
cell[y][x] |= V;
|
||||
avail--;
|
||||
|
||||
for (x1 = 3; x1; x1--)
|
||||
if (x1 != (y1 = irand(x1 + 1)))
|
||||
i = d[x1], d[x1] = d[y1], d[y1] = i;
|
||||
|
||||
for (i = 0; avail && i < 4; i++) {
|
||||
x1 = x + dirs[ d[i] ][0], y1 = y + dirs[ d[i] ][1];
|
||||
|
||||
if (cell[y1][x1] & V) continue;
|
||||
|
||||
/* break walls */
|
||||
if (x1 == x) {
|
||||
t = (y + y1) / 2;
|
||||
cell[t][x+1] &= ~W, cell[t][x] &= ~(E|W), cell[t][x-1] &= ~E;
|
||||
} else if (y1 == y) {
|
||||
t = (x + x1)/2;
|
||||
cell[y-1][t] &= ~S, cell[y][t] &= ~(N|S), cell[y+1][t] &= ~N;
|
||||
}
|
||||
walk(x1, y1);
|
||||
}
|
||||
}
|
||||
|
||||
int solve(int x, int y, int tox, int toy)
|
||||
{
|
||||
int i, t, x1, y1;
|
||||
|
||||
cell[y][x] |= V;
|
||||
if (x == tox && y == toy) return 1;
|
||||
|
||||
each(i, 0, 3) {
|
||||
x1 = x + dirs[i][0], y1 = y + dirs[i][1];
|
||||
if (cell[y1][x1]) continue;
|
||||
|
||||
/* mark path */
|
||||
if (x1 == x) {
|
||||
t = (y + y1)/2;
|
||||
if (cell[t][x] || !solve(x1, y1, tox, toy)) continue;
|
||||
|
||||
cell[t-1][x] |= S, cell[t][x] |= V|N|S, cell[t+1][x] |= N;
|
||||
} else if (y1 == y) {
|
||||
t = (x + x1)/2;
|
||||
if (cell[y][t] || !solve(x1, y1, tox, toy)) continue;
|
||||
|
||||
cell[y][t-1] |= E, cell[y][t] |= V|E|W, cell[y][t+1] |= W;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* backtrack */
|
||||
cell[y][x] &= ~V;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void make_maze()
|
||||
{
|
||||
int i, j;
|
||||
int h2 = 2 * h + 2, w2 = 2 * w + 2;
|
||||
byte **p;
|
||||
|
||||
p = calloc(sizeof(byte*) * (h2 + 2) + w2 * h2 + 1, 1);
|
||||
|
||||
p[1] = (byte*)(p + h2 + 2) + 1;
|
||||
each(i, 2, h2) p[i] = p[i-1] + w2;
|
||||
p[0] = p[h2];
|
||||
cell = &p[1];
|
||||
|
||||
each(i, -1, 2 * h + 1) cell[i][-1] = cell[i][w2 - 1] = V;
|
||||
each(j, 0, 2 * w) cell[-1][j] = cell[h2 - 1][j] = V;
|
||||
each(i, 0, h) each(j, 0, 2 * w) cell[2*i][j] |= E|W;
|
||||
each(i, 0, 2 * h) each(j, 0, w) cell[i][2*j] |= N|S;
|
||||
each(j, 0, 2 * w) cell[0][j] &= ~N, cell[2*h][j] &= ~S;
|
||||
each(i, 0, 2 * h) cell[i][0] &= ~W, cell[i][2*w] &= ~E;
|
||||
|
||||
avail = w * h;
|
||||
walk(irand(2) * 2 + 1, irand(h) * 2 + 1);
|
||||
|
||||
/* reset visited marker (it's also used by path finder) */
|
||||
each(i, 0, 2 * h) each(j, 0, 2 * w) cell[i][j] &= ~V;
|
||||
solve(1, 1, 2 * w - 1, 2 * h - 1);
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
int main(int c, char **v)
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
if (c < 2 || (w = atoi(v[1])) <= 0) w = 16;
|
||||
if (c < 3 || (h = atoi(v[2])) <= 0) h = 8;
|
||||
|
||||
make_maze();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CW 10 /* cell width. This decides how big the output is */
|
||||
|
||||
typedef struct cell_t cell_t, *cell;
|
||||
|
||||
enum { N, E, S, W, V };
|
||||
struct cell_t {
|
||||
unsigned int flags;
|
||||
cell prev, next, nei[4]; /* neighbors */
|
||||
};
|
||||
|
||||
int sx, sy, sz, w, h;
|
||||
|
||||
#define C(y, x) c[(y) * w + x]
|
||||
#define P(y, x) pix[(y) * w2 + x]
|
||||
void draw_maze(cell *c)
|
||||
{
|
||||
#define FOR(a, b) for(a = 0; a < b; a++)
|
||||
FILE *fp;
|
||||
int w2 = w * CW + 8, h2 = h * CW + 7;
|
||||
char *pix = malloc(w2 * h2);
|
||||
memset(pix, 200, w2 * h2);
|
||||
|
||||
void draw_face(int x, int y, int ww, int hh, int px, int py) {
|
||||
int i, j, k, l;
|
||||
cell t;
|
||||
|
||||
px += 2, py += 2;
|
||||
for (i = py; i <= py + hh * CW; i++)
|
||||
memset(&P(i, px), 0, ww * CW+1);
|
||||
|
||||
px++, py++;
|
||||
# define mark(y, x) P(py + CW*i + y, px + CW*j + x) = 255
|
||||
FOR (i, hh) FOR (j, ww) {
|
||||
FOR(k, CW - 1) FOR(l, CW - 1) mark(k, l);
|
||||
|
||||
t = C(y + i, x + j);
|
||||
if (t->flags & (1 << N))
|
||||
FOR (l, CW - 1) mark(-1, l);
|
||||
if (t->flags & (1 << S))
|
||||
FOR (l, CW - 1) mark(CW - 1, l);
|
||||
if (t->flags & (1 << E))
|
||||
FOR (l, CW - 1) mark(l, CW - 1);
|
||||
if (t->flags & (1 << W))
|
||||
FOR (l, CW - 1) mark(l, -1);
|
||||
}
|
||||
}
|
||||
|
||||
draw_face(0, 0, sx, sy, 0, 0);
|
||||
draw_face(0, sy, sx, sz, 0, CW*sy + 1);
|
||||
draw_face(sx, sy, sy, sz, CW*sx + 1, CW*sy + 1);
|
||||
draw_face(sx + sy, sy, sx, sz, CW*(sx + sy) + 2, CW*sy + 1);
|
||||
draw_face(sx + sy + sx, sy, sy, sz, CW*(sx + sy + sx) + 3, CW*sy + 1);
|
||||
draw_face(sx + sy, sy + sz, sx, sy, CW*(sx + sy) + 2, CW*(sy + sz) + 2);
|
||||
|
||||
fp = fopen("maze.pgm", "w+");
|
||||
fprintf(fp, "P5\n%d %d\n255\n", w2, h2);
|
||||
fwrite(pix, 1, w2 * h2, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
cell rand_neighbor(cell x)
|
||||
{
|
||||
cell r = 0;
|
||||
int i, c = 1;
|
||||
for (i = N; i <= W; i++) {
|
||||
if (!x->nei[i] || (x->nei[i]->flags & (1 << V)))
|
||||
continue;
|
||||
if (rand() % c++ == 0)
|
||||
r = x->nei[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void link_cells(cell a, cell b)
|
||||
{
|
||||
int i;
|
||||
for (i = N; i <= W; i++) {
|
||||
if (a->nei[i] != b) continue;
|
||||
a->flags |= 1 << i;
|
||||
break;
|
||||
}
|
||||
for (i = N; i <= W; i++) {
|
||||
if (b->nei[i] != a) continue;
|
||||
b->flags |= 1 << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void walk(cell head)
|
||||
{
|
||||
cell tail = head, p, n;
|
||||
|
||||
while (head) {
|
||||
for (p = head; p; p = n) {
|
||||
p->flags |= 1 << V;
|
||||
n = rand_neighbor(p);
|
||||
if (!n) break;
|
||||
tail->next = n;
|
||||
n->prev = tail;
|
||||
|
||||
tail = n;
|
||||
link_cells(p, n);
|
||||
}
|
||||
while (head && !rand_neighbor(head)) head = head->next;
|
||||
}
|
||||
}
|
||||
|
||||
void make_maze(void)
|
||||
{
|
||||
int i, j;
|
||||
int n = (sx * sy + sx * sz + sy * sz) * 2;
|
||||
cell t, *c;
|
||||
cell_t * cells;
|
||||
|
||||
w = 2 * sx + 2 * sy, h = sy * 2 + sz;
|
||||
cells = calloc(sizeof(cell_t), n);
|
||||
c = calloc(sizeof(cell), w * h);
|
||||
|
||||
for (i = 0; i < sy; i++)
|
||||
for (j = 0; j < sx; j++)
|
||||
C(i, j) = cells + --n;
|
||||
for (; i < sy + sz; i++)
|
||||
for (j = 0; j < w; j++)
|
||||
C(i, j) = cells + --n;
|
||||
for (; i < h; i++)
|
||||
for (j = sx + sy; j < w - sy; j++)
|
||||
C(i, j) = cells + --n;
|
||||
|
||||
for (i = 0; i < h; i++) {
|
||||
for (j = 0; j < w; j++) {
|
||||
t = C(i, j);
|
||||
if (!t) continue;
|
||||
if (i) t->nei[N] = C(i - 1, j);
|
||||
if (i < h - 1) t->nei[S] = C(i + 1, j);
|
||||
if (j) t->nei[W] = C(i, j - 1);
|
||||
if (j < w - 1) t->nei[E] = C(i, j + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < sx; j++) {
|
||||
C(0, j)->nei[N] = C(sy, w - sy - j - 1);
|
||||
C(sy, w - sy - j - 1)->nei[N] = C(0, j);
|
||||
|
||||
C(h - sy - 1, j)->nei[S] = C(h - 1, w - sy - j - 1);
|
||||
C(h - 1, w - sy - j - 1)->nei[S] = C(h - sy - 1, j);
|
||||
}
|
||||
|
||||
for (i = sy; i < sy + sz; i++) {
|
||||
C(i, 0)->nei[W] = C(i, w - 1);
|
||||
C(i, w - 1)->nei[E] = C(i, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < sy; i++) {
|
||||
C(i, 0)->nei[W] = C(sy, w - sy + i);
|
||||
C(sy, w - sy + i)->nei[N] = C(i, 0);
|
||||
|
||||
C(i, sx - 1)->nei[E] = C(sy, sx + sy - i - 1);
|
||||
C(sy, sx + sy - i - 1)->nei[N] = C(i, sx - 1);
|
||||
|
||||
C(h - sy - 1, sx + i)->nei[S] = C(h - 1 - i, sx + sy);
|
||||
C(h - 1 - i, sx + sy)->nei[W] = C(h - sy - 1, sx + i);
|
||||
|
||||
C(sy + sz + i, w - sy - 1)->nei[E] = C(sy + sz - 1, w - sy + i);
|
||||
C(sy + sz - 1, w - sy + i)->nei[S] = C(sy + sz + i, w - sy - 1);
|
||||
}
|
||||
|
||||
walk(C(0, 0));
|
||||
draw_maze(c);
|
||||
}
|
||||
|
||||
int main(int c, char **v)
|
||||
{
|
||||
if (c < 2 || (sx = atoi(v[1])) <= 0) sx = 10;
|
||||
if (c < 3 || (sy = atoi(v[2])) <= 0) sy = sx;
|
||||
if (c < 4 || (sz = atoi(v[3])) <= 0) sz = sy;
|
||||
|
||||
make_maze();
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
Task/Maze-generation/Clojure/maze-generation.clj
Normal file
94
Task/Maze-generation/Clojure/maze-generation.clj
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
(ns maze.core
|
||||
(:require [clojure.set :refer [intersection
|
||||
select]]
|
||||
[clojure.string :as str]))
|
||||
|
||||
;; Misc functions
|
||||
(defn neighborhood
|
||||
([] (neighborhood [0 0]))
|
||||
([coord] (neighborhood coord 1))
|
||||
([[y x] r]
|
||||
(let [y-- (- y r) y++ (+ y r)
|
||||
x-- (- x r) x++ (+ x r)]
|
||||
#{[y++ x] [y-- x] [y x--] [y x++]})))
|
||||
|
||||
(defn cell-empty? [maze coords]
|
||||
(= :empty (get-in maze coords)))
|
||||
|
||||
(defn wall? [maze coords]
|
||||
(= :wall (get-in maze coords)))
|
||||
|
||||
(defn filter-maze
|
||||
([pred maze coords]
|
||||
(select (partial pred maze) (set coords)))
|
||||
([pred maze]
|
||||
(filter-maze
|
||||
pred
|
||||
maze
|
||||
(for [y (range (count maze))
|
||||
x (range (count (nth maze y)))]
|
||||
[y x]))))
|
||||
|
||||
(defn create-empty-maze [width height]
|
||||
(let [width (inc (* 2 width))
|
||||
height (inc (* 2 height))]
|
||||
(vec (take height
|
||||
(interleave
|
||||
(repeat (vec (take width (repeat :wall))))
|
||||
(repeat (vec (take width (cycle [:wall :empty])))))))))
|
||||
|
||||
(defn next-step [possible-steps]
|
||||
(rand-nth (vec possible-steps)))
|
||||
|
||||
;;Algo
|
||||
(defn create-random-maze [width height]
|
||||
(loop [maze (create-empty-maze width height)
|
||||
stack []
|
||||
nonvisited (filter-maze cell-empty? maze)
|
||||
visited #{}
|
||||
coords (next-step nonvisited)]
|
||||
(if (empty? nonvisited)
|
||||
maze
|
||||
(let [nonvisited-neighbors (intersection (neighborhood coords 2) nonvisited)]
|
||||
(cond
|
||||
(seq nonvisited-neighbors)
|
||||
(let [next-coords (next-step nonvisited-neighbors)
|
||||
wall-coords (map #(+ %1 (/ (- %2 %1) 2)) coords next-coords)]
|
||||
(recur (assoc-in maze wall-coords :empty)
|
||||
(conj stack coords)
|
||||
(disj nonvisited next-coords)
|
||||
(conj visited next-coords)
|
||||
next-coords))
|
||||
|
||||
(seq stack)
|
||||
(recur maze (pop stack) nonvisited visited (last stack)))))))
|
||||
|
||||
;;Conversion to string
|
||||
(def cell-code->str
|
||||
[" " " " " " " " "· " "╵ " "╴ " "┘ "
|
||||
" " " " " " " " "╶─" "└─" "──" "┴─"
|
||||
" " " " " " " " "╷ " "│ " "┐ " "┤ "
|
||||
" " " " " " " " "┌─" "├─" "┬─" "┼─"])
|
||||
|
||||
(defn cell-code [maze coord]
|
||||
(transduce
|
||||
(comp
|
||||
(map (partial wall? maze))
|
||||
(keep-indexed (fn [idx el] (when el idx)))
|
||||
(map (partial bit-shift-left 1)))
|
||||
(completing bit-or)
|
||||
0
|
||||
(sort (cons coord (neighborhood coord)))))
|
||||
|
||||
(defn cell->str [maze coord]
|
||||
(get cell-code->str (cell-code maze coord)))
|
||||
|
||||
(defn maze->str [maze]
|
||||
(->> (for [y (range (count maze))]
|
||||
(for [x (range (count (nth maze y)))]
|
||||
(cell->str maze [y x])))
|
||||
(map str/join)
|
||||
(str/join \newline)))
|
||||
|
||||
;;Task
|
||||
(println (maze->str (create-random-maze 10 10)))
|
||||
|
|
@ -2,7 +2,7 @@ function walk(maze, cell, visited = Any[])
|
|||
push!(visited, cell)
|
||||
for neigh in shuffle(neighbors(cell, size(maze)))
|
||||
if !(neigh in visited)
|
||||
maze[round(Int,(cell+neigh)/2)...] = 0 # ifloor(n/2) == n >> 1
|
||||
maze[round.(Int,(cell+neigh)/2)...] = 0
|
||||
walk(maze, neigh, visited)
|
||||
end
|
||||
end
|
||||
|
|
@ -17,7 +17,7 @@ maze(w, h) = walk([i%2|j%2 for i=1:2w+1,j=1:2h+1], 2*[rand(1:w),rand(1:h)])
|
|||
|
||||
pprint(matrix) = for i = 1:size(matrix,1) println(join(matrix[i,:])) end
|
||||
|
||||
function printmaze(maze, wall = convert(UTF32String, "╹╸┛╺┗━┻╻┃┓┫┏┣┳╋"))
|
||||
function printmaze(maze, wall = split("╹ ╸ ┛ ╺ ┗ ━ ┻ ╻ ┃ ┓ ┫ ┏ ┣ ┳ ╋"))
|
||||
h,w = size(maze)
|
||||
pprint([ maze[i,j] == 0 ? ' ' :
|
||||
wall[Int(sum(c-> 2.0^.5(3c[1]+c[2]+3),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import shuffle.shuffle
|
||||
import java.util.*
|
||||
|
||||
class MazeGenerator(val x: Int, val y: Int) {
|
||||
private val maze = Array(x) { IntArray(y) }
|
||||
|
||||
class Maze_generator(val x: Int, val y: Int) {
|
||||
fun generate(cx: Int, cy: Int) {
|
||||
arrayOf(*DIR.values()).shuffle().forEach {
|
||||
Direction.values().shuffle().forEach {
|
||||
val nx = cx + it.dx
|
||||
val ny = cy + it.dy
|
||||
if (between(nx, x) && between(ny, y) && maze[nx][ny] == 0) {
|
||||
|
|
@ -31,10 +33,16 @@ class Maze_generator(val x: Int, val y: Int) {
|
|||
println('+')
|
||||
}
|
||||
|
||||
private enum class DIR(val bit: Int, val dx: Int, val dy: Int) {
|
||||
inline private fun <reified T> Array<T>.shuffle(): Array<T> {
|
||||
val list = toMutableList()
|
||||
Collections.shuffle(list)
|
||||
return list.toTypedArray()
|
||||
}
|
||||
|
||||
private enum class Direction(val bit: Int, val dx: Int, val dy: Int) {
|
||||
N(1, 0, -1), S(2, 0, 1), E(4, 1, 0),W(8, -1, 0);
|
||||
|
||||
var opposite: DIR? = null
|
||||
var opposite: Direction? = null
|
||||
|
||||
companion object {
|
||||
init {
|
||||
|
|
@ -47,14 +55,12 @@ class Maze_generator(val x: Int, val y: Int) {
|
|||
}
|
||||
|
||||
private fun between(v: Int, upper: Int) = v >= 0 && v < upper
|
||||
|
||||
private val maze = Array(x) { IntArray(y) }
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val x = if (args.size >= 1) args[0].toInt() else 8
|
||||
val y = if (args.size == 2) args[1].toInt() else 8
|
||||
with(Maze_generator(x, y)) {
|
||||
with(MazeGenerator(x, y)) {
|
||||
generate(0, 0)
|
||||
display()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
Stack = {}
|
||||
|
||||
function Stack:Create()
|
||||
local stack = {}
|
||||
|
||||
function stack:push(item)
|
||||
self[#self + 1] = item
|
||||
end
|
||||
|
||||
function stack:pop()
|
||||
local item = self[#self]
|
||||
self[#self] = nil
|
||||
return item
|
||||
end
|
||||
|
||||
return stack
|
||||
end
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
require "stack"
|
||||
|
||||
Maze =
|
||||
{
|
||||
directions =
|
||||
{
|
||||
north = { x = 0, y = -1 },
|
||||
east = { x = 1, y = 0 },
|
||||
south = { x = 0, y = 1 },
|
||||
west = { x = -1, y = 0 }
|
||||
}
|
||||
}
|
||||
|
||||
function Maze:Create(width, height, closed)
|
||||
-- Actual maze setup
|
||||
local maze = {}
|
||||
for y = 1, height do
|
||||
maze[y] = {}
|
||||
for x = 1, width do
|
||||
maze[y][x] = { east = self:CreateDoor(closed), south = self:CreateDoor(closed)}
|
||||
|
||||
-- Doors are shared beetween the cells to avoid out of sync conditions and data dublication
|
||||
if x ~= 1 then maze[y][x].west = maze[y][x - 1].east
|
||||
else maze[y][x].west = self:CreateDoor(closed) end
|
||||
|
||||
if y ~= 1 then maze[y][x].north = maze[y - 1][x].south
|
||||
else maze[y][x].north = self:CreateDoor(closed) end
|
||||
end
|
||||
end
|
||||
|
||||
function maze:resetDoors(close)
|
||||
for y = 1, #self do
|
||||
self[y][#self[1]].east:setOpened(not close)
|
||||
|
||||
for i, cell in ipairs(self[y]) do
|
||||
cell.north:setOpened(not close)
|
||||
cell.west:setOpened(not close)
|
||||
end
|
||||
end
|
||||
|
||||
for i, cell in ipairs(self[#self]) do
|
||||
cell.south:setOpened(not close)
|
||||
end
|
||||
end
|
||||
|
||||
function maze:resetVisited()
|
||||
for y = 1, #self do
|
||||
for x = 1, #self[1] do
|
||||
self[y][x].visited = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function maze:tostring(wall, passage)
|
||||
wall = wall or "#"
|
||||
passage = passage or " "
|
||||
|
||||
local result = ""
|
||||
|
||||
local verticalBorder = ""
|
||||
for i = 1, #self[1] do
|
||||
verticalBorder = verticalBorder .. wall .. (self[1][i].north:isClosed() and wall or passage)
|
||||
end
|
||||
verticalBorder = verticalBorder .. wall
|
||||
result = result .. verticalBorder .. "\n"
|
||||
|
||||
for y, row in ipairs(self) do
|
||||
local line = row[1].west:isClosed() and wall or passage
|
||||
local underline = wall
|
||||
for x, cell in ipairs(row) do
|
||||
line = line .. " " .. (cell.east:isClosed() and wall or passage)
|
||||
underline = underline .. (cell.south:isClosed() and wall or passage) .. wall
|
||||
end
|
||||
result = result .. line .. "\n" .. underline .. "\n"
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
return maze
|
||||
end
|
||||
|
||||
|
||||
-- This function was designed to be easily replaced by the function generating Legend of Grimrock doors
|
||||
function Maze:CreateDoor(closed)
|
||||
local door = {}
|
||||
door._closed = closed and true or false
|
||||
|
||||
function door:isClosed()
|
||||
return self._closed
|
||||
end
|
||||
|
||||
function door:isOpened()
|
||||
return not self._closed
|
||||
end
|
||||
|
||||
function door:close()
|
||||
self._closed = true
|
||||
end
|
||||
|
||||
function door:open()
|
||||
self._closed = false
|
||||
end
|
||||
|
||||
function door:setOpened(opened)
|
||||
if opened then
|
||||
self:open()
|
||||
else
|
||||
self:close()
|
||||
end
|
||||
end
|
||||
|
||||
return door
|
||||
end
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
require "maze"
|
||||
|
||||
-- Backtracker algorithm (a variation of the recursive backtracker algorithm made without recursion)
|
||||
function Maze:Backtracker(maze)
|
||||
maze:resetDoors(true)
|
||||
|
||||
local stack = Stack:Create()
|
||||
|
||||
local cell = { x = 1, y = 1 }
|
||||
while true do
|
||||
maze[cell.y][cell.x].visited = true
|
||||
|
||||
-- Gathering all possible travel direction in a list
|
||||
local directions = {}
|
||||
for key, value in pairs(self.directions) do
|
||||
local newPos = { x = cell.x + value.x, y = cell.y + value.y }
|
||||
-- Checking if the targeted cell is in bounds and was not visited previously
|
||||
if maze[newPos.y] and maze[newPos.y][newPos.x] and not maze[newPos.y][newPos.x].visited then
|
||||
directions[#directions + 1] = { name = key, pos = newPos }
|
||||
end
|
||||
end
|
||||
|
||||
-- If there are no possible travel directions - backtracking
|
||||
if #directions == 0 then
|
||||
if #stack > 0 then
|
||||
cell = stack:pop()
|
||||
goto countinue
|
||||
else break end -- Stack is empty and there are no possible directions - maze is generated
|
||||
end
|
||||
|
||||
-- Choosing a random direction from a list of possible direction and carving
|
||||
stack:push(cell)
|
||||
local dir = directions[math.random(#directions)]
|
||||
maze[cell.y][cell.x][dir.name]:open()
|
||||
cell = dir.pos
|
||||
|
||||
::countinue::
|
||||
end
|
||||
|
||||
maze:resetVisited()
|
||||
end
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
require "maze"
|
||||
require "backtracker"
|
||||
|
||||
maze = Maze:Create(30, 10, true)
|
||||
--[[ Maze generation depends on the random seed, so you will get exactly
|
||||
identical maze every time you pass exactly identical seed ]]
|
||||
math.randomseed(os.time())
|
||||
Maze:Backtracker(maze)
|
||||
print(maze:tostring())
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Convert Hex Color to RGB
|
||||
|
||||
function hexrgb(&$h)
|
||||
{
|
||||
return(array(hexdec($h[0].$h[1]),hexdec($h[2].$h[3]),hexdec($h[4].$h[5])));
|
||||
}
|
||||
|
||||
// Allocate a color for an image from RGB
|
||||
|
||||
function rgbc(&$i, &$c)
|
||||
{
|
||||
return(imagecolorallocate($i, $c[0], $c[1], $c[2]));
|
||||
}
|
||||
|
||||
class Maze
|
||||
{
|
||||
|
||||
/*
|
||||
H : horizontal walls
|
||||
V : vertical walls
|
||||
x : number of rows
|
||||
y : numbers of cols
|
||||
r : resolve the maze
|
||||
b : walls thickness
|
||||
c : cell size
|
||||
f : background color
|
||||
m : walls color
|
||||
e : entrance color
|
||||
s : exit color
|
||||
i : gd image identifier
|
||||
*/
|
||||
|
||||
private $H, $V, $x, $y, $r, $b, $c, $f, $m, $e, $s, $i;
|
||||
|
||||
// Initialize Maze class
|
||||
|
||||
function __construct($x, $y, $r, $b, $c, $f, $m, $e, $s)
|
||||
{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
$this->r = $r;
|
||||
$this->b = $b;
|
||||
$this->c = $c;
|
||||
$this->f = hexrgb($f);
|
||||
$this->m = hexrgb($m);
|
||||
$this->e = hexrgb($e);
|
||||
$this->s = hexrgb($s);
|
||||
}
|
||||
|
||||
// Checks if cell is a closed room
|
||||
|
||||
function isroom($x, $y)
|
||||
{
|
||||
return((empty($this->H[$x][$y])
|
||||
&& empty($this->V[$x][$y])
|
||||
&& empty($this->H[$x][$y+1])
|
||||
&& empty($this->V[$x+1][$y])) ? true : false);
|
||||
}
|
||||
|
||||
// Save the stack as solution path
|
||||
|
||||
function save(&$x, &$y, &$m)
|
||||
{
|
||||
if ($this->r == 1 && $x == $this->x - 1 && $y == $this->y - 1)
|
||||
{
|
||||
$this->r = $m;
|
||||
array_push($this->r, array($x, $y));
|
||||
}
|
||||
}
|
||||
|
||||
// Dig the maze
|
||||
|
||||
function dig()
|
||||
{
|
||||
$x = 0;
|
||||
$y = 0;
|
||||
$cc = $this->x * $this->y;
|
||||
$v = 1;
|
||||
$m = array();
|
||||
while ($v < $cc)
|
||||
{
|
||||
$c = '';
|
||||
if ($y > 0 && $this->isroom($x, $y - 1))
|
||||
$c .= 'N';
|
||||
if ($y < $this->y - 1 && $this->isroom($x, $y + 1))
|
||||
$c .= 'S';
|
||||
if ($x < $this->x - 1 && $this->isroom($x + 1, $y))
|
||||
$c .= 'E';
|
||||
if ($x > 0 && $this->isroom($x - 1, $y))
|
||||
$c .= 'W';
|
||||
if ($c)
|
||||
{
|
||||
$v++;
|
||||
array_push($m, array($x, $y));
|
||||
$d = $c[rand(0, strlen($c) - 1)];
|
||||
if ($d == 'N')
|
||||
$this->H[$x][$y--] = true;
|
||||
if ($d == 'S')
|
||||
$this->H[$x][$y++ + 1] = true;
|
||||
if ($d == 'E')
|
||||
$this->V[$x++ + 1][$y] = true;
|
||||
if ($d == 'W')
|
||||
$this->V[$x--][$y] = true;
|
||||
}
|
||||
else
|
||||
list($x, $y) = array_pop($m);
|
||||
$this->save($x, $y, $m);
|
||||
}
|
||||
$this->save($x, $y, $m);
|
||||
$this->V[0][0] = 1;
|
||||
$this->V[$this->x][$this->y - 1] = 1;
|
||||
}
|
||||
|
||||
// Draw the maze full grid
|
||||
|
||||
function grid(&$m)
|
||||
{
|
||||
for ($y = 0; $y <= $this->y; ++$y)
|
||||
{
|
||||
imagefilledrectangle($this->i, 0, $y * ($this->c + $this->b),
|
||||
$this->b + $this->x * ($this->c + $this->b) - 1,
|
||||
$this->b + $y * ($this->c + $this->b) - 1,
|
||||
$m);
|
||||
}
|
||||
for ($x = 0; $x <= $this->x; ++$x)
|
||||
{
|
||||
imagefilledrectangle($this->i, $x * ($this->c + $this->b), 0,
|
||||
$this->b + $x * ($this->c + $this->b) - 1,
|
||||
$this->b + $this->y * ($this->c + $this->b) - 1,
|
||||
$m);
|
||||
}
|
||||
}
|
||||
|
||||
// Breaks the horizontal walls
|
||||
|
||||
function line($x, $y, &$f)
|
||||
{
|
||||
imagefilledrectangle($this->i,
|
||||
$x * ($this->c + $this->b) + $this->b,
|
||||
$y * ($this->c + $this->b),
|
||||
$x * ($this->c + $this->b) + $this->b + $this->c - 1,
|
||||
$y * ($this->c + $this->b) + $this->b,
|
||||
$f);
|
||||
}
|
||||
|
||||
// Breaks the vertical walls
|
||||
|
||||
function col($x, $y, &$f)
|
||||
{
|
||||
imagefilledrectangle($this->i,
|
||||
$x * ($this->c + $this->b),
|
||||
$y * ($this->c + $this->b) + $this->b,
|
||||
$x * ($this->c + $this->b) + $this->b,
|
||||
$y * ($this->c + $this->b) + $this->b + $this->c - 1,
|
||||
$f);
|
||||
}
|
||||
|
||||
// Breaks the walls
|
||||
|
||||
function dot(&$f)
|
||||
{
|
||||
for ($x = 0; $x <= $this->x; ++$x)
|
||||
{
|
||||
for ($y = 0; $y <= $this->y; ++$y)
|
||||
{
|
||||
if (isset($this->H[$x][$y]))
|
||||
$this->line($x, $y, $f);
|
||||
if (isset($this->V[$x][$y]))
|
||||
$this->col($x, $y, $f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill color cell
|
||||
|
||||
function cellfill(&$x, &$y, &$c)
|
||||
{
|
||||
imagefilledrectangle($this->i,
|
||||
$x * ($this->c + $this->b) + $this->b,
|
||||
$y * ($this->c + $this->b) + $this->b,
|
||||
$x * ($this->c + $this->b) + $this->b + $this->c - 1,
|
||||
$y * ($this->c + $this->b) + $this->b + $this->c - 1,
|
||||
$c);
|
||||
}
|
||||
|
||||
// Draw solution
|
||||
|
||||
function path()
|
||||
{
|
||||
$l = count($this->r);
|
||||
for ($i = 0; $i < $l; ++$i)
|
||||
{
|
||||
list($x, $y) = $this->r[$i];
|
||||
$r = ($this->e[0] * ($l - $i) + $this->s[0] * $i) / $l;
|
||||
$g = ($this->e[1] * ($l - $i) + $this->s[1] * $i) / $l;
|
||||
$b = ($this->e[2] * ($l - $i) + $this->s[2] * $i) / $l;
|
||||
if (!isset($c[$r][$g][$b]))
|
||||
$c[$r][$g][$b] = imagecolorallocate($this->i, $r, $g, $b);
|
||||
$this->cellfill($x, $y, $c[$r][$g][$b]);
|
||||
if (isset($ox, $oy))
|
||||
{
|
||||
if ($ox - $x == -1)
|
||||
$this->col($x, $y, $c[$r][$g][$b]);
|
||||
if ($oy - $y == -1)
|
||||
$this->line($x, $y, $c[$r][$g][$b]);
|
||||
if ($ox - $x == 1)
|
||||
$this->col($ox, $oy, $c[$r][$g][$b]);
|
||||
if ($oy - $y == 1)
|
||||
$this->line($ox, $oy, $c[$r][$g][$b]);
|
||||
}
|
||||
if ($i == 0)
|
||||
$this->col(0, 0, $c[$r][$g][$b]);
|
||||
if ($i == $l - 1)
|
||||
$this->col($x + 1, $y, $c[$r][$g][$b]);
|
||||
$ox = $x;
|
||||
$oy = $y;
|
||||
}
|
||||
}
|
||||
|
||||
// Call digger and make rendering
|
||||
|
||||
function __destruct()
|
||||
{
|
||||
$this->dig();
|
||||
$this->i = imagecreatetruecolor(
|
||||
$this->b + $this->x * ($this->c + $this->b),
|
||||
$this->b + $this->y * ($this->c + $this->b));
|
||||
$f = rgbc($this->i, $this->f);
|
||||
$m = rgbc($this->i, $this->m);
|
||||
unset($this->f, $this->m);
|
||||
imagefill($this->i, 0, 0, $f);
|
||||
$this->grid($m);
|
||||
$this->dot($f);
|
||||
unset($f, $m, $this->H, $this->V);
|
||||
if ($this->r)
|
||||
$this->path();
|
||||
unset($this->r, $this->e, $this->s);
|
||||
header('content-disposition:inline;filename="maze.png"');
|
||||
header('cache-control:no-store,no-cache,must-revalidate');
|
||||
header('content-type:image/png');
|
||||
imagepng($this->i, NULL, 9, PNG_ALL_FILTERS);
|
||||
imagedestroy($this->i);
|
||||
}
|
||||
}
|
||||
46
Task/Maze-generation/Phix/maze-generation.phix
Normal file
46
Task/Maze-generation/Phix/maze-generation.phix
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
--
|
||||
-- grid is eg for w=3,h=2: {"+---+---+---+", -- ("wall")
|
||||
-- "| ? | ? | ? |", -- ("cell")
|
||||
-- "+---+---+---+", -- ("wall")
|
||||
-- "| ? | ? | ? |", -- ("cell")
|
||||
-- "+---+---+---+", -- ("wall")
|
||||
-- ""} -- (for a trailing \n)
|
||||
--
|
||||
-- note those ?(x,y) are at [y*2][x*4-1], and we navigate
|
||||
-- using y=2..2*h (+/-2), x=3..w*4-1 (+/-4) directly.
|
||||
--
|
||||
constant w = 11, h = 8
|
||||
|
||||
sequence wall = join(repeat("+",w+1),"---")&"\n",
|
||||
cell = join(repeat("|",w+1)," ? ")&"\n",
|
||||
grid = split(join(repeat(wall,h+1),cell),'\n')
|
||||
|
||||
procedure amaze(integer x, integer y)
|
||||
grid[y][x] = ' ' -- mark cell visited
|
||||
sequence p = shuffle({{x-4,y},{x,y+2},{x+4,y},{x,y-2}})
|
||||
for i=1 to length(p) do
|
||||
integer {nx,ny} = p[i]
|
||||
if nx>1 and nx<w*4 and ny>1 and ny<=2*h and grid[ny][nx]='?' then
|
||||
integer mx = (x+nx)/2
|
||||
grid[(y+ny)/2][mx-1..mx+1] = ' ' -- knock down wall
|
||||
amaze(nx,ny)
|
||||
end if
|
||||
end for
|
||||
end procedure
|
||||
|
||||
function heads()
|
||||
return rand(2)=1 -- 50:50 true(1)/false(0)
|
||||
end function
|
||||
|
||||
integer {x,y} = {(rand(w)*4)-1,rand(h)*2}
|
||||
amaze(x,y)
|
||||
-- mark start pos
|
||||
grid[y][x] = '*'
|
||||
-- add a random door (heads=rhs/lhs, tails=top/btm)
|
||||
if heads() then
|
||||
grid[rand(h)*2][heads()*w*4-1] = ' '
|
||||
else
|
||||
x = rand(w)*4-1
|
||||
grid[heads()*h*2+1][x-1..x+1] = ' '
|
||||
end if
|
||||
puts(1,join(grid,'\n'))
|
||||
|
|
@ -1,109 +1,173 @@
|
|||
import Foundation
|
||||
|
||||
class Direction {
|
||||
var vect:(Int, Int, Int)
|
||||
var bit:Int {
|
||||
let (bit, dx, dy) = vect
|
||||
return bit
|
||||
extension Array {
|
||||
mutating func swap(_ index1:Int, _ index2:Int) {
|
||||
let temp = self[index1]
|
||||
self[index1] = self[index2]
|
||||
self[index2] = temp
|
||||
}
|
||||
|
||||
var dx:Int {
|
||||
let (bit, dx, dy) = vect
|
||||
return dx
|
||||
}
|
||||
|
||||
var dy:Int {
|
||||
let (bit, dx, dy) = vect
|
||||
return dy
|
||||
}
|
||||
|
||||
var opposite:Direction {
|
||||
switch (vect) {
|
||||
case (1, 0, -1):
|
||||
return Direction(bit: 2, dx: 0, dy: 1)
|
||||
case (2, 0, 1):
|
||||
return Direction(bit: 1, dx: 0, dy: -1)
|
||||
case (4, 1, 0):
|
||||
return Direction(bit: 8, dx: -1, dy: 0)
|
||||
case (8, -1, 0):
|
||||
return Direction(bit: 4, dx: 1, dy: 0)
|
||||
default:
|
||||
return Direction(bit: 0, dx: 0, dy: 0)
|
||||
mutating func shuffle() {
|
||||
for _ in 0..<self.count {
|
||||
let index1 = Int(arc4random()) % self.count
|
||||
let index2 = Int(arc4random()) % self.count
|
||||
self.swap(index1, index2)
|
||||
}
|
||||
}
|
||||
|
||||
init(bit:Int, dx:Int, dy:Int) {
|
||||
self.vect = (bit, dx, dy)
|
||||
}
|
||||
}
|
||||
|
||||
let N = Direction(bit: 1, dx: 0, dy: -1)
|
||||
let S = Direction(bit: 2, dx: 0, dy: 1)
|
||||
let E = Direction(bit: 4, dx: 1, dy: 0)
|
||||
let W = Direction(bit: 8, dx: -1, dy: 0)
|
||||
enum Direction:Int {
|
||||
case north = 1
|
||||
case south = 2
|
||||
case east = 4
|
||||
case west = 8
|
||||
|
||||
static var allDirections:[Direction] {
|
||||
return [Direction.north, Direction.south, Direction.east, Direction.west]
|
||||
}
|
||||
|
||||
var opposite:Direction {
|
||||
switch self {
|
||||
case .north:
|
||||
return .south
|
||||
case .south:
|
||||
return .north
|
||||
case .east:
|
||||
return .west
|
||||
case .west:
|
||||
return .east
|
||||
}
|
||||
}
|
||||
|
||||
var diff:(Int, Int) {
|
||||
switch self {
|
||||
case .north:
|
||||
return (0, -1)
|
||||
case .south:
|
||||
return (0, 1)
|
||||
case .east:
|
||||
return (1, 0)
|
||||
case .west:
|
||||
return (-1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
var char:String {
|
||||
switch self {
|
||||
case .north:
|
||||
return "N"
|
||||
case .south:
|
||||
return "S"
|
||||
case .east:
|
||||
return "E"
|
||||
case .west:
|
||||
return "W"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MazeGenerator {
|
||||
let x:Int!
|
||||
let y:Int!
|
||||
var maze:[[Int]]!
|
||||
let x:Int
|
||||
let y:Int
|
||||
var maze:[[Int]]
|
||||
|
||||
init(_ x:Int, _ y:Int) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
var col = [Int](count: y, repeatedValue: 0)
|
||||
self.maze = [[Int]](count: x, repeatedValue: col)
|
||||
let column = [Int](repeating: 0, count: y)
|
||||
self.maze = [[Int]](repeating: column, count: x)
|
||||
generateMaze(0, 0)
|
||||
}
|
||||
|
||||
func display() {
|
||||
for i in 0..<y {
|
||||
// Draw top edge
|
||||
for j in 0..<x {
|
||||
print((maze[j][i] & 1) == 0 ? "+---" : "+ ")
|
||||
private func generateMaze(_ cx:Int, _ cy:Int) {
|
||||
var directions = Direction.allDirections
|
||||
directions.shuffle()
|
||||
for direction in directions {
|
||||
let (dx, dy) = direction.diff
|
||||
let nx = cx + dx
|
||||
let ny = cy + dy
|
||||
if inBounds(nx, ny) && maze[nx][ny] == 0 {
|
||||
maze[cx][cy] |= direction.rawValue
|
||||
maze[nx][ny] |= direction.opposite.rawValue
|
||||
generateMaze(nx, ny)
|
||||
}
|
||||
println("+")
|
||||
}
|
||||
}
|
||||
|
||||
private func inBounds(_ testX:Int, _ testY:Int) -> Bool {
|
||||
return inBounds(value:testX, upper:self.x) && inBounds(value:testY, upper:self.y)
|
||||
}
|
||||
|
||||
private func inBounds(value:Int, upper:Int) -> Bool {
|
||||
return (value >= 0) && (value < upper)
|
||||
}
|
||||
|
||||
func display() {
|
||||
let cellWidth = 3
|
||||
for j in 0..<y {
|
||||
// Draw top edge
|
||||
var topEdge = ""
|
||||
for i in 0..<x {
|
||||
topEdge += "+"
|
||||
topEdge += String(repeating: (maze[i][j] & Direction.north.rawValue) == 0 ? "-" : " ", count: cellWidth)
|
||||
}
|
||||
topEdge += "+"
|
||||
print(topEdge)
|
||||
|
||||
// Draw left edge
|
||||
for j in 0..<x {
|
||||
print((maze[j][i] & 8) == 0 ? "| " : " ")
|
||||
var leftEdge = ""
|
||||
for i in 0..<x {
|
||||
leftEdge += (maze[i][j] & Direction.west.rawValue) == 0 ? "|" : " "
|
||||
leftEdge += String(repeating: " ", count: cellWidth)
|
||||
}
|
||||
println("|")
|
||||
leftEdge += "|"
|
||||
print(leftEdge)
|
||||
}
|
||||
|
||||
// Draw bottom edge
|
||||
for j in 0..<x {
|
||||
print("+---")
|
||||
var bottomEdge = ""
|
||||
for _ in 0..<x {
|
||||
bottomEdge += "+"
|
||||
bottomEdge += String(repeating: "-", count: cellWidth)
|
||||
}
|
||||
println("+")
|
||||
bottomEdge += "+"
|
||||
print(bottomEdge)
|
||||
}
|
||||
|
||||
func generateMaze(cx:Int, _ cy:Int) {
|
||||
var dirs = [N, S, E, W] as NSMutableArray
|
||||
for i in 0..<dirs.count {
|
||||
let x1 = Int(arc4random()) % dirs.count
|
||||
let x2 = Int(arc4random()) % dirs.count
|
||||
dirs.exchangeObjectAtIndex(x1, withObjectAtIndex: x2)
|
||||
}
|
||||
|
||||
for dir in dirs {
|
||||
var dir = dir as Direction
|
||||
let nx = cx + dir.dx
|
||||
let ny = cy + dir.dy
|
||||
if (between(nx, self.x) && between(ny, self.y) && (maze[nx][ny] == 0)) {
|
||||
maze[cx][cy] |= dir.bit
|
||||
maze[nx][ny] |= dir.opposite.bit
|
||||
generateMaze(nx, ny)
|
||||
func displayInts() {
|
||||
for j in 0..<y {
|
||||
var line = ""
|
||||
for i in 0..<x {
|
||||
line += String(maze[i][j]) + "\t"
|
||||
}
|
||||
|
||||
print(line)
|
||||
}
|
||||
}
|
||||
|
||||
func between(v:Int, _ upper:Int) -> Bool {
|
||||
return (v >= 0) && (v < upper)
|
||||
func displayDirections() {
|
||||
for j in 0..<y {
|
||||
var line = ""
|
||||
for i in 0..<x {
|
||||
line += getDirectionsAsString(maze[i][j]) + "\t"
|
||||
}
|
||||
print(line)
|
||||
}
|
||||
}
|
||||
|
||||
private func getDirectionsAsString(_ value:Int) -> String {
|
||||
var line = ""
|
||||
for direction in Direction.allDirections {
|
||||
if (value & direction.rawValue) != 0 {
|
||||
line += direction.char
|
||||
}
|
||||
}
|
||||
return line
|
||||
}
|
||||
}
|
||||
|
||||
let x = 10
|
||||
|
||||
let x = 20
|
||||
let y = 10
|
||||
let maze = MazeGenerator(x, y)
|
||||
maze.display()
|
||||
|
|
|
|||
21
Task/Maze-generation/Zkl/maze-generation.zkl
Normal file
21
Task/Maze-generation/Zkl/maze-generation.zkl
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
fcn make_maze(w = 16, h = 8){
|
||||
// make arrays with lists of lists (all mutable)
|
||||
vis:=(w.pump(List().write,0)+1)*h + w.pump(List().write,1);
|
||||
ver:=(w.pump(List().write,T(Void,"| ")) + "|")*h + T;
|
||||
hor:=(w.pump(List().write,T(Void,"+---")) + "+")*(h + 1);
|
||||
|
||||
fcn(x,y,vis,ver,hor){
|
||||
vis[y][x] = 1;
|
||||
|
||||
d:=L(T(x - 1, y), T(x, y + 1), T(x + 1, y), T(x, y - 1)).shuffle();
|
||||
foreach xx,yy in (d){
|
||||
if(vis[yy][xx]) continue;
|
||||
if(xx==x) hor[y.max(yy)][x]="+ ";
|
||||
if(yy==y) ver[y][x.max(xx)]=" ";
|
||||
self.fcn(xx,yy,vis,ver,hor);
|
||||
}
|
||||
}((0).random(w),(0).random(h),vis,ver,hor);
|
||||
foreach a,b in (hor.zip(ver)) { println(a.concat(),"\n",b.concat()) }
|
||||
return(ver,hor);
|
||||
}
|
||||
make_maze();
|
||||
Loading…
Add table
Add a link
Reference in a new issue