188 lines
4.8 KiB
Awk
188 lines
4.8 KiB
Awk
#!/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);
|
|
}
|