Created
August 23, 2023 06:18
-
-
Save nimaid/a2cd4d204bd9c677d67e8a8d8de44d06 to your computer and use it in GitHub Desktop.
A maze generator for ComputerCraft (Direct 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 R8SRcS2S maze.lua | |
-- A recursive backtracker maze generator for my Create mechanical maze | |
-- All function parameters are 0-indexed, Because I hate LUA. | |
-- To install the slave PC software: | |
--[[ | |
pastebin get 5fGx23UZ rx.lua | |
edit rx.lua | |
pastebin get GWSF49zj startup.lua | |
--]] | |
-- Networking parameters | |
rednet.open("bottom") -- Open RedNet on the bottom face | |
local msg_size = 5 -- Only 5 bits per computer | |
-- Main user variables | |
local maze_dim = 8 -- An 8x8 Maze | |
local button_side = "front" -- The side to listen for button inputs on | |
-- Function to send out data to an array of rx computers | |
send_bytes = function(data) | |
local send_length = #data | |
if send_length > 0 then | |
msgs_needed = math.ceil(send_length / msg_size) | |
for m=0,(msgs_needed-1) do | |
msg_offset = m * msg_size | |
msg_str = tostring(m) -- start of string | |
for i=1,msg_size do | |
local data_in = "" | |
if data[msg_offset+i] == true then | |
data_in = "1" | |
else | |
data_in = "0" | |
end | |
msg_str = msg_str .. " " .. data_in | |
end | |
rednet.broadcast(msg_str) | |
end | |
end | |
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 * maze_dim) -- 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 | |
-- 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! | |
send_bytes(wall) -- Setup maze | |
end | |
print("Give a redstone signal to the " .. button_side .. " to make a new maze!\n") | |
while true do | |
os.pullEvent("redstone") -- Wait for a "redstone" event | |
if rs.getInput(button_side) then -- If it's the right side... | |
print("Making maze...") | |
main() | |
print(" Done!") | |
end | |
end |
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 5fGx23UZ rx.lua | |
-- edit rx.lua | |
-- pastebin get GWSF49zj startup.lua | |
local rx_id = "0" | |
rednet.open("bottom") | |
-- A helper table to map bit positions to sides | |
local side_bit_map = {nil, "left", "back", "right", "front", "top"} | |
split_text = function(text_in) | |
local result = {} | |
for w in text_in:gmatch("%S+") do | |
table.insert(result, w) | |
end | |
return result | |
end | |
while true do | |
id, msg = rednet.receive() | |
split_msg = split_text(msg) | |
if #split_msg == #side_bit_map then | |
rx_dest = split_msg[1] | |
if rx_dest == rx_id then | |
print("Data received!") | |
for idx=2,6 do | |
if split_msg[idx] == "1" then | |
rs.setOutput(side_bit_map[idx], true) | |
else | |
rs.setOutput(side_bit_map[idx], false) | |
end | |
end | |
print(" Sides updated!") | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment