September Morn Update

This commit is contained in:
Ingy döt Net 2019-09-12 10:33:56 -07:00
parent 4e2d22a71d
commit aac6731f2c
6856 changed files with 141342 additions and 21127 deletions

View file

@ -1,27 +1,24 @@
void
grid_maze(data b, integer N)
{
data d;
integer i, j;
call_n(N, b_suffix, d, "+---");
b_suffix(d, "+\n");
N.times(bb_cast, d, "+---");
bb_cast(d, "+\n");
call_n(N, b_suffix, d, "| * ");
b_suffix(d, "|\n");
N.times(bb_cast, d, "| * ");
bb_cast(d, "|\n");
call_n(N, b_extend, b, d);
N.times(bb_copy, b, d);
b_size(d, N * 4 + 2);
b_extend(b, d);
bb_copy(b, d);
}
void
walk_cell(data b, integer N, integer line_size, integer x, integer y,
list x_offsets, list y_offsets)
walk_cell(data b, integer N, line_size, x, y, list x_offsets, y_offsets)
{
integer i, r;
integer i, p, q, r;
b_replace(b, y + x, ' ');
@ -29,29 +26,25 @@ walk_cell(data b, integer N, integer line_size, integer x, integer y,
i = 0;
while (i < 4) {
integer p, q;
p = x + x_offsets[q = (r + i) & 3];
q = y + y_offsets[q];
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[q + p] == '*') {
walk_cell(b, N, line_size, p, q, x_offsets, y_offsets);
if (-1 < p && p < line_size
&& -1 < q && q < line_size * (N * 2 + 1)) {
if (b[q + p] == '*') {
walk_cell(b, N, line_size, p, q, x_offsets, y_offsets);
b[(q + y) / 2 + (p + x) / 2] = ' ';
if (p == x) {
b[(q + y) / 2 + p - 1] = ' ';
b[(q + y) / 2 + p + 1] = ' ';
}
}
}
}
}
}
i += 1;
i += 1;
}
}
void
walk_maze(data b, integer N)
{
integer line_size, x, y;
@ -68,18 +61,14 @@ walk_maze(data b, integer N)
walk_cell(b, N, line_size, x, y, x_offsets, y_offsets);
}
integer
main(void)
{
data b;
integer N;
N = 10;
grid_maze(b, N);
walk_maze(b, N);
grid_maze(b, 10);
walk_maze(b, 10);
o_(b);
return 0;
0;
}

View file

@ -0,0 +1,59 @@
100 MS=10:REM MAZE SIZE
110 DIM S(MS+1,MS+1):REM SOUTH WALLS
120 DIM W(MS+1,MS+1):REM WEST WALLS
130 DIM V(MS+1,MS+1):REM VISITED CELLS
140 PRINT "INITIALIZING..."
150 GOSUB 260:REM INITIALIZE MAZE
160 PRINT "BUILDING..."
170 DIM PC(MS*MS+1):DIM PR(MS*MS+1):REM STACK
180 REM PICK RANDOM STARTING CELL
190 X = RND(-TI)
200 C=(INT(RND(1)*MS)+1)
210 R=(INT(RND(1)*MS)+1)
220 GOSUB 400:REM BUILD MAZE
230 GOSUB 540:REM DRAW MAZE
240 END
250 REM -----INITIALIZE MAZE-----
260 REM SET WALLS ON AND VISITED CELLS OFF
270 T=MS+1
280 FOR C=0 TO T:FOR R=0 TO T:
290 S(C,R)=1:W(C,R)=1:V(C,R)=0
300 NEXT R:NEXT C
310 REM SET BORDER CELLS TO VISITED
320 FOR C=0 TO T
330 V(C,0)=1:V(C,T)=1
340 NEXT C
350 FOR R=0 TO T
360 V(0,R)=1:V(T,R)=1
370 NEXT R
380 RETURN
390 REM -----BUILD MAZE-----
400 U=U+1:PC(U)=C:PR(U)=R:REM PUSH
410 V(C,R)=1
420 IF V(C,R+1)=1 AND V(C+1,R)=1 AND V(C,R-1)=1 AND V(C-1,R)=1 THEN GOTO 500
430 Z=INT(RND(1)*4)
440 IF Z=0 AND V(C,R+1)=0 THEN S(C,R)=0:R=R+1:GOTO 400
450 IF Z=1 AND V(C+1,R)=0 THEN W(C+1,R)=0:C=C+1:GOTO 400
460 IF Z=2 AND V(C,R-1)=0 THEN S(C,R-1)=0:R=R-1:GOTO 400
470 IF Z=3 AND V(C-1,R)=0 THEN W(C,R)=0:C=C-1:GOTO 400
480 GOTO 430
500 C=PC(U):R=PR(U):U=U-1:REM POP
510 IF U > 0 THEN GOTO 420
520 RETURN
530 REM -----DRAW MAZE-----
540 REM OPEN 4,4:CMD 4:REM SEND OUTPUT TO PRINTER
550 PRINT "+--+--+--+--+--+--+--+--+--+--+"
560 FOR R = 1 TO MS
570 FOR C = 1 TO MS+1
580 IF W(C,R)=0 THEN PRINT " ";
590 IF W(C,R)=1 THEN PRINT ": ";
600 NEXT C
610 PRINT
620 FOR C = 1 TO MS
630 IF S(C,R)=0 THEN PRINT "+ ";
640 IF S(C,R)=1 THEN PRINT "+--";
650 NEXT C
660 PRINT "+"
670 NEXT R
680 REM PRINT#4:CLOSE 4:REM CLOSE PRINTER DEVICE
690 RETURN

