langs a-z

This commit is contained in:
Ingy döt Net 2013-04-10 22:43:41 -07:00
parent db842d013d
commit d066446780
11389 changed files with 98361 additions and 1020 deletions

View file

@ -0,0 +1,52 @@
let seen = Hashtbl.create 7
let mark t = Hashtbl.add seen t true
let marked t = Hashtbl.mem seen t
let walls = Hashtbl.create 7
let ord a b = if a <= b then (a,b) else (b,a)
let join a b = Hashtbl.add walls (ord a b) true
let joined a b = Hashtbl.mem walls (ord a b)
let () =
let nx = int_of_string Sys.argv.(1) in
let ny = int_of_string Sys.argv.(2) in
let rec random_order = function
| [] -> []
| [a] -> [a]
| x -> let i = Random.int (List.length x) in
let rec del i = function
| [] -> failwith "del"
| h::t -> if i = 0 then t else h :: del (i-1) t in
(List.nth x i) :: random_order (del i x) in
let get_neighbours (x,y) =
let lim n k = (0 <= k) && (k < n) in
let bounds (x,y) = lim nx x && lim ny y in
List.filter bounds [(x-1,y);(x+1,y);(x,y-1);(x,y+1)] in
let rec visit cell =
mark cell;
let check k =
if not (marked k) then (join cell k; visit k) in
List.iter check (random_order (get_neighbours cell)) in
let print_maze () =
begin
for i = 1 to nx do print_string "+---";done; print_endline "+";
let line n j k l s t u =
for i = 0 to n do print_string (if joined (i,j) (i+k,j+l) then s else t) done;
print_endline u in
for j = 0 to ny-2 do
print_string "| ";
line (nx-2) j 1 0 " " "| " "|";
line (nx-1) j 0 1 "+ " "+---" "+";
done;
print_string "| ";
line (nx-2) (ny-1) 1 0 " " "| " "|";
for i = 1 to nx do print_string "+---";done; print_endline "+";
end in
Random.self_init();
visit (Random.int nx, Random.int ny);
print_maze ();

View file

@ -0,0 +1,87 @@
constant mapping = :OPEN(' '),
:N< >,
:E< >,
:NE< >,
:S< >,
:NS< >,
:ES< >,
:NES< >,
:W< >,
:NW< >,
:EW< >,
:NEW< >,
:SW< >,
:NSW< >,
:ESW< >,
:NESW< >,
:TODO< x >,
:TRIED< · >;
enum Code (mapping.map: *.key);
my @code = mapping.map: *.value;
enum Direction <DeadEnd Up Right Down Left>;
sub gen_maze ( $X,
$Y,
$start_x = (^$X).pick * 2 + 1,
$start_y = (^$Y).pick * 2 + 1 )
{
my @maze;
push @maze, [ ES, -N, (ESW, EW) xx $X - 1, SW ];
push @maze, [ (NS, TODO) xx $X, NS ];
for 1 ..^ $Y {
push @maze, [ NES, EW, (NESW, EW) xx $X - 1, NSW ];
push @maze, [ (NS, TODO) xx $X, NS ];
}
push @maze, [ NE, (EW, NEW) xx $X - 1, -NS, NW ];
@maze[$start_y][$start_x] = OPEN;
my @stack;
my $current = [$start_x, $start_y];
loop {
if my $dir = pick_direction( $current ) {
@stack.push: $current;
$current = move( $dir, $current );
}
else {
last unless @stack;
$current = @stack.pop;
}
}
return @maze;
sub pick_direction([$x,$y]) {
my @neighbors =
(Up if @maze[$y - 2][$x]),
(Down if @maze[$y + 2][$x]),
(Left if @maze[$y][$x - 2]),
(Right if @maze[$y][$x + 2]);
@neighbors.pick or DeadEnd;
}
sub move ($dir, @cur) {
my ($x,$y) = @cur;
given $dir {
when Up { @maze[--$y][$x] = OPEN; @maze[$y][$x-1] -= E; @maze[$y--][$x+1] -= W; }
when Down { @maze[++$y][$x] = OPEN; @maze[$y][$x-1] -= E; @maze[$y++][$x+1] -= W; }
when Left { @maze[$y][--$x] = OPEN; @maze[$y-1][$x] -= S; @maze[$y+1][$x--] -= N; }
when Right { @maze[$y][++$x] = OPEN; @maze[$y-1][$x] -= S; @maze[$y+1][$x++] -= N; }
}
@maze[$y][$x] = 0;
[$x,$y];
}
}
sub display (@maze) {
for @maze -> @y {
for @y -> $w, $c {
print @code[abs $w];
if $c >= 0 { print @code[$c] x 3 }
else { print ' ', @code[abs $c], ' ' }
}
say @code[@y[*-1]];
}
}
display gen_maze( 29, 19 );

