September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View 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)))

View file

@ -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),

View file

@ -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()
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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())

View file

@ -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);
}
}

View 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'))

View file

@ -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()

View 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();