A-M baby
This commit is contained in:
parent
764da6cbbb
commit
db842d013d
19005 changed files with 197040 additions and 7 deletions
10
Task/Maze-generation/0DESCRIPTION
Normal file
10
Task/Maze-generation/0DESCRIPTION
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{{wikipedia|Maze generation algorithm}}
|
||||
Generate and show a maze, using the simple [[wp:Maze_generation_algorithm#Depth-first_search|Depth-first search]] algorithm.
|
||||
|
||||
<!-- BEGIN TEXT FROM WIKIPEDIA -->
|
||||
#Start at a random cell.
|
||||
#Mark the current cell as visited, and get a list of its neighbors. For each neighbor, starting with a randomly selected neighbor:
|
||||
#:If that neighbor hasn't been visited, remove the wall between this cell and that neighbor, and then recurse with that neighbor as the current cell.
|
||||
<!-- END TEXT FROM WIKIPEDIA -->
|
||||
|
||||
See also [[Maze solving]].
|
||||
2
Task/Maze-generation/1META.yaml
Normal file
2
Task/Maze-generation/1META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
note: Games
|
||||
187
Task/Maze-generation/AWK/maze-generation.awk
Normal file
187
Task/Maze-generation/AWK/maze-generation.awk
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
#!/usr/bin/awk -f
|
||||
|
||||
# Remember: AWK is 1-based, for better or worse.
|
||||
|
||||
BEGIN {
|
||||
# The maze dimensions.
|
||||
width = 20; # Global
|
||||
height = 20; # Global
|
||||
resetMaze();
|
||||
|
||||
# Some constants.
|
||||
top = 1;
|
||||
bottom = 2;
|
||||
left = 3;
|
||||
right = 4;
|
||||
|
||||
# Randomize the PRNG.
|
||||
randomize();
|
||||
|
||||
# Visit all the cells starting at a random point.
|
||||
visitCell(getRandX(), getRandY());
|
||||
|
||||
# Show the result.
|
||||
printMaze();
|
||||
}
|
||||
|
||||
# Wander through the maze removing walls as we go.
|
||||
function visitCell(x, y, dirList, dir, nx, ny, ndir, pi) {
|
||||
setVisited(x, y); # This cell has been visited.
|
||||
|
||||
# Visit neighbors in a random order.
|
||||
dirList = getRandDirList();
|
||||
for (dir = 1; dir <= 4; dir++) {
|
||||
# Get coordinates of a random neighbor (next in random direction list).
|
||||
ndir = substr(dirList, dir, 1);
|
||||
nx = getNextX(x, ndir);
|
||||
ny = getNextY(y, ndir);
|
||||
|
||||
# Visit an unvisited neighbor, removing the separating walls.
|
||||
if (wasVisited(nx, ny) == 0) {
|
||||
rmWall(x, y, ndir);
|
||||
rmWall(nx, ny, getOppositeDir(ndir));
|
||||
visitCell(nx, ny)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Display the text-mode maze.
|
||||
function printMaze( x, y, r, w) {
|
||||
for (y = 1; y <= height; y++) {
|
||||
for (pass = 1; pass <= 2; pass++) { # Go over each row twice: top, middle
|
||||
for (x = 1; x <= width; x++) {
|
||||
if (pass == 1) { # top
|
||||
printf("+");
|
||||
printf(hasWall(x, y, top) == 1 ? "---" : " ");
|
||||
if (x == width) printf("+");
|
||||
}
|
||||
else if (pass == 2) { # left, right
|
||||
printf(hasWall(x, y, left) == 1 ? "|" : " ");
|
||||
printf(" ");
|
||||
if (x == width) printf(hasWall(x, y, right) == 1 ? "|" : " ");
|
||||
}
|
||||
}
|
||||
print;
|
||||
}
|
||||
}
|
||||
for (x = 1; x <= width; x++) printf("+---"); # bottom row
|
||||
print("+"); # bottom right corner
|
||||
}
|
||||
|
||||
# Given a direction, get its opposite.
|
||||
function getOppositeDir(d) {
|
||||
if (d == top) return bottom;
|
||||
if (d == bottom) return top;
|
||||
if (d == left) return right;
|
||||
if (d == right) return left;
|
||||
}
|
||||
|
||||
# Build a list (string) of the four directions in random order.
|
||||
function getRandDirList( dirList, randDir, nx, ny, idx) {
|
||||
dirList = "";
|
||||
while (length(dirList) < 4) {
|
||||
randDir = getRandDir();
|
||||
if (!index(dirList, randDir)) {
|
||||
dirList = dirList randDir;
|
||||
}
|
||||
}
|
||||
return dirList;
|
||||
}
|
||||
|
||||
# Get x coordinate of the neighbor in a given a direction.
|
||||
function getNextX(x, dir) {
|
||||
if (dir == left) x = x - 1;
|
||||
if (dir == right) x = x + 1;
|
||||
if (!isGoodXY(x, 1)) return -1; # Off the edge.
|
||||
return x;
|
||||
}
|
||||
|
||||
# Get y coordinate of the neighbor in a given a direction.
|
||||
function getNextY(y, dir) {
|
||||
if (dir == top) y = y - 1;
|
||||
if (dir == bottom) y = y + 1;
|
||||
if (!isGoodXY(1, y)) return -1; # Off the edge.
|
||||
return y;
|
||||
}
|
||||
|
||||
# Mark a cell as visited.
|
||||
function setVisited(x, y, cell) {
|
||||
cell = getCell(x, y);
|
||||
if (cell == -1) return;
|
||||
cell = substr(cell, 1, 4) "1"; # walls plus visited
|
||||
setCell(x, y, cell);
|
||||
}
|
||||
|
||||
# Get the visited state of a cell.
|
||||
function wasVisited(x, y, cell) {
|
||||
cell = getCell(x, y);
|
||||
if (cell == -1) return 1; # Off edges already visited.
|
||||
return substr(getCell(x,y), 5, 1);
|
||||
}
|
||||
|
||||
# Remove a cell's wall in a given direction.
|
||||
function rmWall(x, y, d, i, oldCell, newCell) {
|
||||
oldCell = getCell(x, y);
|
||||
if (oldCell == -1) return;
|
||||
newCell = "";
|
||||
for (i = 1; i <= 4; i++) { # Ugly as concat of two substrings and a constant?.
|
||||
newCell = newCell (i == d ? "0" : substr(oldCell, i, 1));
|
||||
}
|
||||
newCell = newCell wasVisited(x, y);
|
||||
setCell(x, y, newCell);
|
||||
}
|
||||
|
||||
# Determine if a cell has a wall in a given direction.
|
||||
function hasWall(x, y, d, cell) {
|
||||
cell = getCell(x, y);
|
||||
if (cell == -1) return 1; # Cells off edge always have all walls.
|
||||
return substr(getCell(x, y), d, 1);
|
||||
}
|
||||
|
||||
# Plunk a cell into the maze.
|
||||
function setCell(x, y, cell, idx) {
|
||||
if (!isGoodXY(x, y)) return;
|
||||
maze[x, y] = cell
|
||||
}
|
||||
|
||||
# Get a cell from the maze.
|
||||
function getCell(x, y, idx) {
|
||||
if (!isGoodXY(x, y)) return -1; # Bad cell marker.
|
||||
return maze[x, y];
|
||||
}
|
||||
|
||||
# Are the given coordinates in the maze?
|
||||
function isGoodXY(x, y) {
|
||||
if (x < 1 || x > width) return 0;
|
||||
if (y < 1 || y > height) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Build the empty maze.
|
||||
function resetMaze( x, y) {
|
||||
delete maze;
|
||||
for (y = 1; y <= height; y++) {
|
||||
for (x = 1; x <= width; x++) {
|
||||
maze[x, y] = "11110"; # walls (up, down, left, right) and visited state.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Random things properly scaled.
|
||||
|
||||
function getRandX() {
|
||||
return 1 + int(rand() * width);
|
||||
}
|
||||
|
||||
function getRandY() {
|
||||
return 1 +int(rand() * height);
|
||||
}
|
||||
|
||||
function getRandDir() {
|
||||
return 1 + int(rand() * 4);
|
||||
}
|
||||
|
||||
function randomize() {
|
||||
"echo $RANDOM" | getline t;
|
||||
srand(t);
|
||||
}
|
||||
27
Task/Maze-generation/Ada/maze-generation-1.ada
Normal file
27
Task/Maze-generation/Ada/maze-generation-1.ada
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
generic
|
||||
Height : Positive;
|
||||
Width : Positive;
|
||||
package Mazes is
|
||||
|
||||
type Maze_Grid is private;
|
||||
|
||||
procedure Initialize (Maze : in out Maze_Grid);
|
||||
|
||||
procedure Put (Item : Maze_Grid);
|
||||
|
||||
private
|
||||
|
||||
type Directions is (North, South, West, East);
|
||||
|
||||
type Cell_Walls is array (Directions) of Boolean;
|
||||
type Cells is record
|
||||
Walls : Cell_Walls := (others => True);
|
||||
Visited : Boolean := False;
|
||||
end record;
|
||||
|
||||
subtype Height_Type is Positive range 1 .. Height;
|
||||
subtype Width_Type is Positive range 1 .. Width;
|
||||
|
||||
type Maze_Grid is array (Height_Type, Width_Type) of Cells;
|
||||
|
||||
end Mazes;
|
||||
217
Task/Maze-generation/Ada/maze-generation-2.ada
Normal file
217
Task/Maze-generation/Ada/maze-generation-2.ada
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
with Ada.Numerics.Discrete_Random;
|
||||
with Ada.Text_IO;
|
||||
|
||||
package body Mazes is
|
||||
package RNG is new Ada.Numerics.Discrete_Random (Positive);
|
||||
package Random_Direction is new Ada.Numerics.Discrete_Random (Directions);
|
||||
|
||||
Generator : RNG.Generator;
|
||||
Dir_Generator : Random_Direction.Generator;
|
||||
|
||||
function "-" (Dir : Directions) return Directions;
|
||||
|
||||
procedure Depth_First_Algorithm
|
||||
(Maze : in out Maze_Grid;
|
||||
Row : Height_Type;
|
||||
Column : Width_Type);
|
||||
|
||||
function Has_Unvisited_Neighbours
|
||||
(Maze : Maze_Grid;
|
||||
Row : Height_Type;
|
||||
Column : Width_Type)
|
||||
return Boolean;
|
||||
|
||||
procedure Move
|
||||
(Row : in out Height_Type;
|
||||
Column : in out Width_Type;
|
||||
Direction : Directions;
|
||||
Valid_Move : out Boolean);
|
||||
|
||||
function "-" (Dir : Directions) return Directions is
|
||||
begin
|
||||
case Dir is
|
||||
when North =>
|
||||
return South;
|
||||
when South =>
|
||||
return North;
|
||||
when East =>
|
||||
return West;
|
||||
when West =>
|
||||
return East;
|
||||
end case;
|
||||
end "-";
|
||||
|
||||
procedure Depth_First_Algorithm
|
||||
(Maze : in out Maze_Grid;
|
||||
Row : Height_Type;
|
||||
Column : Width_Type)
|
||||
is
|
||||
Next_Row : Height_Type;
|
||||
Next_Column : Width_Type;
|
||||
Next_Direction : Directions;
|
||||
Valid_Direction : Boolean;
|
||||
begin
|
||||
-- mark as visited
|
||||
Maze (Row, Column).Visited := True;
|
||||
-- continue as long as there are unvisited neighbours left
|
||||
while Has_Unvisited_Neighbours (Maze, Row, Column) loop
|
||||
-- use random direction
|
||||
Next_Direction := Random_Direction.Random (Dir_Generator);
|
||||
Next_Row := Row;
|
||||
Next_Column := Column;
|
||||
Move (Next_Row, Next_Column, Next_Direction, Valid_Direction);
|
||||
if Valid_Direction then
|
||||
-- connect the two cells
|
||||
if not Maze (Next_Row, Next_Column).Visited then
|
||||
Maze (Row, Column).Walls (Next_Direction) :=
|
||||
False;
|
||||
Maze (Next_Row, Next_Column).Walls (-Next_Direction) :=
|
||||
False;
|
||||
Depth_First_Algorithm (Maze, Next_Row, Next_Column);
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
end Depth_First_Algorithm;
|
||||
|
||||
function Has_Unvisited_Neighbours
|
||||
(Maze : Maze_Grid;
|
||||
Row : Height_Type;
|
||||
Column : Width_Type)
|
||||
return Boolean
|
||||
is
|
||||
Neighbour_Row : Height_Type;
|
||||
Neighbour_Column : Width_Type;
|
||||
Is_Valid : Boolean;
|
||||
begin
|
||||
for Dir in Directions loop
|
||||
Neighbour_Row := Row;
|
||||
Neighbour_Column := Column;
|
||||
Move
|
||||
(Row => Neighbour_Row,
|
||||
Column => Neighbour_Column,
|
||||
Direction => Dir,
|
||||
Valid_Move => Is_Valid);
|
||||
if Is_Valid
|
||||
and then not Maze (Neighbour_Row, Neighbour_Column).Visited
|
||||
then
|
||||
return True;
|
||||
end if;
|
||||
end loop;
|
||||
return False;
|
||||
end Has_Unvisited_Neighbours;
|
||||
|
||||
procedure Initialize (Maze : in out Maze_Grid) is
|
||||
Row, Column : Positive;
|
||||
begin
|
||||
-- initialize random generators
|
||||
RNG.Reset (Generator);
|
||||
Random_Direction.Reset (Dir_Generator);
|
||||
-- choose starting cell
|
||||
Row := RNG.Random (Generator) mod Height + 1;
|
||||
Column := RNG.Random (Generator) mod Width + 1;
|
||||
Ada.Text_IO.Put_Line
|
||||
("Starting generation at " &
|
||||
Positive'Image (Row) &
|
||||
" x" &
|
||||
Positive'Image (Column));
|
||||
Depth_First_Algorithm (Maze, Row, Column);
|
||||
end Initialize;
|
||||
|
||||
procedure Move
|
||||
(Row : in out Height_Type;
|
||||
Column : in out Width_Type;
|
||||
Direction : Directions;
|
||||
Valid_Move : out Boolean)
|
||||
is
|
||||
begin
|
||||
Valid_Move := False;
|
||||
case Direction is
|
||||
when North =>
|
||||
if Row > Height_Type'First then
|
||||
Valid_Move := True;
|
||||
Row := Row - 1;
|
||||
end if;
|
||||
when East =>
|
||||
if Column < Width_Type'Last then
|
||||
Valid_Move := True;
|
||||
Column := Column + 1;
|
||||
end if;
|
||||
when West =>
|
||||
if Column > Width_Type'First then
|
||||
Valid_Move := True;
|
||||
Column := Column - 1;
|
||||
end if;
|
||||
when South =>
|
||||
if Row < Height_Type'Last then
|
||||
Valid_Move := True;
|
||||
Row := Row + 1;
|
||||
end if;
|
||||
end case;
|
||||
end Move;
|
||||
|
||||
procedure Put (Item : Maze_Grid) is
|
||||
begin
|
||||
for Row in Item'Range (1) loop
|
||||
if Row = Item'First (1) then
|
||||
for Col in Item'Range (2) loop
|
||||
if Col = Item'First (2) then
|
||||
Ada.Text_IO.Put ('+');
|
||||
end if;
|
||||
if Item (Row, Col).Walls (North) then
|
||||
Ada.Text_IO.Put ("---");
|
||||
else
|
||||
Ada.Text_IO.Put (" ");
|
||||
end if;
|
||||
Ada.Text_IO.Put ('+');
|
||||
end loop;
|
||||
Ada.Text_IO.New_Line;
|
||||
end if;
|
||||
for Col in Item'Range (2) loop
|
||||
if Col = Item'First (2) then
|
||||
if Item (Row, Col).Walls (West) then
|
||||
Ada.Text_IO.Put ('|');
|
||||
else
|
||||
Ada.Text_IO.Put (' ');
|
||||
end if;
|
||||
elsif Item (Row, Col).Walls (West)
|
||||
and then Item (Row, Col - 1).Walls (East)
|
||||
then
|
||||
Ada.Text_IO.Put ('|');
|
||||
elsif Item (Row, Col).Walls (West)
|
||||
or else Item (Row, Col - 1).Walls (East)
|
||||
then
|
||||
Ada.Text_IO.Put ('>');
|
||||
else
|
||||
Ada.Text_IO.Put (' ');
|
||||
end if;
|
||||
if Item (Row, Col).Visited then
|
||||
Ada.Text_IO.Put (" ");
|
||||
else
|
||||
Ada.Text_IO.Put ("???");
|
||||
end if;
|
||||
if Col = Item'Last (2) then
|
||||
if Item (Row, Col).Walls (East) then
|
||||
Ada.Text_IO.Put ('|');
|
||||
else
|
||||
Ada.Text_IO.Put (' ');
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
Ada.Text_IO.New_Line;
|
||||
for Col in Item'Range (2) loop
|
||||
--for Col in Item'Range (2) loop
|
||||
if Col = Item'First (2) then
|
||||
Ada.Text_IO.Put ('+');
|
||||
end if;
|
||||
if Item (Row, Col).Walls (South) then
|
||||
Ada.Text_IO.Put ("---");
|
||||
else
|
||||
Ada.Text_IO.Put (" ");
|
||||
end if;
|
||||
Ada.Text_IO.Put ('+');
|
||||
--end loop;
|
||||
end loop;
|
||||
Ada.Text_IO.New_Line;
|
||||
end loop;
|
||||
end Put;
|
||||
end Mazes;
|
||||
8
Task/Maze-generation/Ada/maze-generation-3.ada
Normal file
8
Task/Maze-generation/Ada/maze-generation-3.ada
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
with Mazes;
|
||||
procedure Main is
|
||||
package Small_Mazes is new Mazes (Height => 8, Width => 11);
|
||||
My_Maze : Small_Mazes.Maze_Grid;
|
||||
begin
|
||||
Small_Mazes.Initialize (My_Maze);
|
||||
Small_Mazes.Put (My_Maze);
|
||||
end Main;
|
||||
110
Task/Maze-generation/Aime/maze-generation.aime
Normal file
110
Task/Maze-generation/Aime/maze-generation.aime
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
void
|
||||
grid_maze(data b, integer N)
|
||||
{
|
||||
data d;
|
||||
integer i, j;
|
||||
|
||||
j = N;
|
||||
while (j) {
|
||||
b_suffix(d, "+---");
|
||||
j -= 1;
|
||||
}
|
||||
{
|
||||
b_suffix(d, "+\n");
|
||||
}
|
||||
|
||||
j = N;
|
||||
while (j) {
|
||||
b_suffix(d, "| * ");
|
||||
j -= 1;
|
||||
}
|
||||
{
|
||||
b_suffix(d, "|\n");
|
||||
}
|
||||
|
||||
i = N;
|
||||
while (i) {
|
||||
b_extend(b, d);
|
||||
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
b_size(d, N * 4 + 2);
|
||||
|
||||
{
|
||||
b_extend(b, d);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
walk_cell(data b, integer N, integer line_size, integer x, integer y,
|
||||
list x_offsets, list y_offsets)
|
||||
{
|
||||
integer i, r;
|
||||
|
||||
b_replace(b, y + x, ' ');
|
||||
|
||||
r = drand(3);
|
||||
|
||||
i = 0;
|
||||
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);
|
||||
|
||||
if (-1 < p && p < line_size
|
||||
&& -1 < q && q < line_size * (N * 2 + 1)) {
|
||||
if (b_text(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, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
walk_maze(data b, integer N)
|
||||
{
|
||||
integer line_size, x, y;
|
||||
list x_offsets, y_offsets;
|
||||
|
||||
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);
|
||||
|
||||
x = drand(N - 1) * 4 + 2;
|
||||
y = line_size * (drand(N - 1) * 2 + 1);
|
||||
|
||||
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);
|
||||
|
||||
o_text(b_string(b));
|
||||
|
||||
return 0;
|
||||
}
|
||||
65
Task/Maze-generation/AutoHotkey/maze-generation.ahk
Normal file
65
Task/Maze-generation/AutoHotkey/maze-generation.ahk
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
; Initially build the board
|
||||
Width := 11
|
||||
Height := 8
|
||||
Loop % height*2+1
|
||||
{
|
||||
Outer := A_Index
|
||||
Loop % Width
|
||||
maze .= Outer & 1 ? "+-" : "|0"
|
||||
maze .= (Outer & 1 ? "+" : "|") "`n"
|
||||
}
|
||||
StringTrimRight, maze, maze, 1 ; removes trailing newline
|
||||
Clipboard := Walk(maze)
|
||||
|
||||
Walk(S, x=0, y=0){
|
||||
If !x{ ; --Start at a random cell...
|
||||
StringReplace, junk, S, `n,,UseErrorLevel ; Calculate rows
|
||||
Random, y, 1, ErrorLevel//2
|
||||
Random, x, 1, InStr(S, "`n")//2-1 ; Calculate height
|
||||
}
|
||||
|
||||
; --Obtain a list of its neighbors...
|
||||
neighbors := x "," y+1 "`n" x "," y-1 "`n" x+1 "," y "`n" x-1 "," y
|
||||
; --Randomize the list...
|
||||
Sort neighbors, random
|
||||
|
||||
; --Then for each neighbor...
|
||||
Loop Parse, neighbors, `n
|
||||
{
|
||||
pC := InStr(A_LoopField, ","), x2 := SubStr(A_LoopField, 1, pC-1), y2 := SubStr(A_LoopField, pC+1)
|
||||
; If it has not been visited...
|
||||
If GetChar(S, 2*x2, 2*y2) = "0"{
|
||||
; Mark it as visited...
|
||||
S := ChangeChar(s, 2*x2, 2*y2, " ")
|
||||
; Remove the wall between this cell and the neighbor...
|
||||
S := ChangeChar(S, x+x2, y+y2, " ")
|
||||
; Then recurse with the neighbor as the current cell
|
||||
S := Walk(S, x2, y2)
|
||||
}
|
||||
}
|
||||
return S
|
||||
}
|
||||
|
||||
; Change a character in a string using x and y coordinates
|
||||
ChangeChar(s, x, y, c){
|
||||
Loop Parse, s, `n
|
||||
{
|
||||
If (A_Index = Y)
|
||||
Loop Parse, A_LoopField
|
||||
If (A_Index = x)
|
||||
out .= c
|
||||
Else out .= A_LoopField
|
||||
Else out .= A_LoopField
|
||||
out .= "`n"
|
||||
}
|
||||
StringTrimRight, out, out, 1
|
||||
return out
|
||||
}
|
||||
|
||||
; retrieve a character in a string using x and y coordinates
|
||||
GetChar(s, x, y, n=1){
|
||||
x*=n, y*=n
|
||||
Loop Parse, s, `n
|
||||
If (A_Index = Y)
|
||||
return SubStr(A_LoopField, x, 1)
|
||||
}
|
||||
42
Task/Maze-generation/BBC-BASIC/maze-generation.bbc
Normal file
42
Task/Maze-generation/BBC-BASIC/maze-generation.bbc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
MazeWidth% = 11
|
||||
MazeHeight% = 9
|
||||
MazeCell% = 50
|
||||
|
||||
VDU 23,22,MazeWidth%*MazeCell%/2+3;MazeHeight%*MazeCell%/2+3;8,16,16,128
|
||||
VDU 23,23,3;0;0;0; : REM Line thickness
|
||||
PROCgeneratemaze(Maze&(), MazeWidth%, MazeHeight%, MazeCell%)
|
||||
END
|
||||
|
||||
DEF PROCgeneratemaze(RETURN m&(), w%, h%, s%)
|
||||
LOCAL x%, y%
|
||||
DIM m&(w%, h%)
|
||||
FOR y% = 0 TO h%
|
||||
LINE 0,y%*s%,w%*s%,y%*s%
|
||||
NEXT
|
||||
FOR x% = 0 TO w%
|
||||
LINE x%*s%,0,x%*s%,h%*s%
|
||||
NEXT
|
||||
GCOL 15
|
||||
PROCcell(m&(), RND(w%)-1, y% = RND(h%)-1, w%, h%, s%)
|
||||
ENDPROC
|
||||
|
||||
DEF PROCcell(m&(), x%, y%, w%, h%, s%)
|
||||
LOCAL i%, p%, q%, r%
|
||||
m&(x%,y%) OR= &40 : REM Mark visited
|
||||
r% = RND(4)
|
||||
FOR i% = r% TO r%+3
|
||||
CASE i% MOD 4 OF
|
||||
WHEN 0: p% = x%-1 : q% = y%
|
||||
WHEN 1: p% = x%+1 : q% = y%
|
||||
WHEN 2: p% = x% : q% = y%-1
|
||||
WHEN 3: p% = x% : q% = y%+1
|
||||
ENDCASE
|
||||
IF p% >= 0 IF p% < w% IF q% >= 0 IF q% < h% IF m&(p%,q%) < &40 THEN
|
||||
IF p% > x% m&(p%,q%) OR= 1 : LINE p%*s%,y%*s%+4,p%*s%,(y%+1)*s%-4
|
||||
IF q% > y% m&(p%,q%) OR= 2 : LINE x%*s%+4,q%*s%,(x%+1)*s%-4,q%*s%
|
||||
IF x% > p% m&(x%,y%) OR= 1 : LINE x%*s%,y%*s%+4,x%*s%,(y%+1)*s%-4
|
||||
IF y% > q% m&(x%,y%) OR= 2 : LINE x%*s%+4,y%*s%,(x%+1)*s%-4,y%*s%
|
||||
PROCcell(m&(), p%, q%, w%, h%, s%)
|
||||
ENDIF
|
||||
NEXT
|
||||
ENDPROC
|
||||
146
Task/Maze-generation/C/maze-generation-1.c
Normal file
146
Task/Maze-generation/C/maze-generation-1.c
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#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;
|
||||
}
|
||||
184
Task/Maze-generation/C/maze-generation-2.c
Normal file
184
Task/Maze-generation/C/maze-generation-2.c
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
#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;
|
||||
}
|
||||
30
Task/Maze-generation/Common-Lisp/maze-generation-1.lisp
Normal file
30
Task/Maze-generation/Common-Lisp/maze-generation-1.lisp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
(defun shuffle (list) ;; Z not uniform
|
||||
(sort list '> :key (lambda(x) (random 1.0))))
|
||||
|
||||
(defun neighbors (x y maze)
|
||||
(remove-if-not
|
||||
(lambda (x-y) (and (< -1 (first x-y) (array-dimension maze 0))
|
||||
(< -1 (second x-y) (array-dimension maze 1))))
|
||||
`((,x ,(+ y 2)) (,(- x 2) ,y) (,x ,(- y 2)) (,(+ x 2) ,y))))
|
||||
|
||||
(defun remove-wall (maze x y &optional visited)
|
||||
(labels ((walk (maze x y)
|
||||
(push (list x y) visited)
|
||||
(loop for (u v) in (shuffle (neighbors x y maze))
|
||||
unless (member (list u v) visited :test 'equal)
|
||||
do (setf (aref maze u v) #\space
|
||||
(aref maze (/ (+ x u) 2) (/ (+ y v) 2)) #\space)
|
||||
(walk maze u v))))
|
||||
(setf (aref maze x y) #\space)
|
||||
(walk maze x y)))
|
||||
|
||||
(defun draw-maze (width height &key (block #\BOX_DRAWINGS_LIGHT_DIAGONAL_CROSS))
|
||||
(let ((maze (make-array (list (1+ (* 2 height)) (1+ (* 2 width)))
|
||||
:element-type 'character :initial-element block)))
|
||||
(remove-wall maze (1+ (* 2 (random height))) (1+ (* 2 (random width))))
|
||||
(loop for i below (array-dimension maze 0)
|
||||
do (fresh-line)
|
||||
(loop for j below (array-dimension maze 1)
|
||||
do (princ (aref maze i j))))))
|
||||
|
||||
(draw-maze 20 6)
|
||||
57
Task/Maze-generation/Common-Lisp/maze-generation-2.lisp
Normal file
57
Task/Maze-generation/Common-Lisp/maze-generation-2.lisp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
(setf *random-state* (make-random-state t))
|
||||
|
||||
(defun 2d-array (w h)
|
||||
(make-array (list h w) :initial-element 0))
|
||||
|
||||
(defmacro or-and (v a b c)
|
||||
`(if (or ,a (and ,b (= 1 ,c))) 0 ,v))
|
||||
|
||||
(defun make-maze (w h)
|
||||
(let ((vis (2d-array w h))
|
||||
(ver (2d-array w h))
|
||||
(hor (2d-array w h)))
|
||||
(labels
|
||||
((walk (y x)
|
||||
(setf (aref vis y x) 1)
|
||||
(loop
|
||||
(let (x2 y2)
|
||||
(loop for (dx dy) in '((-1 0) (1 0) (0 -1) (0 1))
|
||||
with cnt = 0 do
|
||||
(let ((xx (+ x dx))
|
||||
(yy (+ y dy)))
|
||||
(if (and (array-in-bounds-p vis yy xx)
|
||||
(zerop (aref vis yy xx))
|
||||
(zerop (random (incf cnt))))
|
||||
(setf x2 xx y2 yy))))
|
||||
(if (not x2) (return-from walk))
|
||||
(if (= x x2)
|
||||
(setf (aref hor (min y y2) x) 1)
|
||||
(setf (aref ver y (min x x2)) 1))
|
||||
(walk y2 x2))))
|
||||
|
||||
(show ()
|
||||
(let ((g " │││─┘┐┤─└┌├─┴┬┼"))
|
||||
(loop for i from 0 to h do
|
||||
(loop for j from 0 to w do
|
||||
(format t "~c~a"
|
||||
(char g
|
||||
(+ (or-and 1 (= i 0) (> j 0) (aref ver (1- i) (1- j)))
|
||||
(or-and 2 (= i h) (> j 0) (aref ver i (1- j)))
|
||||
(or-and 4 (= j 0) (> i 0) (aref hor (1- i) (1- j)))
|
||||
(or-and 8 (= j w) (> i 0) (aref hor (1- i) j ))))
|
||||
(if (and (< j w)
|
||||
(or (= i 0)
|
||||
(= 0 (aref hor (1- i) j))))
|
||||
"───" " ")))
|
||||
(terpri)
|
||||
(when (< i h)
|
||||
(loop for j from 0 below w do
|
||||
(format t (if (or (= j 0)
|
||||
(= 0 (aref ver i (1- j))))
|
||||
"│ " " ")))
|
||||
(format t "│~%"))))))
|
||||
|
||||
(walk (random h) (random w))
|
||||
(show))))
|
||||
|
||||
(make-maze 20 20)
|
||||
24
Task/Maze-generation/D/maze-generation.d
Normal file
24
Task/Maze-generation/D/maze-generation.d
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import std.stdio, std.algorithm, std.range, std.random;
|
||||
alias R = std.array.replicate;
|
||||
|
||||
void main() {
|
||||
enum int w = 14, h = 10;
|
||||
auto vis = new bool[][](h, w),
|
||||
hor = iota(h + 1).map!(_ => ["+---"].R(w)).array,
|
||||
ver = h.iota.map!(_ => ["| "].R(w) ~ "|").array;
|
||||
|
||||
void walk(in int x, in int y) /*nothrow*/ {
|
||||
vis[y][x] = true;
|
||||
static struct P { immutable uint x, y; } // Will wrap-around.
|
||||
auto d = [P(x-1, y), P(x, y+1), P(x+1, y), P(x, y-1)];
|
||||
foreach (p; d.randomCover(unpredictableSeed.Random)) {
|
||||
if (p.x >= w || p.y >= h || vis[p.y][p.x]) continue;
|
||||
if (p.x == x) hor[max(y, p.y)][x] = "+ ";
|
||||
if (p.y == y) ver[y][max(x, p.x)] = " ";
|
||||
walk(p.tupleof);
|
||||
}
|
||||
}
|
||||
walk(uniform(0, w), uniform(0, h));
|
||||
foreach (a, b; hor.zip(ver ~ []))
|
||||
join(a ~ ["+\n"] ~ b).writeln;
|
||||
}
|
||||
150
Task/Maze-generation/EGL/maze-generation.egl
Normal file
150
Task/Maze-generation/EGL/maze-generation.egl
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
program MazeGen
|
||||
|
||||
// First and last columns/rows are "dead" cells. Makes generating
|
||||
// a maze with border walls much easier. Therefore, a visible
|
||||
// 20x20 maze has a maze size of 22.
|
||||
mazeSize int = 22;
|
||||
|
||||
south boolean[][];
|
||||
west boolean[][];
|
||||
visited boolean[][];
|
||||
|
||||
function main()
|
||||
initMaze();
|
||||
generateMaze();
|
||||
drawMaze();
|
||||
end
|
||||
|
||||
private function initMaze()
|
||||
|
||||
visited = createBooleanArray(mazeSize, mazeSize, false);
|
||||
|
||||
// Initialize border cells as already visited
|
||||
for(col int from 1 to mazeSize)
|
||||
visited[col][1] = true;
|
||||
visited[col][mazeSize] = true;
|
||||
end
|
||||
for(row int from 1 to mazeSize)
|
||||
visited[1][row] = true;
|
||||
visited[mazeSize][row] = true;
|
||||
end
|
||||
|
||||
// Initialize all walls as present
|
||||
south = createBooleanArray(mazeSize, mazeSize, true);
|
||||
west = createBooleanArray(mazeSize, mazeSize, true);
|
||||
|
||||
end
|
||||
|
||||
private function createBooleanArray(col int in, row int in, initialState boolean in) returns(boolean[][])
|
||||
|
||||
newArray boolean[][] = new boolean[0][0];
|
||||
|
||||
for(i int from 1 to col)
|
||||
innerArray boolean[] = new boolean[0];
|
||||
for(j int from 1 to row)
|
||||
innerArray.appendElement(initialState);
|
||||
end
|
||||
newArray.appendElement(innerArray);
|
||||
end
|
||||
|
||||
return(newArray);
|
||||
|
||||
end
|
||||
|
||||
private function createIntegerArray(col int in, row int in, initialValue int in) returns(int[][])
|
||||
|
||||
newArray int[][] = new int[0][0];
|
||||
|
||||
for(i int from 1 to col)
|
||||
innerArray int[] = new int[0];
|
||||
for(j int from 1 to row)
|
||||
innerArray.appendElement(initialValue);
|
||||
end
|
||||
newArray.appendElement(innerArray);
|
||||
end
|
||||
|
||||
return(newArray);
|
||||
|
||||
end
|
||||
|
||||
private function generate(col int in, row int in)
|
||||
|
||||
// Mark cell as visited
|
||||
visited[col][row] = true;
|
||||
|
||||
// Keep going as long as there is an unvisited neighbor
|
||||
while(!visited[col][row + 1] || !visited[col + 1][row] ||
|
||||
!visited[col][row - 1] || !visited[col - 1][row])
|
||||
|
||||
while(true)
|
||||
r float = MathLib.random(); // Choose a random direction
|
||||
|
||||
case
|
||||
when(r < 0.25 && !visited[col][row + 1]) // Go south
|
||||
south[col][row] = false; // South wall down
|
||||
generate(col, row + 1);
|
||||
exit while;
|
||||
when(r >= 0.25 && r < 0.50 && !visited[col + 1][row]) // Go east
|
||||
west[col + 1][row] = false; // West wall of neighbor to the east down
|
||||
generate(col + 1, row);
|
||||
exit while;
|
||||
when(r >= 0.5 && r < 0.75 && !visited[col][row - 1]) // Go north
|
||||
south[col][row - 1] = false; // South wall of neighbor to the north down
|
||||
generate(col, row - 1);
|
||||
exit while;
|
||||
when(r >= 0.75 && r < 1.00 && !visited[col - 1][row]) // Go west
|
||||
west[col][row] = false; // West wall down
|
||||
generate(col - 1, row);
|
||||
exit while;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private function generateMaze()
|
||||
|
||||
// Pick random start position (within the visible maze space)
|
||||
randomStartCol int = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
|
||||
randomStartRow int = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
|
||||
|
||||
generate(randomStartCol, randomStartRow);
|
||||
|
||||
end
|
||||
|
||||
private function drawMaze()
|
||||
|
||||
line string;
|
||||
|
||||
// Iterate over wall arrays (skipping dead border cells as required).
|
||||
// Construct a line at a time and output to console.
|
||||
for(row int from 1 to mazeSize - 1)
|
||||
|
||||
if(row > 1)
|
||||
line = "";
|
||||
for(col int from 2 to mazeSize)
|
||||
if(west[col][row])
|
||||
line ::= "| ";
|
||||
else
|
||||
line ::= " ";
|
||||
end
|
||||
end
|
||||
Syslib.writeStdout(line);
|
||||
end
|
||||
|
||||
line = "";
|
||||
for(col int from 2 to mazeSize - 1)
|
||||
if(south[col][row])
|
||||
line ::= "+---";
|
||||
else
|
||||
line ::= "+ ";
|
||||
end
|
||||
end
|
||||
line ::= "+";
|
||||
SysLib.writeStdout(line);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
119
Task/Maze-generation/Go/maze-generation.go
Normal file
119
Task/Maze-generation/Go/maze-generation.go
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type maze struct {
|
||||
c []byte // cell contents
|
||||
h []byte // horizontal walls above cells
|
||||
v []byte // vertical walls to the left of cells
|
||||
c2 [][]byte // cells by row
|
||||
h2 [][]byte // horizontal walls by row (ignore first row)
|
||||
v2 [][]byte // vertical walls by row (ignore first of each column)
|
||||
}
|
||||
|
||||
func newMaze(rows, cols int) *maze {
|
||||
c := make([]byte, rows*cols) // all cells
|
||||
h := bytes.Repeat([]byte{'-'}, rows*cols) // all horizontal walls
|
||||
v := bytes.Repeat([]byte{'|'}, rows*cols) // all vertical walls
|
||||
c2 := make([][]byte, rows) // cells by row
|
||||
h2 := make([][]byte, rows) // horizontal walls by row
|
||||
v2 := make([][]byte, rows) // vertical walls by row
|
||||
for i := range h2 {
|
||||
c2[i] = c[i*cols : (i+1)*cols]
|
||||
h2[i] = h[i*cols : (i+1)*cols]
|
||||
v2[i] = v[i*cols : (i+1)*cols]
|
||||
}
|
||||
return &maze{c, h, v, c2, h2, v2}
|
||||
}
|
||||
|
||||
func (m *maze) String() string {
|
||||
hWall := []byte("+---")
|
||||
hOpen := []byte("+ ")
|
||||
vWall := []byte("| ")
|
||||
vOpen := []byte(" ")
|
||||
rightCorner := []byte("+\n")
|
||||
rightWall := []byte("|\n")
|
||||
var b []byte
|
||||
// for all rows
|
||||
for r, hw := range m.h2 {
|
||||
// draw h walls
|
||||
for _, h := range hw {
|
||||
if h == '-' || r == 0 {
|
||||
b = append(b, hWall...)
|
||||
} else {
|
||||
b = append(b, hOpen...)
|
||||
}
|
||||
}
|
||||
b = append(b, rightCorner...)
|
||||
// draw v walls
|
||||
for c, vw := range m.v2[r] {
|
||||
if vw == '|' || c == 0 {
|
||||
b = append(b, vWall...)
|
||||
} else {
|
||||
b = append(b, vOpen...)
|
||||
}
|
||||
// draw cell contents
|
||||
if m.c2[r][c] != 0 {
|
||||
b[len(b)-2] = m.c2[r][c]
|
||||
}
|
||||
}
|
||||
b = append(b, rightWall...)
|
||||
}
|
||||
// draw bottom edge of maze
|
||||
for _ = range m.h2[0] {
|
||||
b = append(b, hWall...)
|
||||
}
|
||||
b = append(b, rightCorner...)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (m *maze) gen() {
|
||||
m.g2(rand.Intn(len(m.c2)), rand.Intn(len(m.c2[0])))
|
||||
}
|
||||
|
||||
const (
|
||||
up = iota
|
||||
dn
|
||||
rt
|
||||
lf
|
||||
)
|
||||
|
||||
func (m *maze) g2(r, c int) {
|
||||
m.c2[r][c] = ' '
|
||||
for _, dir := range rand.Perm(4) {
|
||||
switch dir {
|
||||
case up:
|
||||
if r > 0 && m.c2[r-1][c] == 0 {
|
||||
m.h2[r][c] = 0
|
||||
m.g2(r-1, c)
|
||||
}
|
||||
case lf:
|
||||
if c > 0 && m.c2[r][c-1] == 0 {
|
||||
m.v2[r][c] = 0
|
||||
m.g2(r, c-1)
|
||||
}
|
||||
case dn:
|
||||
if r < len(m.c2)-1 && m.c2[r+1][c] == 0 {
|
||||
m.h2[r+1][c] = 0
|
||||
m.g2(r+1, c)
|
||||
}
|
||||
case rt:
|
||||
if c < len(m.c2[0])-1 && m.c2[r][c+1] == 0 {
|
||||
m.v2[r][c+1] = 0
|
||||
m.g2(r, c+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
m := newMaze(4, 6)
|
||||
m.gen()
|
||||
fmt.Print(m)
|
||||
}
|
||||
67
Task/Maze-generation/Haskell/maze-generation.hs
Normal file
67
Task/Maze-generation/Haskell/maze-generation.hs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import Control.Monad
|
||||
import Control.Monad.ST
|
||||
import Data.Array
|
||||
import Data.Array.ST
|
||||
import Data.STRef
|
||||
import System.Random
|
||||
|
||||
rand :: Random a => (a, a) -> STRef s StdGen -> ST s a
|
||||
rand range gen = do
|
||||
(a, g) <- liftM (randomR range) $ readSTRef gen
|
||||
gen `writeSTRef` g
|
||||
return a
|
||||
|
||||
data Maze = Maze {rightWalls, belowWalls :: Array (Int, Int) Bool}
|
||||
|
||||
maze :: Int -> Int -> StdGen -> ST s Maze
|
||||
maze width height gen = do
|
||||
visited <- mazeArray False
|
||||
rWalls <- mazeArray True
|
||||
bWalls <- mazeArray True
|
||||
gen <- newSTRef gen
|
||||
liftM2 (,) (rand (0, maxX) gen) (rand (0, maxY) gen) >>=
|
||||
visit gen visited rWalls bWalls
|
||||
liftM2 Maze (freeze rWalls) (freeze bWalls)
|
||||
where visit gen visited rWalls bWalls here = do
|
||||
writeArray visited here True
|
||||
let ns = neighbors here
|
||||
i <- rand (0, length ns - 1) gen
|
||||
forM_ (ns !! i : take i ns ++ drop (i + 1) ns) $ \there -> do
|
||||
seen <- readArray visited there
|
||||
unless seen $ do
|
||||
removeWall here there
|
||||
visit gen visited rWalls bWalls there
|
||||
where removeWall (x1, y1) (x2, y2) = writeArray
|
||||
(if x1 == x2 then bWalls else rWalls)
|
||||
(min x1 x2, min y1 y2)
|
||||
False
|
||||
|
||||
neighbors (x, y) =
|
||||
(if x == 0 then [] else [(x - 1, y )]) ++
|
||||
(if x == maxX then [] else [(x + 1, y )]) ++
|
||||
(if y == 0 then [] else [(x, y - 1)]) ++
|
||||
(if y == maxY then [] else [(x, y + 1)])
|
||||
|
||||
maxX = width - 1
|
||||
maxY = height - 1
|
||||
|
||||
mazeArray = newArray ((0, 0), (maxX, maxY))
|
||||
:: Bool -> ST s (STArray s (Int, Int) Bool)
|
||||
|
||||
printMaze :: Maze -> IO ()
|
||||
printMaze (Maze rWalls bWalls) = do
|
||||
putStrLn $ '+' : (concat $ replicate (maxX + 1) "---+")
|
||||
forM_ [0 .. maxY] $ \y -> do
|
||||
putStr "|"
|
||||
forM_ [0 .. maxX] $ \x -> do
|
||||
putStr " "
|
||||
putStr $ if rWalls ! (x, y) then "|" else " "
|
||||
putStrLn ""
|
||||
forM_ [0 .. maxX] $ \x -> do
|
||||
putStr "+"
|
||||
putStr $ if bWalls ! (x, y) then "---" else " "
|
||||
putStrLn "+"
|
||||
where maxX = fst (snd $ bounds rWalls)
|
||||
maxY = snd (snd $ bounds rWalls)
|
||||
|
||||
main = getStdGen >>= stToIO . maze 11 8 >>= printMaze
|
||||
93
Task/Maze-generation/Icon/maze-generation.icon
Normal file
93
Task/Maze-generation/Icon/maze-generation.icon
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
link printf
|
||||
|
||||
procedure main(A) # generate rows x col maze
|
||||
/mh := \A[1] | 12 # or take defaults 12 x 16
|
||||
/mw := \A[2] | 16
|
||||
mz := DisplayMaze(GenerateMaze(mh,mw))
|
||||
WriteImage(mz.filename) # save file
|
||||
WAttrib(mz.window,"canvas=normal") # show maze in hidden window
|
||||
until Event() == &lpress # wait for left mouse press
|
||||
close(mz.window)
|
||||
end
|
||||
|
||||
$define FINISH 64 # exit
|
||||
$define START 32 # entrance
|
||||
$define PATH 128
|
||||
$define SEEN 16 # bread crumbs for generator
|
||||
$define NORTH 8 # sides ...
|
||||
$define EAST 4
|
||||
$define SOUTH 2
|
||||
$define WEST 1
|
||||
$define EMPTY 0 # like new
|
||||
|
||||
procedure GenerateMaze(r,c) #: Depth First Maze Generation
|
||||
static maze,h,w,rd
|
||||
if /maze then { # BEGING - No maze yet
|
||||
/h := integer(1 < r) | runerr(r,205) # valid size 2x2 or better
|
||||
/w := integer(1 < c) | runerr(r,205)
|
||||
every !(maze := list(h)) := list(w,EMPTY) # shinny new empty maze
|
||||
start := [?h,?w,?4-1,START] # random [r,c] start & finish
|
||||
finish := [?h,?w,(start[3]+2)%4,FINISH] # w/ opposite side exponent
|
||||
every x := start | finish do {
|
||||
case x[3] := 2 ^ x[3] of { # get side from exponent and
|
||||
NORTH : x[1] := 1 # project r,c to selected edge
|
||||
EAST : x[2] := w
|
||||
SOUTH : x[1] := h
|
||||
WEST : x[2] := 1
|
||||
}
|
||||
maze[x[1],x[2]] +:= x[3] + x[4] # transcribe s/f to maze
|
||||
}
|
||||
rd := [NORTH, EAST, SOUTH, WEST] # initial list of directions
|
||||
GenerateMaze(start[1],start[2]) # recurse through maze
|
||||
return 1(.maze,maze := &null) # return maze, reset for next
|
||||
}
|
||||
else { # ----------------------- recursed to clear insize of maze
|
||||
if iand(maze[r,c],SEEN) = 0 then { # in bounds and not SEEN yet?
|
||||
maze[r,c] +:= SEEN # Mark current cell as visited
|
||||
every !rd :=: ?rd # randomize list of directions
|
||||
every d := !rd do
|
||||
case d of { # try all, succeed & clear wall
|
||||
NORTH : maze[r,c] +:= ( GenerateMaze(r-1,c), NORTH)
|
||||
EAST : maze[r,c] +:= ( GenerateMaze(r,c+1), EAST)
|
||||
SOUTH : maze[r,c] +:= ( GenerateMaze(r+1,c), SOUTH)
|
||||
WEST : maze[r,c] +:= ( GenerateMaze(r,c-1), WEST)
|
||||
}
|
||||
return # signal success to caller
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
$define CELL 20 # cell size in pixels
|
||||
$define BORDER 30 # border size in pixels
|
||||
|
||||
record mazeinfo(window,maze,filename) # keepers
|
||||
|
||||
procedure DisplayMaze(maze) #: show it off
|
||||
if CELL < 8 then runerr(205,CELL) # too small
|
||||
|
||||
wh := (ch := (mh := *maze ) * CELL) + 2 * BORDER # win, cell, maze height
|
||||
ww := (cw := (mw := *maze[1]) * CELL) + 2 * BORDER # win, cell, maze width
|
||||
|
||||
wparms := [ sprintf("Maze %dx%d",*maze,*maze[1]), # window parameters
|
||||
"g","bg=white","canvas=hidden",
|
||||
sprintf("size=%d,%d",ww,wh),
|
||||
sprintf("dx=%d",BORDER),
|
||||
sprintf("dy=%d",BORDER)]
|
||||
|
||||
&window := open!wparms | stop("Unable to open Window")
|
||||
|
||||
Fg("black") # Draw full grid
|
||||
every DrawLine(x := 0 to cw by CELL,0,x,ch+1) # . verticals
|
||||
every DrawLine(0,y := 0 to ch by CELL,cw+1,y) # . horizontals
|
||||
|
||||
Fg("white") # Set to erase lines
|
||||
every y := CELL*((r := 1 to mh)-1) & x := CELL*((c := 1 to mw)-1) do {
|
||||
WAttrib("dx="||x+BORDER,"dy="||y+BORDER) # position @ cell r,c
|
||||
if iand(maze[r,c],NORTH) > 0 then DrawLine(2,0,CELL-1,0)
|
||||
if iand(maze[r,c],EAST) > 0 then DrawLine(CELL,2,CELL,CELL-1)
|
||||
if iand(maze[r,c],SOUTH) > 0 then DrawLine(2,CELL,CELL-1,CELL)
|
||||
if iand(maze[r,c],WEST) > 0 then DrawLine(0,2,0,CELL-1)
|
||||
}
|
||||
|
||||
return mazeinfo(&window,maze,sprintf("maze-%dx%d-%d.gif",r,c,&now))
|
||||
end
|
||||
31
Task/Maze-generation/J/maze-generation-1.j
Normal file
31
Task/Maze-generation/J/maze-generation-1.j
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
maze=:4 :0
|
||||
assert.0<:n=.<:x*y
|
||||
horiz=. 0$~x,y-1
|
||||
verti=. 0$~(x-1),y
|
||||
path=.,:here=. ?x,y
|
||||
unvisited=.0 (<here+1)} 0,0,~|:0,0,~1$~y,x
|
||||
while.n do.
|
||||
neighbors=. here+"1 (,-)=0 1
|
||||
neighbors=. neighbors #~ (<"1 neighbors+1) {unvisited
|
||||
if.#neighbors do.
|
||||
n=.n-1
|
||||
next=. ({~ ?@#) neighbors
|
||||
unvisited=.0 (<next+1)} unvisited
|
||||
if.{.next=here
|
||||
do. horiz=.1 (<-:here+next-0 1)} horiz
|
||||
else. verti=. 1 (<-:here+next-1 0)} verti end.
|
||||
path=.path,here=.next
|
||||
else.
|
||||
here=.{:path
|
||||
path=.}:path
|
||||
end.
|
||||
end.
|
||||
horiz;verti
|
||||
)
|
||||
|
||||
display=:3 :0
|
||||
size=. >.&$&>/y
|
||||
text=. (}:1 3$~2*1+{:size)#"1":size$<' '
|
||||
'hdoor vdoor'=. 2 4&*&.>&.> (#&,{@;&i./@$)&.> y
|
||||
' ' (a:-.~0 1;0 2; 0 3;(2 1-~$text);(1 4&+&.> hdoor),,vdoor+&.>"0/2 1;2 2;2 3)} text
|
||||
)
|
||||
18
Task/Maze-generation/J/maze-generation-2.j
Normal file
18
Task/Maze-generation/J/maze-generation-2.j
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
display 8 maze 11
|
||||
+ +---+---+---+---+---+---+---+---+---+---+
|
||||
| | | | |
|
||||
+ + + + +---+ + +---+---+ + +
|
||||
| | | | | | | |
|
||||
+ +---+---+ + +---+---+---+ + + +
|
||||
| | | | | | |
|
||||
+---+ +---+ + + +---+ + +---+---+
|
||||
| | | | | | |
|
||||
+ + +---+---+ +---+ + +---+---+ +
|
||||
| | | | | | | | |
|
||||
+ +---+ + + + + +---+---+ + +
|
||||
| | | | |
|
||||
+ +---+---+---+---+---+---+---+ +---+ +
|
||||
| | | | | | | | |
|
||||
+ + + + + + + + +---+ + +
|
||||
| | | | |
|
||||
+---+---+---+---+---+---+---+---+---+---+---+
|
||||
93
Task/Maze-generation/Java/maze-generation.java
Normal file
93
Task/Maze-generation/Java/maze-generation.java
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
package org.rosettacode;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
|
||||
/*
|
||||
* recursive backtracking algorithm
|
||||
* shamelessly borrowed from the ruby at
|
||||
* http://weblog.jamisbuck.org/2010/12/27/maze-generation-recursive-backtracking
|
||||
*/
|
||||
public class MazeGenerator {
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int[][] maze;
|
||||
private static final Random rand = new Random();
|
||||
|
||||
public MazeGenerator(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
maze = new int[this.x][this.y];
|
||||
generateMaze(0, 0);
|
||||
}
|
||||
|
||||
public void display() {
|
||||
for (int i = 0; i < y; i++) {
|
||||
// draw the north edge
|
||||
for (int j = 0; j < x; j++) {
|
||||
System.out.print((maze[j][i] & 1) == 0 ? "+---" : "+ ");
|
||||
}
|
||||
System.out.println("+");
|
||||
// draw the west edge
|
||||
for (int j = 0; j < x; j++) {
|
||||
System.out.print((maze[j][i] & 8) == 0 ? "| " : " ");
|
||||
}
|
||||
System.out.println("|");
|
||||
}
|
||||
// draw the bottom line
|
||||
for (int j = 0; j < x; j++) {
|
||||
System.out.print("+---");
|
||||
}
|
||||
System.out.println("+");
|
||||
}
|
||||
|
||||
private void generateMaze(int cx, int cy) {
|
||||
DIR[] dirs = DIR.values();
|
||||
Collections.shuffle(Arrays.asList(dirs));
|
||||
for (DIR dir : dirs) {
|
||||
int nx = cx + dir.dx;
|
||||
int ny = cy + dir.dy;
|
||||
if (between(nx, x) && between(ny, y)
|
||||
&& (maze[nx][ny] == 0)) {
|
||||
maze[cx][cy] |= dir.bit;
|
||||
maze[nx][ny] |= dir.opposite.bit;
|
||||
generateMaze(nx, ny);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean between(int v, int upper) {
|
||||
return (v >= 0) && (v < upper);
|
||||
}
|
||||
|
||||
private enum DIR {
|
||||
N(1, 0, -1), S(2, 0, 1), E(4, 1, 0), W(8, -1, 0);
|
||||
private final int bit;
|
||||
private final int dx;
|
||||
private final int dy;
|
||||
private DIR opposite;
|
||||
|
||||
// use the static initializer to resolve forward references
|
||||
static {
|
||||
N.opposite = S;
|
||||
S.opposite = N;
|
||||
E.opposite = W;
|
||||
W.opposite = E;
|
||||
}
|
||||
|
||||
private DIR(int bit, int dx, int dy) {
|
||||
this.bit = bit;
|
||||
this.dx = dx;
|
||||
this.dy = dy;
|
||||
}
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
int x = args.length >= 1 ? (Integer.parseInt(args[0])) : 8;
|
||||
int y = args.length == 2 ? (Integer.parseInt(args[1])) : 8;
|
||||
MazeGenerator maze = new MazeGenerator(x, y);
|
||||
maze.display();
|
||||
}
|
||||
|
||||
}
|
||||
63
Task/Maze-generation/JavaScript/maze-generation-1.js
Normal file
63
Task/Maze-generation/JavaScript/maze-generation-1.js
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
function maze(x,y) {
|
||||
var n=x*y-1;
|
||||
if (n<0) {alert("illegal maze dimensions");return;}
|
||||
var horiz=[]; for (var j= 0; j<x+1; j++) horiz[j]= [];
|
||||
var verti=[]; for (var j= 0; j<y+1; j++) verti[j]= [];
|
||||
var here= [Math.floor(Math.random()*x), Math.floor(Math.random()*y)];
|
||||
var path= [here];
|
||||
var unvisited= [];
|
||||
for (var j= 0; j<x+2; j++) {
|
||||
unvisited[j]= [];
|
||||
for (var k= 0; k<y+1; k++)
|
||||
unvisited[j].push(j>0 && j<x+1 && k>0 && (j != here[0]+1 || k != here[1]+1));
|
||||
}
|
||||
while (0<n) {
|
||||
var potential= [[here[0]+1, here[1]], [here[0],here[1]+1],
|
||||
[here[0]-1, here[1]], [here[0],here[1]-1]];
|
||||
var neighbors= [];
|
||||
for (var j= 0; j < 4; j++)
|
||||
if (unvisited[potential[j][0]+1][potential[j][1]+1])
|
||||
neighbors.push(potential[j]);
|
||||
if (neighbors.length) {
|
||||
n= n-1;
|
||||
next= neighbors[Math.floor(Math.random()*neighbors.length)];
|
||||
unvisited[next[0]+1][next[1]+1]= false;
|
||||
if (next[0] == here[0])
|
||||
horiz[next[0]][(next[1]+here[1]-1)/2]= true;
|
||||
else
|
||||
verti[(next[0]+here[0]-1)/2][next[1]]= true;
|
||||
path.push(here= next);
|
||||
} else
|
||||
here= path.pop();
|
||||
}
|
||||
return ({x: x, y: y, horiz: horiz, verti: verti});
|
||||
}
|
||||
|
||||
function display(m) {
|
||||
var text= [];
|
||||
for (var j= 0; j<m.x*2+1; j++) {
|
||||
var line= [];
|
||||
if (0 == j%2)
|
||||
for (var k=0; k<m.y*4+1; k++)
|
||||
if (0 == k%4)
|
||||
line[k]= '+';
|
||||
else
|
||||
if (j>0 && m.verti[j/2-1][Math.floor(k/4)])
|
||||
line[k]= ' ';
|
||||
else
|
||||
line[k]= '-';
|
||||
else
|
||||
for (var k=0; k<m.y*4+1; k++)
|
||||
if (0 == k%4)
|
||||
if (k>0 && m.horiz[(j-1)/2][k/4-1])
|
||||
line[k]= ' ';
|
||||
else
|
||||
line[k]= '|';
|
||||
else
|
||||
line[k]= ' ';
|
||||
if (0 == j) line[1]= line[2]= line[3]= ' ';
|
||||
if (m.x*2-1 == j) line[4*m.y]= ' ';
|
||||
text.push(line.join('')+'\r\n');
|
||||
}
|
||||
return text.join('');
|
||||
}
|
||||
5
Task/Maze-generation/JavaScript/maze-generation-2.js
Normal file
5
Task/Maze-generation/JavaScript/maze-generation-2.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<html><head><title></title></head><body><pre id="out"></pre></body></html>
|
||||
<script type="text/javascript">
|
||||
/* ABOVE CODE GOES HERE */
|
||||
document.getElementById('out').innerHTML= display(maze(8,11));
|
||||
</script>
|
||||
2
Task/Maze-generation/JavaScript/maze-generation-3.js
Normal file
2
Task/Maze-generation/JavaScript/maze-generation-3.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
function step() {
|
||||
if (0<n) {
|
||||
5
Task/Maze-generation/JavaScript/maze-generation-4.js
Normal file
5
Task/Maze-generation/JavaScript/maze-generation-4.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
document.getElementById('out').innerHTML= display({x: x, y: y, horiz: horiz, verti: verti, here: here});
|
||||
setTimeout(step, 100);
|
||||
}
|
||||
}
|
||||
step();
|
||||
3
Task/Maze-generation/JavaScript/maze-generation-5.js
Normal file
3
Task/Maze-generation/JavaScript/maze-generation-5.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
if (m.here && m.here[0]*2+1 == j && m.here[1]*4+2 == k)
|
||||
line[k]= '#'
|
||||
else if (0 == k%4) {
|
||||
3
Task/Maze-generation/JavaScript/maze-generation-6.js
Normal file
3
Task/Maze-generation/JavaScript/maze-generation-6.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
here= next;
|
||||
if (1 < neighbors.length)
|
||||
path.push(here);
|
||||
115
Task/Maze-generation/JavaScript/maze-generation-7.js
Normal file
115
Task/Maze-generation/JavaScript/maze-generation-7.js
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<html><head><title>Maze maker</title>
|
||||
<style type="text/css">
|
||||
table { border-collapse: collapse }
|
||||
td { width: 1em; height: 1em; border: 1px solid }
|
||||
td.s { border-bottom: none }
|
||||
td.n { border-top: none }
|
||||
td.w { border-left: none }
|
||||
td.e { border-right: none }
|
||||
td.v { background: skyblue}
|
||||
</style>
|
||||
<script type="application/javascript">
|
||||
Node.prototype.add = function(tag, cnt, txt) {
|
||||
for (var i = 0; i < cnt; i++)
|
||||
this.appendChild(ce(tag, txt));
|
||||
}
|
||||
Node.prototype.ins = function(tag) {
|
||||
this.insertBefore(ce(tag), this.firstChild)
|
||||
}
|
||||
Node.prototype.kid = function(i) { return this.childNodes[i] }
|
||||
Node.prototype.cls = function(t) { this.className += ' ' + t }
|
||||
|
||||
NodeList.prototype.map = function(g) {
|
||||
for (var i = 0; i < this.length; i++) g(this[i]);
|
||||
}
|
||||
|
||||
function ce(tag, txt) {
|
||||
var x = document.createElement(tag);
|
||||
if (txt !== undefined) x.innerHTML = txt;
|
||||
return x
|
||||
}
|
||||
|
||||
function gid(e) { return document.getElementById(e) }
|
||||
function irand(x) { return Math.floor(Math.random() * x) }
|
||||
|
||||
function make_maze() {
|
||||
var w = parseInt(gid('rows').value || 8, 10);
|
||||
var h = parseInt(gid('cols').value || 8, 10);
|
||||
var tbl = gid('maze');
|
||||
tbl.innerHTML = '';
|
||||
tbl.add('tr', h);
|
||||
tbl.childNodes.map(function(x) {
|
||||
x.add('th', 1);
|
||||
x.add('td', w, '*');
|
||||
x.add('th', 1)});
|
||||
tbl.ins('tr');
|
||||
tbl.add('tr', 1);
|
||||
tbl.firstChild.add('th', w + 2);
|
||||
tbl.lastChild.add('th', w + 2);
|
||||
for (var i = 1; i <= h; i++) {
|
||||
for (var j = 1; j <= w; j++) {
|
||||
tbl.kid(i).kid(j).neighbors = [
|
||||
tbl.kid(i + 1).kid(j),
|
||||
tbl.kid(i).kid(j + 1),
|
||||
tbl.kid(i).kid(j - 1),
|
||||
tbl.kid(i - 1).kid(j)
|
||||
];
|
||||
}
|
||||
}
|
||||
walk(tbl.kid(irand(h) + 1).kid(irand(w) + 1));
|
||||
gid('solve').style.display='inline';
|
||||
}
|
||||
|
||||
function shuffle(x) {
|
||||
for (var i = 3; i > 0; i--) {
|
||||
j = irand(i + 1);
|
||||
if (j == i) continue;
|
||||
var t = x[j]; x[j] = x[i]; x[i] = t;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
var dirs = ['s', 'e', 'w', 'n'];
|
||||
function walk(c) {
|
||||
c.innerHTML = ' ';
|
||||
var idx = shuffle([0, 1, 2, 3]);
|
||||
for (var j = 0; j < 4; j++) {
|
||||
var i = idx[j];
|
||||
var x = c.neighbors[i];
|
||||
if (x.textContent != '*') continue;
|
||||
c.cls(dirs[i]), x.cls(dirs[3 - i]);
|
||||
walk(x);
|
||||
}
|
||||
}
|
||||
|
||||
function solve(c, t) {
|
||||
if (c === undefined) {
|
||||
c = gid('maze').kid(1).kid(1);
|
||||
c.cls('v');
|
||||
}
|
||||
if (t === undefined)
|
||||
t = gid('maze') .lastChild.previousSibling
|
||||
.lastChild.previousSibling;
|
||||
|
||||
if (c === t) return 1;
|
||||
c.vis = 1;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var x = c.neighbors[i];
|
||||
if (x.tagName.toLowerCase() == 'th') continue;
|
||||
if (x.vis || !c.className.match(dirs[i]) || !solve(x, t))
|
||||
continue;
|
||||
|
||||
x.cls('v');
|
||||
return 1;
|
||||
}
|
||||
c.vis = null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
</script></head>
|
||||
<body><form><fieldset>
|
||||
<label>rows </label><input id='rows' size="3"/>
|
||||
<label>colums </label><input id='cols' size="3"/>
|
||||
<a href="javascript:make_maze()">Generate</a>
|
||||
<a id='solve' style='display:none' href='javascript:solve(); void(0)'>Solve</a>
|
||||
</fieldset></form><table id='maze'/></body></html>
|
||||
53
Task/Maze-generation/MATLAB/maze-generation.m
Normal file
53
Task/Maze-generation/MATLAB/maze-generation.m
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
function M = makeMaze(n)
|
||||
showProgress = false;
|
||||
|
||||
colormap([1,1,1;1,1,1;0,0,0]);
|
||||
set(gcf,'color','w');
|
||||
|
||||
NoWALL = 0;
|
||||
WALL = 2;
|
||||
NotVISITED = -1;
|
||||
VISITED = -2;
|
||||
|
||||
m = 2*n+3;
|
||||
M = NotVISITED(ones(m));
|
||||
offsets = [-1, m, 1, -m];
|
||||
|
||||
M([1 2:2:end end],:) = WALL;
|
||||
M(:,[1 2:2:end end]) = WALL;
|
||||
|
||||
currentCell = sub2ind(size(M),3,3);
|
||||
M(currentCell) = VISITED;
|
||||
|
||||
S = currentCell;
|
||||
|
||||
while (~isempty(S))
|
||||
moves = currentCell + 2*offsets;
|
||||
unvistedNeigbors = find(M(moves)==NotVISITED);
|
||||
|
||||
if (~isempty(unvistedNeigbors))
|
||||
next = unvistedNeigbors(randi(length(unvistedNeigbors),1));
|
||||
M(currentCell + offsets(next)) = NoWALL;
|
||||
|
||||
newCell = currentCell + 2*offsets(next);
|
||||
if (any(M(newCell+2*offsets)==NotVISITED))
|
||||
S = [S newCell];
|
||||
end
|
||||
|
||||
currentCell = newCell;
|
||||
M(currentCell) = VISITED;
|
||||
else
|
||||
currentCell = S(1);
|
||||
S = S(2:end);
|
||||
end
|
||||
|
||||
if (showProgress)
|
||||
image(M-VISITED);
|
||||
axis equal off;
|
||||
drawnow;
|
||||
pause(.01);
|
||||
end
|
||||
end
|
||||
|
||||
image(M-VISITED);
|
||||
axis equal off;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
MazeGraphics[m_, n_] :=
|
||||
Block[{$RecursionLimit = Infinity,
|
||||
unvisited = Tuples[Range /@ {m, n}], maze},
|
||||
maze = Graphics[{Line[{{#, # - {0, 1}}, {#, # - {1, 0}}}] & /@
|
||||
unvisited,
|
||||
Line[{{0, n}, {0, 0}, {m, 0}}]}]; {unvisited =
|
||||
DeleteCases[unvisited, #];
|
||||
Do[If[MemberQ[unvisited, neighbor],
|
||||
maze = DeleteCases[
|
||||
maze, {#,
|
||||
neighbor - {1, 1}} | {neighbor, # - {1, 1}}, {5}]; #0@
|
||||
neighbor], {neighbor,
|
||||
RandomSample@{# + {0, 1}, # - {0, 1}, # + {1, 0}, # - {1,
|
||||
0}}}]} &@RandomChoice@unvisited; maze];
|
||||
maze = MazeGraphics[21, 13]
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
MazeGraph[m_, n_] :=
|
||||
Block[{$RecursionLimit = Infinity, grid = GridGraph[{m, n}],
|
||||
visited = {}},
|
||||
Graph[Range[m n], Reap[{AppendTo[visited, #];
|
||||
Do[
|
||||
If[FreeQ[visited, neighbor],
|
||||
Sow[# <-> neighbor]; #0@neighbor], {neighbor,
|
||||
RandomSample@AdjacencyList[grid, #]}]} &@
|
||||
RandomChoice@VertexList@grid][[2, 1]],
|
||||
GraphLayout -> {"GridEmbedding", "Dimension" -> {m, n}}]];
|
||||
maze = MazeGraph[13, 21]
|
||||
36
Task/Maze-generation/Perl/maze-generation.pl
Normal file
36
Task/Maze-generation/Perl/maze-generation.pl
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use List::Util 'max';
|
||||
|
||||
my ($w, $h) = @ARGV;
|
||||
$w ||= 26;
|
||||
$h ||= 127;
|
||||
my $avail = $w * $h;
|
||||
|
||||
# cell is padded by sentinel col and row, so I don't check array bounds
|
||||
my @cell = (map([(('1') x $w), 0], 1 .. $h), [('') x ($w + 1)]);
|
||||
my @ver = map([("| ") x $w], 1 .. $h);
|
||||
my @hor = map([("+--") x $w], 0 .. $h);
|
||||
|
||||
sub walk {
|
||||
my ($x, $y) = @_;
|
||||
$cell[$y][$x] = '';
|
||||
$avail-- or return; # no more bottles, er, cells
|
||||
|
||||
my @d = ([-1, 0], [0, 1], [1, 0], [0, -1]);
|
||||
while (@d) {
|
||||
my $i = splice @d, int(rand @d), 1;
|
||||
my ($x1, $y1) = ($x + $i->[0], $y + $i->[1]);
|
||||
|
||||
$cell[$y1][$x1] or next;
|
||||
|
||||
if ($x == $x1) { $hor[ max($y1, $y) ][$x] = '+ ' }
|
||||
if ($y == $y1) { $ver[$y][ max($x1, $x) ] = ' ' }
|
||||
walk($x1, $y1);
|
||||
}
|
||||
}
|
||||
|
||||
walk(int rand $w, int rand $h); # generate
|
||||
|
||||
for (0 .. $h) { # display
|
||||
print @{$hor[$_]}, "+\n";
|
||||
print @{$ver[$_]}, "|\n" if $_ < $h;
|
||||
}
|
||||
30
Task/Maze-generation/PicoLisp/maze-generation.l
Normal file
30
Task/Maze-generation/PicoLisp/maze-generation.l
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
(load "@lib/simul.l")
|
||||
|
||||
(de maze (DX DY)
|
||||
(let Maze (grid DX DY)
|
||||
(let Fld (get Maze (rand 1 DX) (rand 1 DY))
|
||||
(recur (Fld)
|
||||
(for Dir (shuffle '((west . east) (east . west) (south . north) (north . south)))
|
||||
(with ((car Dir) Fld)
|
||||
(unless (or (: west) (: east) (: south) (: north))
|
||||
(put Fld (car Dir) This)
|
||||
(put This (cdr Dir) Fld)
|
||||
(recurse This) ) ) ) ) )
|
||||
(for (X . Col) Maze
|
||||
(for (Y . This) Col
|
||||
(set This
|
||||
(cons
|
||||
(cons
|
||||
(: west)
|
||||
(or
|
||||
(: east)
|
||||
(and (= Y 1) (= X DX)) ) )
|
||||
(cons
|
||||
(: south)
|
||||
(or
|
||||
(: north)
|
||||
(and (= X 1) (= Y DY)) ) ) ) ) ) )
|
||||
Maze ) )
|
||||
|
||||
(de display (Maze)
|
||||
(disp Maze 0 '((This) " ")) )
|
||||
89
Task/Maze-generation/Prolog/maze-generation.pro
Normal file
89
Task/Maze-generation/Prolog/maze-generation.pro
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
:- dynamic cell/2.
|
||||
|
||||
maze(Lig,Col) :-
|
||||
retractall(cell(_,_)),
|
||||
|
||||
new(D, window('Maze')),
|
||||
|
||||
% creation of the grid
|
||||
forall(between(0,Lig, I),
|
||||
(XL is 50, YL is I * 30 + 50,
|
||||
XR is Col * 30 + 50,
|
||||
new(L, line(XL, YL, XR, YL)),
|
||||
send(D, display, L))),
|
||||
|
||||
forall(between(0,Col, I),
|
||||
(XT is 50 + I * 30, YT is 50,
|
||||
YB is Lig * 30 + 50,
|
||||
new(L, line(XT, YT, XT, YB)),
|
||||
send(D, display, L))),
|
||||
|
||||
SX is Col * 30 + 100,
|
||||
SY is Lig * 30 + 100,
|
||||
send(D, size, new(_, size(SX, SY))),
|
||||
|
||||
% choosing a first cell
|
||||
L0 is random(Lig),
|
||||
C0 is random(Col),
|
||||
assert(cell(L0, C0)),
|
||||
\+search(D, Lig, Col, L0, C0),
|
||||
send(D, open).
|
||||
|
||||
search(D, Lig, Col, L, C) :-
|
||||
Dir is random(4),
|
||||
nextcell(Dir, Lig, Col, L, C, L1, C1),
|
||||
assert(cell(L1,C1)),
|
||||
assert(cur(L1,C1)),
|
||||
erase_line(D, L, C, L1, C1),
|
||||
search(D, Lig, Col, L1, C1).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
erase_line(D, L, C, L, C1) :-
|
||||
( C < C1 -> C2 = C1; C2 = C),
|
||||
XT is C2 * 30 + 50,
|
||||
YT is L * 30 + 51, YR is (L+1) * 30 + 50,
|
||||
new(Line, line(XT, YT, XT, YR)),
|
||||
send(Line, colour, white),
|
||||
send(D, display, Line).
|
||||
|
||||
erase_line(D, L, C, L1, C) :-
|
||||
XT is 51 + C * 30, XR is 50 + (C + 1) * 30,
|
||||
( L < L1 -> L2 is L1; L2 is L),
|
||||
YT is L2 * 30 + 50,
|
||||
new(Line, line(XT, YT, XR, YT)),
|
||||
send(Line, colour, white),
|
||||
send(D, display, Line).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
nextcell(Dir, Lig, Col, L, C, L1, C1) :-
|
||||
next(Dir, Lig, Col, L, C, L1, C1);
|
||||
( Dir1 is (Dir+3) mod 4,
|
||||
next(Dir1, Lig, Col, L, C, L1, C1));
|
||||
( Dir2 is (Dir+1) mod 4,
|
||||
next(Dir2, Lig, Col, L, C, L1, C1));
|
||||
( Dir3 is (Dir+2) mod 4,
|
||||
next(Dir3, Lig, Col, L, C, L1, C1)).
|
||||
|
||||
% 0 => northward
|
||||
next(0, _Lig, _Col, L, C, L1, C) :-
|
||||
L > 0,
|
||||
L1 is L - 1,
|
||||
\+cell(L1, C).
|
||||
|
||||
% 1 => rightward
|
||||
next(1, _Lig, Col, L, C, L, C1) :-
|
||||
C < Col - 1,
|
||||
C1 is C + 1,
|
||||
\+cell(L, C1).
|
||||
|
||||
% 2 => southward
|
||||
next(2, Lig, _Col, L, C, L1, C) :-
|
||||
L < Lig - 1,
|
||||
L1 is L + 1,
|
||||
\+cell(L1, C).
|
||||
|
||||
% 3 => leftward
|
||||
next(2, _Lig, _Col, L, C, L, C1) :-
|
||||
C > 0,
|
||||
C1 is C - 1,
|
||||
\+cell(L, C1).
|
||||
23
Task/Maze-generation/Python/maze-generation.py
Normal file
23
Task/Maze-generation/Python/maze-generation.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from random import shuffle, randrange
|
||||
|
||||
def make_maze(w = 16, h = 8):
|
||||
vis = [[0] * w + [1] for _ in range(h)] + [[1] * (w + 1)]
|
||||
ver = [["| "] * w + ['|'] for _ in range(h)] + [[]]
|
||||
hor = [["+--"] * w + ['+'] for _ in range(h + 1)]
|
||||
|
||||
def walk(x, y):
|
||||
vis[y][x] = 1
|
||||
|
||||
d = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)]
|
||||
shuffle(d)
|
||||
for (xx, yy) in d:
|
||||
if vis[yy][xx]: continue
|
||||
if xx == x: hor[max(y, yy)][x] = "+ "
|
||||
if yy == y: ver[y][max(x, xx)] = " "
|
||||
walk(xx, yy)
|
||||
|
||||
walk(randrange(w), randrange(h))
|
||||
for (a, b) in zip(hor, ver):
|
||||
print(''.join(a + ['\n'] + b))
|
||||
|
||||
make_maze()
|
||||
60
Task/Maze-generation/REXX/maze-generation.rexx
Normal file
60
Task/Maze-generation/REXX/maze-generation.rexx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*REXX program to generate and display a (rectangular) maze. */
|
||||
height=0; @.=0 /*default for all cells visited.*/
|
||||
parse arg rows cols seed . /*allow user to specify maze size*/
|
||||
if rows='' | rows==',' then rows=19 /*No rows given? Use the default*/
|
||||
if cols='' | cols==',' then cols=19 /*No cols given? Use the default*/
|
||||
if seed\=='' then call random ,,seed /*use a seed for repeatability. */
|
||||
call buildRow '┌'copies('─┬',cols-1)'─┐'
|
||||
/*(below) build maze's grid & pop*/
|
||||
do r=1 for rows; _=; __=; hp= '|'; hj='├'
|
||||
do c=1 for cols; _= _||hp'1'; __=__||hj'─'; hj='┼'; hp='│'
|
||||
end /*c*/
|
||||
call buildRow _'│'
|
||||
if r\==rows then call buildRow __'┤'
|
||||
end /*r*/
|
||||
|
||||
call buildRow '└'copies('─┴',cols-1)'─┘'
|
||||
r!=random(1,rows)*2; c!=random(1,cols)*2; @.r!.c!=0 /*choose 1st cell*/
|
||||
|
||||
do forever; n=hood(r!,c!); if n==0 then if \fcell() then leave
|
||||
call ?; @._r._c=0
|
||||
ro=r!; co=c!; r!=_r; c!=_c
|
||||
?.zr=?.zr%2; ?.zc=?.zc%2
|
||||
rw=ro+?.zr; cw=co+?.zc
|
||||
@.rw.cw='·'
|
||||
end /*forever*/
|
||||
|
||||
do r=1 for height; _= /*display the maze. */
|
||||
do c=1 for cols*2 + 1; _=_ || @.r.c; end
|
||||
if r//2 then _=translate(_,'-','fa'x) /*translate to minus*/
|
||||
_=translate(_,'\','fa'x) /*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 screen.*/
|
||||
end /*r*/
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*──────────────────────────────────FCELL subroutine────────────────────*/
|
||||
fcell: do r=1 for rows; r2=r+r
|
||||
do c=1 for cols; c2=c+c
|
||||
if hood(r2,c2)==1 then do; r!=r2; c!=c2; @.r!.c!=0; return 1
|
||||
end
|
||||
end /*c*/
|
||||
end /*r*/
|
||||
return 0
|
||||
/*──────────────────────────────────@ subroutine────────────────────────*/
|
||||
@: parse arg _r,_c; return @._r._c
|
||||
/*──────────────────────────────────? subroutine────────────────────────*/
|
||||
?: 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*/
|
||||
/*──────────────────────────────────HOOD subroutine─────────────────────*/
|
||||
hood: parse arg rh,ch; return @(rh+2,ch)+@(rh-2,ch)+@(rh,ch-2)+@(rh,ch+2)
|
||||
/*──────────────────────────────────BUILDROW subroutine─────────────────*/
|
||||
buildRow: parse arg z; height=height+1; width=length(z)
|
||||
do c=1 for width; @.height.c=substr(z,c,1); end; return
|
||||
119
Task/Maze-generation/Ruby/maze-generation.rb
Normal file
119
Task/Maze-generation/Ruby/maze-generation.rb
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
class Maze
|
||||
DIRECTIONS = [ [1, 0], [-1, 0], [0, 1], [0, -1] ]
|
||||
|
||||
def initialize(width, height)
|
||||
@width = width
|
||||
@height = height
|
||||
@start_x = rand(width)
|
||||
@start_y = 0
|
||||
@end_x = rand(width)
|
||||
@end_y = height - 1
|
||||
|
||||
# Which walls do exist? Default to "true". Both arrays are
|
||||
# one element bigger than they need to be. For example, the
|
||||
# @vertical_walls[y][x] is true if there is a wall between
|
||||
# (x,y) and (x+1,y). The additional entry makes printing
|
||||
# easier.
|
||||
@vertical_walls = Array.new(height) { Array.new(width, true) }
|
||||
@horizontal_walls = Array.new(height) { Array.new(width, true) }
|
||||
# Path for the solved maze.
|
||||
@path = Array.new(height) { Array.new(width) }
|
||||
|
||||
# "Hack" to print the exit.
|
||||
@horizontal_walls[@end_y][@end_x] = false
|
||||
|
||||
reset_visiting_state
|
||||
|
||||
# Generate the maze.
|
||||
generate
|
||||
end
|
||||
|
||||
# Print a nice ASCII maze.
|
||||
def print
|
||||
# Special handling: print the top line.
|
||||
line = "+"
|
||||
for x in (0...@width)
|
||||
line.concat(x == @start_x ? " +" : "---+")
|
||||
end
|
||||
puts line
|
||||
|
||||
# For each cell, print the right and bottom wall, if it exists.
|
||||
for y in (0...@height)
|
||||
line = "|"
|
||||
for x in (0...@width)
|
||||
line.concat(@path[y][x] ? " o " : " ")
|
||||
line.concat(@vertical_walls[y][x] ? "|" : " ")
|
||||
end
|
||||
puts line
|
||||
|
||||
line = "+"
|
||||
for x in (0...@width)
|
||||
line.concat(@horizontal_walls[y][x] ? "---+" : " +")
|
||||
end
|
||||
puts line
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Reset the VISITED state of all cells.
|
||||
def reset_visiting_state
|
||||
@visited = Array.new(@height) { Array.new(@width) }
|
||||
end
|
||||
|
||||
# Check whether the given coordinate is within the valid range.
|
||||
def coordinate_valid?(x, y)
|
||||
(x >= 0) && (y >= 0) && (x < @width) && (y < @height)
|
||||
end
|
||||
|
||||
# Is the given coordinate valid and the cell not yet visited?
|
||||
def move_valid?(x, y)
|
||||
coordinate_valid?(x, y) && !@visited[y][x]
|
||||
end
|
||||
|
||||
# Generate the maze.
|
||||
def generate
|
||||
generate_visit_cell @start_x, @start_y
|
||||
reset_visiting_state
|
||||
end
|
||||
|
||||
# Depth-first maze generation.
|
||||
def generate_visit_cell(x, y)
|
||||
# Mark cell as visited.
|
||||
@visited[y][x] = true
|
||||
|
||||
# Randomly get coordinates of surrounding cells (may be outside
|
||||
# of the maze range, will be sorted out later).
|
||||
coordinates = []
|
||||
for dir in DIRECTIONS.shuffle
|
||||
coordinates << [ x + dir[0], y + dir[1] ]
|
||||
end
|
||||
|
||||
for new_x, new_y in coordinates
|
||||
next unless move_valid?(new_x, new_y)
|
||||
|
||||
# Recurse if it was possible to connect the current
|
||||
# and the the cell (this recursion is the "depth-first"
|
||||
# part).
|
||||
connect_cells(x, y, new_x, new_y)
|
||||
generate_visit_cell new_x, new_y
|
||||
end
|
||||
end
|
||||
|
||||
# Try to connect two cells. Returns whether it was valid to do so.
|
||||
def connect_cells(x1, y1, x2, y2)
|
||||
if x1 == x2
|
||||
# Cells must be above each other, remove a horizontal
|
||||
# wall.
|
||||
@horizontal_walls[ [y1, y2].min ][x1] = false
|
||||
else
|
||||
# Cells must be next to each other, remove a vertical
|
||||
# wall.
|
||||
@vertical_walls[y1][ [x1, x2].min ] = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Demonstration:
|
||||
maze = Maze.new 20, 10
|
||||
maze.print
|
||||
97
Task/Maze-generation/Tcl/maze-generation.tcl
Normal file
97
Task/Maze-generation/Tcl/maze-generation.tcl
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package require TclOO; # Or Tcl 8.6
|
||||
|
||||
# Helper to pick a random number
|
||||
proc rand n {expr {int(rand() * $n)}}
|
||||
# Helper to pick a random element of a list
|
||||
proc pick list {lindex $list [rand [llength $list]]}
|
||||
# Helper _function_ to index into a list of lists
|
||||
proc tcl::mathfunc::idx {v x y} {lindex $v $x $y}
|
||||
|
||||
oo::class create maze {
|
||||
variable x y horiz verti content
|
||||
constructor {width height} {
|
||||
set y $width
|
||||
set x $height
|
||||
|
||||
set n [expr {$x * $y - 1}]
|
||||
if {$n < 0} {error "illegal maze dimensions"}
|
||||
set horiz [set verti [lrepeat $x [lrepeat $y 0]]]
|
||||
# This matrix holds the output for the Maze Solving task; not used for generation
|
||||
set content [lrepeat $x [lrepeat $y " "]]
|
||||
set unvisited [lrepeat [expr {$x+2}] [lrepeat [expr {$y+2}] 0]]
|
||||
# Helper to write into a list of lists (with offsets)
|
||||
proc unvisited= {x y value} {
|
||||
upvar 1 unvisited u
|
||||
lset u [expr {$x+1}] [expr {$y+1}] $value
|
||||
}
|
||||
|
||||
lappend stack [set here [list [rand $x] [rand $y]]]
|
||||
for {set j 0} {$j < $x} {incr j} {
|
||||
for {set k 0} {$k < $y} {incr k} {
|
||||
unvisited= $j $k [expr {$here ne [list $j $k]}]
|
||||
}
|
||||
}
|
||||
|
||||
while {0 < $n} {
|
||||
lassign $here hx hy
|
||||
set neighbours {}
|
||||
foreach {dx dy} {1 0 0 1 -1 0 0 -1} {
|
||||
if {idx($unvisited, $hx+$dx+1, $hy+$dy+1)} {
|
||||
lappend neighbours [list [expr {$hx+$dx}] [expr {$hy+$dy}]]
|
||||
}
|
||||
}
|
||||
if {[llength $neighbours]} {
|
||||
lassign [set here [pick $neighbours]] nx ny
|
||||
unvisited= $nx $ny 0
|
||||
if {$nx == $hx} {
|
||||
lset horiz $nx [expr {min($ny, $hy)}] 1
|
||||
} else {
|
||||
lset verti [expr {min($nx, $hx)}] $ny 1
|
||||
}
|
||||
lappend stack $here
|
||||
incr n -1
|
||||
} else {
|
||||
set here [lindex $stack end]
|
||||
set stack [lrange $stack 0 end-1]
|
||||
}
|
||||
}
|
||||
|
||||
rename unvisited= {}
|
||||
}
|
||||
|
||||
# Maze displayer; takes a maze dictionary, returns a string
|
||||
method view {} {
|
||||
set text {}
|
||||
for {set j 0} {$j < $x*2+1} {incr j} {
|
||||
set line {}
|
||||
for {set k 0} {$k < $y*4+1} {incr k} {
|
||||
if {$j%2 && $k%4==2} {
|
||||
# At the centre of the cell, put the "content" of the cell
|
||||
append line [expr {idx($content, $j/2, $k/4)}]
|
||||
} elseif {$j%2 && ($k%4 || $k && idx($horiz, $j/2, $k/4-1))} {
|
||||
append line " "
|
||||
} elseif {$j%2} {
|
||||
append line "|"
|
||||
} elseif {0 == $k%4} {
|
||||
append line "+"
|
||||
} elseif {$j && idx($verti, $j/2-1, $k/4)} {
|
||||
append line " "
|
||||
} else {
|
||||
append line "-"
|
||||
}
|
||||
}
|
||||
if {!$j} {
|
||||
lappend text [string replace $line 1 3 " "]
|
||||
} elseif {$x*2-1 == $j} {
|
||||
lappend text [string replace $line end end " "]
|
||||
} else {
|
||||
lappend text $line
|
||||
}
|
||||
}
|
||||
return [join $text \n]
|
||||
}
|
||||
}
|
||||
|
||||
# Demonstration
|
||||
maze create m 11 8
|
||||
puts [m view]
|
||||
Loading…
Add table
Add a link
Reference in a new issue