View file

@ -0,0 +1,136 @@
Enumeration
;indexes for types of offsets from maze coordinates (x,y)
#visited ;used to index visited(x,y) in a given direction from current maze cell
#maze ;used to index maze() in a given direction from current maze cell
#wall ;used to index walls in maze() in a given direction from current maze cell
#numOffsets = #wall
;direction indexes
#dir_ID = 0 ;identity value, produces no changes
#firstDir
#dir_N = #firstDir
#dir_E
#dir_S
#dir_W
#numDirs = #dir_W
EndEnumeration
DataSection
;maze(x,y) offsets for visited, maze, & walls for each direction
Data.i 1, 1, 0, 0, 0, 0 ;ID
Data.i 1, 0, 0, -1, 0, 0 ;N
Data.i 2, 1, 1, 0, 1, 0 ;E
Data.i 1, 2, 0, 1, 0, 1 ;S
Data.i 0, 1, -1, 0, 0, 0 ;W
Data.i %00, %01, %10, %01, %10 ;wall values for ID, N, E, S, W
EndDataSection
#cellDWidth = 4
Structure mazeOutput
vWall.s
hWall.s
EndStructure
;setup reference values indexed by type and direction from current map cell
Global Dim offset.POINT(#numOffsets, #numDirs)
Define i, j
For i = 0 To #numDirs
For j = 0 To #numOffsets
Read.i offset(j, i)\x: Read.i offset(j, i)\y
Next
Next
Global Dim wallvalue(#numDirs)
For i = 0 To #numDirs: Read.i wallvalue(i): Next
Procedure makeDisplayMazeRow(Array mazeRow.mazeOutput(1), Array maze(2), y)
;modify mazeRow() to produce output of 2 strings showing the vertical walls above and horizontal walls across a given maze row
Protected x, vWall.s, hWall.s
Protected mazeWidth = ArraySize(maze(), 1), mazeHeight = ArraySize(maze(), 2)
vWall = "": hWall = ""
For x = 0 To mazeWidth
If maze(x, y) & wallvalue(#dir_N): vWall + "+ ": Else: vWall + "+---": EndIf
If maze(x, y) & wallvalue(#dir_W): hWall + " ": Else: hWall + "| ": EndIf
Next
mazeRow(0)\vWall = Left(vWall, mazeWidth * #cellDWidth + 1)
If y <> mazeHeight: mazeRow(0)\hWall = Left(hWall, mazeWidth * #cellDWidth + 1): Else: mazeRow(0)\hWall = "": EndIf
EndProcedure
Procedure displayMaze(Array maze(2))
Protected x, y, vWall.s, hWall.s, mazeHeight = ArraySize(maze(), 2)
Protected Dim mazeRow.mazeOutput(0)
For y = 0 To mazeHeight
makeDisplayMazeRow(mazeRow(), maze(), y)
PrintN(mazeRow(0)\vWall): PrintN(mazeRow(0)\hWall)
Next
EndProcedure
Procedure generateMaze(Array maze(2), mazeWidth, mazeHeight)
Dim maze(mazeWidth, mazeHeight) ;Each cell specifies walls present above and to the left of it,
;array includes an extra row and column for the right and bottom walls
Dim visited(mazeWidth + 1, mazeHeight + 1) ;Each cell represents a cell of the maze, an extra line of cells are included
;as padding around the representative cells for easy border detection
Protected i
;mark outside border as already visited (off limits)
For i = 0 To mazeWidth
visited(i + offset(#visited, #dir_N)\x, 0 + offset(#visited, #dir_N)\y) = #True
visited(i + offset(#visited, #dir_S)\x, mazeHeight - 1 + offset(#visited, #dir_S)\y) = #True
Next
For i = 0 To mazeHeight
visited(0 + offset(#visited, #dir_W)\x, i + offset(#visited, #dir_W)\y) = #True
visited(mazeWidth - 1 + offset(#visited, #dir_E)\x, i + offset(#visited, #dir_E)\y) = #True
Next
;generate maze
Protected x = Random(mazeWidth - 1), y = Random (mazeHeight - 1), cellCount, nextCell
visited(x + offset(#visited, #dir_ID)\x, y + offset(#visited, #dir_ID)\y) = #True
PrintN("Maze of size " + Str(mazeWidth) + " x " + Str(mazeHeight) + ", generation started at " + Str(x) + " x " + Str(y))
NewList stack.POINT()
Dim unvisited(#numDirs - #firstDir)
Repeat
cellCount = 0
For i = #firstDir To #numDirs
If Not visited(x + offset(#visited, i)\x, y + offset(#visited, i)\y)
unvisited(cellCount) = i: cellCount + 1
EndIf
Next
If cellCount
nextCell = unvisited(Random(cellCount - 1))
visited(x + offset(#visited, nextCell)\x, y + offset(#visited, nextCell)\y) = #True
maze(x + offset(#wall, nextCell)\x, y + offset(#wall, nextCell)\y) | wallvalue(nextCell)
If cellCount > 1
AddElement(stack())
stack()\x = x: stack()\y = y
EndIf
x + offset(#maze, nextCell)\x: y + offset(#maze, nextCell)\y
ElseIf ListSize(stack()) > 0
x = stack()\x: y = stack()\y
DeleteElement(stack())
Else
Break ;end maze generation
EndIf
ForEver
; ;mark random entry and exit point
; x = Random(mazeWidth - 1): y = Random(mazeHeight - 1)
; maze(x, 0) | wallvalue(#dir_N): maze(mazeWidth, y) | wallvalue(#dir_E)
ProcedureReturn
EndProcedure
If OpenConsole()
Dim maze(0, 0)
Define mazeWidth = Random(5) + 7: mazeHeight = Random(5) + 3
generateMaze(maze(), mazeWidth, mazeHeight)
displayMaze(maze())
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
EndIf

View file

@ -0,0 +1,29 @@
import IO;
import util::Math;
import List;
public void make_maze(int w, int h){
vis = [[0 | _ <- [1..w]] | _ <- [1..h]];
ver = [["| "| _ <- [1..w]] + ["|"] | _ <- [1..h]] + [[]];
hor = [["+--"| _ <- [1..w]] + ["+"] | _ <- [1..h + 1]];
void walk(int x, int y){
vis[y][x] = 1;
d = [<x - 1, y>, <x, y + 1>, <x + 1, y>, <x, y - 1>];
while (d != []){
<<xx, yy>, d> = takeOneFrom(d);
if (xx < 0 || yy < 0 || xx >= w || yy >= w) continue;
if (vis[yy][xx] == 1) continue;
if (xx == x) hor[max([y, yy])][x] = "+ ";
if (yy == y) ver[y][max([x, xx])] = " ";
walk(xx, yy);
}
}
walk(arbInt(w), arbInt(h));
for (<a, b> <- zip(hor, ver)){
println(("" | it + "<z>" | z <- a));
println(("" | it + "<z>" | z <- b));
}
}

View file

@ -0,0 +1,44 @@
code Ran=1, CrLf=9, Text=12; \intrinsic routines
def Cols=20, Rows=6; \dimensions of maze (cells)
int Cell(Cols+1, Rows+1, 3); \cells (plus right and bottom borders)
def LeftWall, Ceiling, Connected; \attributes of each cell (= 0, 1 and 2)
proc ConnectFrom(X, Y); \Connect cells starting from cell X,Y
int X, Y;
int Dir, Dir0;
[Cell(X, Y, Connected):= true; \mark current cell as connected
Dir:= Ran(4); \randomly choose a direction
Dir0:= Dir; \save this initial direction
repeat case Dir of \try to connect to cell at Dir
0: if X+1<Cols & not Cell(X+1, Y, Connected) then \go right
[Cell(X+1, Y, LeftWall):= false; ConnectFrom(X+1, Y)];
1: if Y+1<Rows & not Cell(X, Y+1, Connected) then \go down
[Cell(X, Y+1, Ceiling):= false; ConnectFrom(X, Y+1)];
2: if X-1>=0 & not Cell(X-1, Y, Connected) then \go left
[Cell(X, Y, LeftWall):= false; ConnectFrom(X-1, Y)];
3: if Y-1>=0 & not Cell(X, Y-1, Connected) then \go up
[Cell(X, Y, Ceiling):= false; ConnectFrom(X, Y-1)]
other []; \(never occurs)
Dir:= Dir+1 & $03; \next direction
until Dir = Dir0;
];
int X, Y;
[for Y:= 0 to Rows do
for X:= 0 to Cols do
[Cell(X, Y, LeftWall):= true; \start with all walls and
Cell(X, Y, Ceiling):= true; \ ceilings in place
Cell(X, Y, Connected):= false; \ and all cells disconnected
];
Cell(0, 0, LeftWall):= false; \make left and right doorways
Cell(Cols, Rows-1, LeftWall):= false;
ConnectFrom(Ran(Cols), Ran(Rows)); \randomly pick a starting cell
for Y:= 0 to Rows do \display the maze
[CrLf(0);
for X:= 0 to Cols do
Text(0, if X#Cols & Cell(X, Y, Ceiling) then "+--" else "+ ");
CrLf(0);
for X:= 0 to Cols do
Text(0, if Y#Rows & Cell(X, Y, LeftWall) then "| " else " ");
];
]