Skip to content

Instantly share code, notes, and snippets.

@nimaid
Last active August 23, 2023 00:26
Show Gist options
  • Save nimaid/59d03422de2929e707406f7d68a166ab to your computer and use it in GitHub Desktop.
Save nimaid/59d03422de2929e707406f7d68a166ab to your computer and use it in GitHub Desktop.
A maze generator for ComputerCraft (Shift Register Version)
-- 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