View file

@ -0,0 +1,37 @@
; maze generation
(import (otus random!))
(define WIDTH 30)
(define HEIGHT 8)
(define maze
(map (lambda (?)
(repeat #b01111 WIDTH)) ; 0 - unvisited, 1111 - all walls exists
(iota HEIGHT)))
(define (at x y)
(list-ref (list-ref maze y) x))
(define (unvisited? x y)
(if (and (< -1 x WIDTH) (< -1 y HEIGHT))
(zero? (band (at x y) #b10000))))
(define neighbors '((-1 . 0) (0 . -1) (+1 . 0) (0 . +1)))
(define walls '( #b10111 #b11011 #b11101 #b11110))
(define antiwalls '( #b11101 #b11110 #b10111 #b11011))
(let loop ((x (rand! WIDTH)) (y (rand! HEIGHT)))
(list-set! (list-ref maze y) x (bor (at x y) #b10000))
(let try ()
(if (or
(unvisited? (- x 1) y) ; left
(unvisited? x (- y 1)) ; top
(unvisited? (+ x 1) y) ; right
(unvisited? x (+ y 1))) ; bottom
(let*((p (rand! 4))
(neighbor (list-ref neighbors p)))
(let ((nx (+ x (car neighbor)))
(ny (+ y (cdr neighbor))))
(if (unvisited? nx ny)
(let ((ncell (at nx ny)))
(list-set! (list-ref maze y) x (band (at x y) (list-ref walls p)))
(list-set! (list-ref maze ny) nx (band ncell (list-ref antiwalls p)))
(loop nx ny)))
(try))))))

View file

@ -0,0 +1,22 @@
; maze printing:
(display "+")
(for-each (lambda (?) (display "--+")) (iota WIDTH))
(print)
(for-each (lambda (l)
; left wall (always)
(display "|")
; draw right wall
(for-each (lambda (x)
(display " ")
(display (if (zero? (band x #b10)) " " "|")))
l)
(print)
(display "+")
; draw bottom wall
(for-each (lambda (x)
(display (if (zero? (band x #b01)) " " "--"))
(display "+"))
l)
(print))
maze)
(print)

View file

@ -0,0 +1,148 @@
<?php
class Maze
{
protected $width;
protected $height;
protected $grid;
protected $path;
protected $horWalls;
protected $vertWalls;
protected $dirs;
protected $isDebug;
public function __construct($x, $y, $debug = false)
{
$this->width = $x;
$this->height = $y;
$this->path = [];
$this->dirs = [ [0, -1], [0, 1], [-1, 0], [1, 0]]; // array of coordinates of N,S,W,E
$this->horWalls = []; // list of removed horizontal walls (---+)
$this->vertWalls = [];// list of removed vertical walls (|)
$this->isDebug = $debug; // debug flag
// generate the maze:
$this->generate();
}
protected function generate()
{
$this->initMaze(); // init the stack and an unvisited grid
// start from a random cell and then proceed recursively
$this->walk(mt_rand(0, $this->width-1), mt_rand(0, $this->height-1));
}
/**
* Actually prints the Maze, on stdOut. Put in a separate method to allow extensibility
* For simplicity sake doors are positioned on the north wall and east wall
*/
public function printOut()
{
$this->log("Horizontal walls: %s", json_encode($this->horWalls));
$this->log("Vertical walls: %s", json_encode($this->vertWalls));
$northDoor = mt_rand(0,$this->width-1);
$eastDoor = mt_rand(0, $this->height-1);
$str = '+';
for ($i=0;$i<$this->width;$i++) {
$str .= ($northDoor == $i) ? ' +' : '---+';
}
$str .= PHP_EOL;
for ($i=0; $i<$this->height; $i++) {
for ($j=0; $j<$this->width; $j++) {
$str .= (!empty($this->vertWalls[$j][$i]) ? $this->vertWalls[$j][$i] : '| ');
}
$str .= ($i == $eastDoor ? ' ' : '|').PHP_EOL.'+';
for ($j=0; $j<$this->width; $j++) {
$str .= (!empty($this->horWalls[$j][$i]) ? $this->horWalls[$j][$i] : '---+');
}
$str .= PHP_EOL;
}
echo $str;
}
/**
* Logs to stdOut if debug flag is enabled
*/
protected function log(...$params)
{
if ($this->isDebug) {
echo vsprintf(array_shift($params), $params).PHP_EOL;
}
}
private function walk($x, $y)
{
$this->log('Entering cell %d,%d', $x, $y);
// mark current cell as visited
$this->grid[$x][$y] = true;
// add cell to path
$this->path[] = [$x, $y];
// get list of all neighbors
$neighbors = $this->getNeighbors($x, $y);
$this->log("Valid neighbors: %s", json_encode($neighbors));
if(empty($neighbors)) {
// Dead end, we need now to backtrack, if there's still any cell left to be visited
$this->log("Start backtracking along path: %s", json_encode($this->path));
array_pop($this->path);
if (!empty($this->path)) {
$next = array_pop($this->path);
return $this->walk($next[0], $next[1]);
}
} else {
// randomize neighbors, as per request
shuffle($neighbors);
foreach ($neighbors as $n) {
$nextX = $n[0];
$nextY = $n[1];
if ($nextX == $x) {
$wallY = max($nextY, $y);
$this->log("New cell is on the same column (%d,%d), removing %d, (%d-1) horizontal wall", $nextX, $nextY, $x, $wallY);
$this->horWalls[$x][min($nextY, $y)] = " +";
}
if ($nextY == $y) {
$wallX = max($nextX, $x);
$this->log("New cell is on the same row (%d,%d), removing %d,%d vertical wall", $nextX, $nextY, $wallX, $y);
$this->vertWalls[$wallX][$y] = " ";
}
return $this->walk($nextX, $nextY);
}
}
}
/**
* Initialize an empty grid of $width * $height dimensions
*/
private function initMaze()
{
for ($i=0;$i<$this->width;$i++) {
for ($j = 0;$j<$this->height;$j++) {
$this->grid[$i][$j] = false;
}
}
}
/**
* @param int $x
* @param int $y
* @return array
*/
private function getNeighbors($x, $y)
{
$neighbors = [];
foreach ($this->dirs as $dir) {
$nextX = $dir[0] + $x;
$nextY = $dir[1] + $y;
if (($nextX >= 0 && $nextX < $this->width && $nextY >= 0 && $nextY < $this->height) && !$this->grid[$nextX][$nextY]) {
$neighbors[] = [$nextX, $nextY];
}
}
return $neighbors;
}
}
$maze = new Maze(10,10);
$maze->printOut();

View file

@ -1,103 +1,98 @@
/*REXX program generates and displays a rectangular solvable maze (of any size).*/
height=0; @.=0 /*default for all cells visited. */
/*REXX program generates and displays a rectangular solvable maze (of any size). */
parse arg rows cols seed . /*allow user to specify the maze size. */
if rows='' | rows=="," then rows=19 /*No rows given? Then use the default.*/
if cols='' | cols=="," then cols=19 /* " cols " ? " " " " */
if seed\=='' then call random ,,seed /*use a random seed for repeatability.*/
call buildRow ''copies("~┬",cols-1)'~' /*construct the top edge of the maze. */
if rows='' | rows==',' then rows= 19 /*No rows given? Then use the default.*/
if cols='' | cols==',' then cols= 19 /* " cols " ? " " " " */
if datatype(seed, 'W') then call random ,,seed /*use a random seed for repeatability.*/
ht=0; @.=0 /*HT= # rows in grid; @.: default cell*/
call makeRow ''copies('~', cols - 1)'~' /*construct the top edge of the maze. */
/* [↓] construct the maze's grid. */
do r=1 for rows; _=; __=; hp= "|"; hj=''
do c=1 for cols; _= _||hp'1'; __=__||hj"~"; hj=''; hp=""
end /*c*/
call buildRow _'' /*construct the right edge of the cells*/
if r\==rows then call buildRow __'' /* " " " " " " maze.*/
end /*r*/
do r=1 for rows; _=; __=; hp= "|"; hj= ''
do c=1 for cols; _= _ || hp'1'; __= __ || hj"~"; hj= ''; hp= ""
end /*c*/
call makeRow _'' /*construct the right edge of the cells*/
if r\==rows then call makeRow __'' /* " " " " " " maze.*/
end /*r*/ /* [↑] construct the maze's grid. */
call buildRow ''copies("~┴", cols-1)'~' /*construct the bottom edge of the maze*/
r!=random(1,rows)*2; c!=random(1,cols)*2; @.r!.c!=0 /*choose the first cell in maze*/
call makeRow ''copies("~┴", cols - 1)'~' /*construct the bottom edge of the maze*/
r!= random(1, rows) *2; c!= random(1, cols) *2; @.r!.c!= 0 /*choose 1st cell.*/
/* [↓] traipse through the maze. */
do forever; n=hood(r!,c!)
if n==0 then if \fCell() then leave
call ?; @._r._c=0 /*get the (next) maze direction to go. */
ro=r!; co=c!; r!=_r; c!=_c /*save original maze cell coordinates. */
?.zr=?.zr%2; ?.zc=?.zc%2 /*get the maze row and cell directions.*/
rw=ro+?.zr; cw=co+?.zc /*calculate the next row and column. */
@.rw.cw=. /*mark the maze cell as being visited. */
do forever; n= hood(r!, c!); if n==0 then if \fCell() then leave /*¬freecell?*/
call ?; @._r._c= 0 /*get the (next) maze direction to go. */
ro= r!; co= c!; r!= _r; c!= _c /*save original maze cell coordinates. */
?.zr= ?.zr % 2; ?.zc= ?.zc % 2 /*get the maze row and cell directions.*/
rw= ro + ?.zr; cw= co + ?.zc /*calculate the next row and column. */
@.rw.cw= . /*mark the maze cell as being visited. */
end /*forever*/
do r=1 for height; _= /*display the maze. */
do c=1 for cols*2 + 1; _=_ || @.r.c; end /*c*/
if \(r//2) then _=translate(_, '\', .) /*trans to backslash*/
@.r=_ /*save the row in @.*/
/* [↓] display maze to the terminal. */
do r=1 for ht; _=
do c=1 for cols*2 + 1; _= _ || @.r.c; end /*c*/
if \(r//2) then _= translate(_, '\', .) /*trans to backslash*/
@.r= _ /*save the row in @.*/
end /*r*/
do #=1 for height; _=@.# /*display the maze to the terminal. */
call makeNice /*make some cell corners look prettier.*/
_=changestr(1 , _, 111) /*──────these four ────────────────────*/
_=changestr(0 , _, 000) /*───────── statements are ────────────*/
_=changestr(. , _, " ") /*────────────── used for preserving ──*/
_=changestr('~' , _, "───") /*────────────────── the aspect ratio. */
say translate(_ , '', "═|\10") /*make it presentable for the screen. */
do #=1 for ht; _= @.# /*display the maze to the terminal. */
call makeNice /*prettify cell corners and dead─ends. */
_= changestr( 1 , _ , 111 ) /*──────these four ────────────────────*/
_= changestr( 0 , _ , 000 ) /*───────── statements are ────────────*/
_= changestr( . , _ , " " ) /*────────────── used for preserving ──*/
_= changestr('~', _ , "───" ) /*────────────────── the aspect ratio. */
say translate( _ , '' , "═|\10" ) /*make it presentable for the screen. */
end /*#*/
end /*#*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
@: parse arg _r,_c; return @._r._c /*a fast way to reference a maze cell. */
hood: parse arg rh,ch; return @(rh+2,ch) + @(rh-2,ch) + @(rh,ch-2) + @(rh,ch+2)
@: parse arg _r,_c; return @._r._c /*a fast way to reference a maze cell. */
makeRow: parse arg z; ht= ht+1; do c=1 for length(z); @.ht.c=substr(z,c,1); end; return
hood: parse arg rh,ch; return @(rh+2,ch) + @(rh-2,ch) + @(rh,ch-2) + @(rh,ch+2)
/*──────────────────────────────────────────────────────────────────────────────────────*/
?: do forever; ?.=0; ?=random(1,4); if ?==1 then ?.zc=-2 /*north*/
if ?==2 then ?.zr= 2 /* east*/
if ?==3 then ?.zc= 2 /*south*/
if ?==4 then ?.zr=-2 /* west*/
_r=r!+?.zr; _c=c!+?.zc; if @._r._c==1 then return
end /*forever*/
?: do forever; ?.= 0; ?= random(1, 4); if ?==1 then ?.zc= -2 /*north*/
if ?==2 then ?.zr= 2 /* east*/
if ?==3 then ?.zc= 2 /*south*/
if ?==4 then ?.zr= -2 /* west*/
_r= r! + ?.zr; _c= c! + ?.zc; if @._r._c == 1 then return
end /*forever*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
buildRow: parse arg z; height=height+1; width=length(z)
do c=1 for width; @.height.c=substr(z,c,1); end; return
fCell: do r=1 for rows; rr= r + r
do c=1 for cols; cc= c + c
if hood(rr,cc)==1 then do; r!= rr; c!= cc; @.r!.c!= 0; return 1; end
end /*c*/ /* [↑] r! and c! are used by invoker.*/
end /*r*/; return 0
/*──────────────────────────────────────────────────────────────────────────────────────*/
fCell: do r=1 for rows; rr=r+r
do c=1 for cols; cc=c+c
if hood(rr, cc)==1 then do; r!=rr; c!=cc; @.r!.c!=0; return 1; end
end /*c*/
end /*r*/ /* [↑] r! and c! are used by invoker.*/
return 0
/*──────────────────────────────────────────────────────────────────────────────────────*/
makeNice: width=length(_); old=#-1; new=#+1; old_=@.old; new_=@.new
if left(_,2) =='.' then _=translate(_, "|", '')
if right(_,2)=='.' then _=translate(_, "|", '')
/* [↓] handle the top row of the grid.*/
do k=1 for width while #==1; z=substr(_,k,1) /*maze top row.*/
if z\=='' then iterate
if substr(new_,k,1)=='\' then _=overlay("",_,k)
end /*k*/
makeNice: width= length(_); old= # - 1; new= # + 1; old_= @.old; new_= @.new
if left(_, 2)=='.' then _= translate(_, "|", '')
if right(_,2)=='.' then _= translate(_, "|", '')
do k=1 for width while #==height; z=substr(_,k,1) /*maze bot row.*/
if z\=='' then iterate
if substr(old_, k, 1)=='\' then _=overlay("", _, k)
end /*k*/
/* [↓] handle the mid rows of the grid*/
do k=3 to width-2 by 2 while #//2; z=substr(_,k,1) /*maze mid rows*/
if z\=='' then iterate
le=substr(_,k-1,1)
ri=substr(_,k+1,1)
up=substr(old_,k,1)
dw=substr(new_,k,1)
select
when le== . & ri== . & up=='' & dw=="" then _=overlay('|',_,k)
when le=='~' & ri=="~" & up=='\' & dw=="\" then _=overlay('',_,k)
when le=='~' & ri=="~" & up=='\' & dw=="" then _=overlay('',_,k)
when le=='~' & ri=="~" & up=='' & dw=="\" then _=overlay('',_,k)
when le=='~' & ri== . & up=='\' & dw=="\" then _=overlay('',_,k)
when le== . & ri=="~" & up=='\' & dw=="\" then _=overlay('',_,k)
when le== . & ri== . & up=='' & dw=="\" then _=overlay('|',_,k)
when le== . & ri== . & up=='\' & dw=="" then _=overlay('|',_,k)
when le== . & ri=="~" & up=='\' & dw=="" then _=overlay('',_,k)
when le== . & ri=="~" & up=='' & dw=="\" then _=overlay('',_,k)
when le=='~' & ri== . & up=='\' & dw=="" then _=overlay('',_,k)
when le=='~' & ri== . & up=='' & dw=="\" then _=overlay('',_,k)
when le=='~' & ri== . & up=='' & dw=="" then _=overlay('',_,k)
when le== . & ri=="~" & up=='' & dw=="" then _=overlay('',_,k)
otherwise nop
end /*select*/
end /*k*/
return
do k=1 for width while #==1; z= substr(_, k, 1) /*maze top row.*/
if z\=='' then iterate
if substr(new_, k, 1)=='\' then _= overlay("", _, k)
end /*k*/
do k=1 for width while #==ht; z= substr(_, k, 1) /*maze bot row.*/
if z\=='' then iterate
if substr(old_, k, 1)=='\' then _= overlay("", _, k)
end /*k*/
do k=3 to width-2 by 2 while #//2; z= substr(_, k, 1) /*maze mid rows*/
if z\=='' then iterate
le= substr(_ , k-1, 1)
ri= substr(_ , k+1, 1)
up= substr(old_, k , 1)
dw= substr(new_, k , 1)
select
when le== . & ri== . & up=='' & dw=="" then _= overlay('|', _, k)
when le=='~' & ri=="~" & up=='\' & dw=="\" then _= overlay('', _, k)
when le=='~' & ri=="~" & up=='\' & dw=="" then _= overlay('', _, k)
when le=='~' & ri=="~" & up=='' & dw=="\" then _= overlay('', _, k)
when le=='~' & ri== . & up=='\' & dw=="\" then _= overlay('', _, k)
when le== . & ri=="~" & up=='\' & dw=="\" then _= overlay('', _, k)
when le== . & ri== . & up=='' & dw=="\" then _= overlay('|', _, k)
when le== . & ri== . & up=='\' & dw=="" then _= overlay('|', _, k)
when le== . & ri=="~" & up=='\' & dw=="" then _= overlay('', _, k)
when le== . & ri=="~" & up=='' & dw=="\" then _= overlay('', _, k)
when le=='~' & ri== . & up=='\' & dw=="" then _= overlay('', _, k)
when le=='~' & ri== . & up=='' & dw=="\" then _= overlay('', _, k)
when le=='~' & ri== . & up=='' & dw=="" then _= overlay('', _, k)
when le== . & ri=="~" & up=='' & dw=="" then _= overlay('', _, k)
otherwise nop
end /*select*/
end /*k*/; return

View file

@ -1,58 +1,54 @@
/*REXX program generates and displays a rectangular solvable maze (of any size). */
height=0; @.=0 /*default for all cells visited. */
parse arg rows cols seed . /*allow user to specify the maze size. */
if rows='' | rows=="," then rows=19 /*No rows given? Then use the default.*/
if cols='' | cols=="," then cols=19 /* " cols " ? " " " " */
if seed\=='' then call random ,,seed /*use a random seed for repeatability.*/
call buildRow ''copies("─┬", cols-1)'' /*construct the top edge of the maze.*/
/* [↓] construct the maze's grid. */
do r=1 for rows; _=; __=; hp= "|"; hj=''
do c=1 for cols; _= _||hp'1'; __=__||hj""; hj=''; hp=""
end /*c*/
call buildRow _'' /*construct the right edge of the cells*/
if r\==rows then call buildRow __'' /* " " " " " " maze.*/
end /*r*/
if rows='' | rows=="," then rows= 19 /*No rows given? Then use the default.*/
if cols='' | cols=="," then cols= 19 /* " cols " ? " " " " */
if datatype(seed, 'W') then call random ,,seed /*use a random seed for repeatability.*/
ht=0; @.=0 /*HT= # rows in grid; @.: default cell*/
call makeRow ''copies("─┬", cols-1)'' /*construct the top edge of the maze.*/
call buildRow ''copies("─┴", cols-1)'' /*construct the bottom edge of the maze*/
r!=random(1,rows)*2; c!=random(1,cols)*2; @.r!.c!=0 /*choose the first cell.*/
do r=1 for rows; _=; __=; hp= "|"; hj= ''
do c=1 for cols; _= _ || hp'1'; __= __ || hj""; hj= ''; hp= ""
end /*c*/
call makeRow _'' /*construct the right edge of the cells*/
if r\==rows then call makeRow __'' /* " " " " " " maze.*/
end /*r*/ /* [↑] construct the maze's grid. */
call makeRow ''copies("─┴", cols-1)'' /*construct the bottom edge of the maze*/
r!= random(1, rows)*2; c!= random(1, cols)*2; @.r!.c!= 0 /*choose the 1st cell.*/
/* [↓] traipse through the maze. */
do forever; n=hood(r!, c!) /*number of free maze cells. */
if n==0 then if \fCell() then leave /*if no free maze cells left, then done*/
call ?; @._r._c=0 /*get the (next) maze direction to go. */
ro=r!; co=c!; r!=_r; c!=_c /*save the original cell coordinates. */
?.zr=?.zr%2; ?.zc=?.zc%2 /*get the maze row and cell directions.*/
rw=ro+?.zr; cw=co+?.zc /*calculate the next maze row and col. */
do forever; n= hood(r!, c!) /*number of free maze cells. */
if n==0 then if \fCell() then leave /*if no free maze cells left, then done*/
call ?; @._r._c= 0 /*get the (next) maze direction to go. */
ro= r!; co= c!; r!= _r; c!= _c /*save the original cell coordinates. */
?.zr= ?.zr % 2; ?.zc= ?.zc % 2 /*get the maze row and cell directions.*/
rw= ro + ?.zr; cw= co + ?.zc /*calculate the next maze row and col. */
@.rw.cw=. /*mark the maze cell as being visited. */
end /*forever*/
do r=1 for height; _= /*display the maze. */
do c=1 for cols*2 + 1; _=_ || @.r.c; end /*c*/
if \(r//2) then _=translate(_, '\', .) /*trans to backslash*/
_=changestr(1 , _, 111) /*──────these four ────────────────────*/
_=changestr(0 , _, 000) /*───────── statements are ────────────*/
_=changestr(. , _, " ") /*────────────── used for preserving ──*/
_=changestr('', _, "───") /*────────────────── the aspect ratio. */
say translate(_, '', "|\10") /*make it presentable for the screen. */
/* [↓] display maze to the terminal. */
do r=1 for ht; _=
do c=1 for cols*2 + 1; _= _ || @.r.c; end /*c*/
if \(r//2) then _= translate(_, '\',.) /*translate a period to a backslash.*/
_= changestr( 1 , _ , 111 ) /*──────these four ────────────────────*/
_= changestr( 0 , _ , 000 ) /*───────── statements are ────────────*/
_= changestr( . , _ , " " ) /*────────────── used for preserving ──*/
_= changestr('', _ , "───" ) /*────────────────── the aspect ratio. */
say translate( _ , '' , "|\10") /*make it presentable for the screen. */
end /*r*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
@: parse arg _r,_c; return @._r._c /*a fast way to reference a maze cell. */
@: parse arg _r,_c; return @._r._c /*a fast way to reference a maze cell. */
makeRow: parse arg z; ht= ht+1; do c=1 for length(z); @.ht.c=substr(z,c,1); end; return
hood: parse arg rh,ch; return @(rh+2,ch) + @(rh-2,ch) + @(rh,ch-2) + @(rh,ch+2)
/*──────────────────────────────────────────────────────────────────────────────────────*/
?: do forever; ?.=0; ?=random(1,4); if ?==1 then ?.zc=-2 /*north*/
if ?==2 then ?.zr= 2 /* east*/
if ?==3 then ?.zc= 2 /*south*/
if ?==4 then ?.zr=-2 /* west*/
_r=r!+?.zr; _c=c!+?.zc; if @._r._c==1 then return
end /*forever*/
?: do forever; ?.= 0; ?= random(1, 4); if ?==1 then ?.zc= -2 /*north*/
if ?==2 then ?.zr= 2 /* east*/
if ?==3 then ?.zc= 2 /*south*/
if ?==4 then ?.zr= -2 /* west*/
_r= r! + ?.zr; _c= c! + ?.zc; if @._r._c == 1 then return
end /*forever*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
buildRow: parse arg z; height=height+1; width=length(z)
do c=1 for width; @.height.c=substr(z,c,1); end; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
fCell: do r=1 for rows; rr=r+r
do c=1 for cols; cc=c+c
if hood(rr,cc)==1 then do; r!=rr; c!=cc; @.r!.c!=0; return 1; end
end /*c*/
end /*r*/ /* [↑] r! and c! are used by invoker.*/
return 0
/*──────────────────────────────────────────────────────────────────────────────────────*/
hood: parse arg rh,ch; return @(rh+2,ch) + @(rh-2,ch) + @(rh,ch-2) + @(rh,ch+2)
fCell: do r=1 for rows; rr= r + r
do c=1 for cols; cc= c + c
if hood(rr,cc)==1 then do; r!= rr; c!= cc; @.r!.c!= 0; return 1; end
end /*c*/ /* [↑] r! and c! are used by invoker.*/
end /*r*/; return 0

View file

@ -0,0 +1,137 @@
use rand::{thread_rng, Rng, rngs::ThreadRng};
const WIDTH: usize = 16;
const HEIGHT: usize = 16;
#[derive(Clone, Copy)]
struct Cell {
col: usize,
row: usize,
}
impl Cell {
fn from(col: usize, row: usize) -> Cell {
Cell {col, row}
}
}
struct Maze {
cells: [[bool; HEIGHT]; WIDTH], //cell visited/non visited
walls_h: [[bool; WIDTH]; HEIGHT + 1], //horizontal walls existing/removed
walls_v: [[bool; WIDTH + 1]; HEIGHT], //vertical walls existing/removed
thread_rng: ThreadRng, //Random numbers generator
}
impl Maze {
///Inits the maze, with all the cells unvisited and all the walls active
fn new() -> Maze {
Maze {
cells: [[true; HEIGHT]; WIDTH],
walls_h: [[true; WIDTH]; HEIGHT + 1],
walls_v: [[true; WIDTH + 1]; HEIGHT],
thread_rng: thread_rng(),
}
}
///Randomly chooses the starting cell
fn first(&mut self) -> Cell {
Cell::from(self.thread_rng.gen_range(0, WIDTH), self.thread_rng.gen_range(0, HEIGHT))
}
///Opens the enter and exit doors
fn open_doors(&mut self) {
let from_top: bool = self.thread_rng.gen();
let limit = if from_top { WIDTH } else { HEIGHT };
let door = self.thread_rng.gen_range(0, limit);
let exit = self.thread_rng.gen_range(0, limit);
if from_top {
self.walls_h[0][door] = false;
self.walls_h[HEIGHT][exit] = false;
} else {
self.walls_v[door][0] = false;
self.walls_v[exit][WIDTH] = false;
}
}
///Removes a wall between the two Cell arguments
fn remove_wall(&mut self, cell1: &Cell, cell2: &Cell) {
if cell1.row == cell2.row {
self.walls_v[cell1.row][if cell1.col > cell2.col { cell1.col } else { cell2.col }] = false;
} else {
self.walls_h[if cell1.row > cell2.row { cell1.row } else { cell2.row }][cell1.col] = false;
};
}
///Returns a random non-visited neighbor of the Cell passed as argument
fn neighbor(&mut self, cell: &Cell) -> Option<Cell> {
self.cells[cell.col][cell.row] = false;
let mut neighbors = Vec::new();
if cell.col > 0 && self.cells[cell.col - 1][cell.row] { neighbors.push(Cell::from(cell.col - 1, cell.row)); }
if cell.row > 0 && self.cells[cell.col][cell.row - 1] { neighbors.push(Cell::from(cell.col, cell.row - 1)); }
if cell.col < WIDTH - 1 && self.cells[cell.col + 1][cell.row] { neighbors.push(Cell::from(cell.col + 1, cell.row)); }
if cell.row < HEIGHT - 1 && self.cells[cell.col][cell.row + 1] { neighbors.push(Cell::from(cell.col, cell.row + 1)); }
if neighbors.is_empty() {
None
} else {
let next = neighbors.get(self.thread_rng.gen_range(0, neighbors.len())).unwrap();
self.remove_wall(cell, next);
Some(*next)
}
}
///Builds the maze (runs the Depth-first search algorithm)
fn build(&mut self) {
let mut cell_stack: Vec<Cell> = Vec::new();
let mut next = self.first();
loop {
while let Some(cell) = self.neighbor(&next) {
cell_stack.push(cell);
next = cell;
}
match cell_stack.pop() {
Some(cell) => next = cell,
None => break,
}
}
}
///Displays a wall
fn paint_wall(h_wall: bool, active: bool) {
if h_wall {
print!("{}", if active { "+---" } else { "+ " });
} else {
print!("{}", if active { "| " } else { " " });
}
}
///Displays a final wall for a row
fn paint_close_wall(h_wall: bool) {
if h_wall { println!("+") } else { println!() }
}
///Displays a whole row of walls
fn paint_row(&self, h_walls: bool, index: usize) {
let iter = if h_walls { self.walls_h[index].iter() } else { self.walls_v[index].iter() };
for &wall in iter {
Maze::paint_wall(h_walls, wall);
}
Maze::paint_close_wall(h_walls);
}
///Paints the maze
fn paint(&self) {
for i in 0 .. HEIGHT {
self.paint_row(true, i);
self.paint_row(false, i);
}
self.paint_row(true, HEIGHT);
}
}
fn main() {
let mut maze = Maze::new();
maze.build();
maze.open_doors();
maze.paint();
}

View file

@ -4,13 +4,6 @@
(defvar vi)
(defvar pa)
(defun scramble (list)
(let ((out ()))
(each ((item list))
(let ((r (random *r* (+ 1 (length out)))))
(set [out r..r] (list item))))
out))
(defun neigh (loc)
(let ((x (from loc))
(y (to loc)))
@ -19,7 +12,7 @@
(defun make-maze-rec (cu)
(set [vi cu] t)
(each ((ne (scramble (neigh cu))))
(each ((ne (shuffle (neigh cu))))
(cond ((not [vi ne])
(push ne [pa cu])
(push cu [pa ne])

View file

@ -2,13 +2,6 @@
(defvar pa) ;; path connectivity hash
(defvar sc) ;; count, derived from straightness fator
(defun scramble (list)
(let ((out ()))
(each ((item list))
(let ((r (rand (+ 1 (length out)))))
(set [out r..r] (list item))))
out))
(defun rnd-pick (list)
(if list [list (rand (length list))]))
@ -19,23 +12,20 @@
x..(- y 1) x..(+ y 1))))
(defun make-maze-impl (cu)
(let ((fr (hash :equal-based))
(q (list cu))
(let ((q (list cu))
(c sc))
(set [fr cu] t)
(set [vi cu] t)
(while q
(let* ((cu (first q))
(ne (rnd-pick (remove-if (orf vi fr) (neigh cu)))))
(cond (ne (set [fr ne] t)
(ne (rnd-pick (remove-if vi (neigh cu)))))
(cond (ne (set [vi ne] t)
(push ne [pa cu])
(push cu [pa ne])
(push ne q)
(cond ((<= (dec c) 0)
(set q (scramble q))
(set q (shuffle q))
(set c sc))))
(t (set [vi cu] t)
(del [fr cu])
(pop q)))))))
(t (pop q)))))))
(defun make-maze (w h sf)
(let ((vi (hash :equal-based))