Last active
August 23, 2023 00:26
-
-
Save nimaid/59d03422de2929e707406f7d68a166ab to your computer and use it in GitHub Desktop.
A maze generator for ComputerCraft (Shift Register Version)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- pastebin get wz9tPFbS maze.lua | |
-- A recursive backtracker maze generator for my shift regiser based mechanical maze | |
-- All function parameters are 0-indexed, Because I hate LUA. | |
-- Shift register connections | |
local clk = "left" | |
local data = "back" | |
local latch = "right" | |
-- Main user variables | |
local maze_dim = 4 -- A 4x4 Maze | |
local delay = 0.15 -- Delay to use for timing pulses | |
-- Fuction to momentarily pulse a face on then off | |
pulse = function(face) | |
rs.setOutput(face, true) | |
sleep(delay) | |
rs.setOutput(face, false) | |
end | |
-- Function to turn all outputs off | |
all_off = function() | |
rs.setOutput(clk, false) | |
rs.setOutput(data, false) | |
rs.setOutput(latch, false) | |
end | |
-- Function to output binary values to a shift register | |
shift_out = function(values) | |
all_off() | |
for k, v in pairs(values) do | |
rs.setOutput(data, v) | |
sleep(delay) | |
pulse(clk) | |
end | |
pulse(latch) | |
all_off() | |
end | |
-- Function to make a table filled with a value | |
filled_table = function(table_size, value) | |
local new_table = {} | |
for i=1, table_size do | |
new_table[i] = value | |
end | |
return new_table | |
end | |
-- Function to make a 2d table filled with a value | |
filled_table_2d = function(table_size_x, table_size_y, value) | |
local new_table = {} | |
for x=1, table_size_x do | |
new_table[x] = {} | |
for y=1, table_size_y do | |
new_table[x][y] = value | |
end | |
end | |
return new_table | |
end | |
-- A class to represent directions | |
local Direction = { UP = 0, | |
RIGHT = 1, | |
DOWN = 2, | |
LEFT = 3 } | |
-- A function to pick a random Direction | |
random_dir = function() | |
local n = math.random(4) | |
if n == 1 then | |
return Direction.UP | |
elseif n == 2 then | |
return Direction.DOWN | |
elseif n == 3 then | |
return Direction.LEFT | |
else | |
return Direction.RIGHT | |
end | |
end | |
-- Main Function | |
main = function() | |
-- Make major variables | |
local cell_explored = filled_table_2d(maze_dim, maze_dim, false) | |
local wall_count = maze_dim * (maze_dim + 1) * 2 | |
local wall = filled_table(wall_count, true) | |
-- A function to get the index of a cell wall in a specified direction | |
get_wall_index = function(x, y, dir) | |
local n = x + (y * 4) -- The "cell number", left to right, top to bottom | |
if dir == Direction.UP then | |
return n + (maze_dim * (maze_dim + 1)) | |
elseif dir == Direction.DOWN then | |
return n + (maze_dim * (maze_dim + 2)) | |
elseif dir == Direction.LEFT then | |
return n + y | |
elseif dir == Direction.RIGHT then | |
return n + y + 1 | |
else | |
error("Invalid direction!") | |
end | |
end | |
-- A function to set a wall state | |
set_wall = function(x, y, dir, state) | |
wall[get_wall_index(x, y, dir)+1] = state | |
end | |
-- A simplified function to break a wall | |
break_wall = function(x, y, dir) | |
set_wall(x, y, dir, false) | |
end | |
-- A function to "explore" a given cell | |
explore_cell = function(x, y) | |
cell_explored[x+1][y+1] = true | |
end | |
-- A function to get the "explored" state of a cell | |
is_explored = function(x, y) | |
return cell_explored[x+1][y+1] | |
end | |
-- A function to get a list of unexplored neighbor cells and their directions | |
get_neighbors = function(x, y) | |
local neighbor_list = {} | |
if x > 0 then -- If a left cell exists | |
if not is_explored(x - 1, y) then -- If left cell not explored | |
table.insert(neighbor_list, | |
{ | |
dir = Direction.LEFT, | |
x = x - 1, | |
y = y | |
} | |
) | |
end | |
end | |
if x < (maze_dim-1) then -- If a right cell exists | |
if not is_explored(x + 1, y) then -- If right cell not explored | |
table.insert(neighbor_list, | |
{ | |
dir = Direction.RIGHT, | |
x = x + 1, | |
y = y | |
} | |
) | |
end | |
end | |
if y > 0 then -- If an up cell exists | |
if not is_explored(x, y - 1) then -- If up cell not explored | |
table.insert(neighbor_list, | |
{ | |
dir = Direction.UP, | |
x = x, | |
y = y - 1 | |
} | |
) | |
end | |
end | |
if y < (maze_dim - 1) then -- If a down cell exists | |
if not is_explored(x, y + 1) then -- If down cell not explored | |
table.insert(neighbor_list, | |
{ | |
dir = Direction.DOWN, | |
x = x, | |
y = y + 1 | |
} | |
) | |
end | |
end | |
return neighbor_list | |
end | |
--[[ | |
-- Define start and end points | |
local start_point = { x = 0, | |
y = 0, | |
dir = Direction.LEFT | |
} -- Upper left | |
local end_point = { x = maze_dim - 1, | |
y = maze_dim - 1, | |
dir = Direction.RIGHT | |
} -- Lower right | |
--]] | |
-- Calculate random starting point and direction | |
local start_point = {dir = random_dir(), x = nil, y = nil} | |
local start_coord = math.random(maze_dim) - 1 | |
if start_point.dir == Direction.UP then | |
start_point.x = start_coord | |
start_point.y = 0 | |
elseif start_point.dir == Direction.DOWN then | |
start_point.x = start_coord | |
start_point.y = maze_dim - 1 | |
elseif start_point.dir == Direction.LEFT then | |
start_point.x = 0 | |
start_point.y = start_coord | |
elseif start_point.dir == Direction.RIGHT then | |
start_point.x = maze_dim - 1 | |
start_point.y = start_coord | |
end | |
-- Make end point opposite of start point | |
local end_point = { x = (maze_dim - 1) - start_point.x, | |
y = (maze_dim - 1) - start_point.y, | |
dir = nil | |
} | |
if start_point.dir == Direction.UP then | |
end_point.dir = Direction.DOWN | |
elseif start_point.dir == Direction.DOWN then | |
end_point.dir = Direction.UP | |
elseif start_point.dir == Direction.LEFT then | |
end_point.dir = Direction.RIGHT | |
elseif start_point.dir == Direction.RIGHT then | |
end_point.dir = Direction.LEFT | |
end | |
-- Punch entrance and exit | |
break_wall(start_point.x, start_point.y, start_point.dir) | |
break_wall(end_point.x, end_point.y, end_point.dir) | |
--[[ | |
-- Recursive method: | |
-- | |
-- 1. Given a current cell as a parameter | |
-- 2. Mark the current cell as visited | |
-- 3. While the current cell has any unvisited neighbour cells | |
-- a. Choose one of the unvisited neighbours | |
-- b. Remove the wall between the current cell and the chosen cell | |
-- c. Invoke the routine recursively for the chosen cell | |
--]] | |
recursive_maze = function(x, y) -- (1) | |
explore_cell(x, y) -- (2) | |
-- (3) | |
local neighbours = get_neighbors(x, y) | |
while(#neighbours > 0) do | |
local new_cell = neighbours[math.random(#neighbours)] -- (a) | |
break_wall(x, y, new_cell.dir) -- (b) | |
recursive_maze(new_cell.x, new_cell.y) -- (c) | |
neighbours = get_neighbors(x, y) -- Update neighbors list | |
end | |
end | |
recursive_maze(end_point.x, end_point.y) -- Run! | |
shift_out(wall) -- Setup maze | |
end | |
print("Press the button on the front of the computer to make a new maze!\n") | |
while true do | |
if rs.getInput("front") then | |
print("Making maze...") | |
main() | |
print(" Done!") | |
end | |
sleep(delay) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment