Skip to content

Instantly share code, notes, and snippets.

@xslendix
Created November 19, 2022 23:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xslendix/b4c5fee305c5b03825ecba8967dedc02 to your computer and use it in GitHub Desktop.
Save xslendix/b4c5fee305c5b03825ecba8967dedc02 to your computer and use it in GitHub Desktop.
-- Logic
function check_inventory_slots()
local data_saplings = turtle.getItemDetail(1)
local data_torches = turtle.getItemDetail(2)
if not data_saplings then
return 'check_inventory_slots() -> Failed to get saplings information'
else
local sapling_name = data_saplings.name
if not string.find(sapling_name, 'sapling') then
return 'check_inventory_slots() -> Invalid item in saplings slot'
end
if data_saplings.count < 1 then
return 'check_inventory_slots() -> Not enough saplings'
end
end
if not data_torches then
return 'check_inventory_slots() -> Failed to get torches information'
else
local torch_name = data_torches.name
if not string.find(torch_name, 'torch') then
return 'check_inventory_slots() -> Invalid item in torches slot'
end
if data_torches.count < 2 then
return 'check_inventory_slots() -> Not enough torches'
end
end
return nil
end
-- Config
config = {}
function config:load(path)
if not fs.exists(path) then
error('config:load() -> Invalid configuration file.')
end
local file = fs.open(path, 'r')
local width_str = file.readLine()
local height_str = file.readLine()
local tree_spacing_str = file.readLine()
local cfg = {
width = tonumber(width_str) or error('config:load() -> Invalid width'),
height = tonumber(height_str) or error('config:load() -> Invalid height'),
tree_spacing = tonumber(tree_spacing_str) or error('config:load() -> Invalid tree spacing'),
}
cfg.tree_spacing = cfg.tree_spacing + 1
file.close()
return cfg
end
-- State
state = {
-- instruction_index
}
function state:load(path)
if not fs.exists(path) then
local file = fs.open(path, 'a')
file.write('1')
file.close()
end
local file = fs.open(path, 'r')
x_str = file.readLine()
y_str = file.readLine()
heading_str = file.readLine()
tree_index_str = file.readLine()
local ret = {
instruction_index = tonumber(x_str) or error('state:load() -> Invalid X coordinate'),
}
file.close()
return ret
end
function state:update(path, state)
fs.delete(path)
local file = fs.open(path, 'a')
file.write(state.instruction_index)
file.close()
end
_trajectory = {
-- forward
-- back
-- left
-- right
-- chop_or_place_tree
}
function calculate_trajectories(config)
flag = 'forward'
local trajectories = {}
for i=0, config.width, 5 do
for j=0, config.height, 5 do
table.insert(trajectories, 'chop_or_place_tree')
table.insert(trajectories, flag)
end
if flag == 'forward' then
flag = 'back'
else
flag = 'forward'
end
table.remove(trajectories)
table.insert(trajectories, 'right')
end
table.remove(trajectories)
table.insert(trajectories, '----------------')
-- Loop the other way around the table and create the inverse of the instructions.
local table_size = #trajectories
for i=table_size-1, 1, -1 do
local val = trajectories[i]
if val == 'right' then
val = 'left'
end
if val == 'back' then
val = 'forward'
elseif val == 'forward' then
val = 'back'
end
table.insert(trajectories, val)
end
return trajectories
end
-- Application
app = {
config = {},
state = {},
trajectories = {},
logs = {},
paused = false,
input_mode = false,
running = true,
}
CONFIG_FILE = '/tree.cfg'
STATE_FILE = '/tree.state'
function app:draw()
local w, h = term.getSize()
term.clear()
term.setCursorPos(1, 1)
print('TreeFarm - Made by xSlendiX')
term.setTextColor(colors.red)
for i=1, w do
term.write('-')
end
term.setTextColor(colors.white)
term.setCursorPos(1, 3)
cnt = 0
min = #app.logs-h
for i=#app.logs, min, -1 do
cnt = cnt + 1
if cnt > h-3 then break end
if app.logs[i] ~= nil then
print(app.logs[i])
end
end
if app.input_mode then
term.setCursorPos(1, h-1)
term.setTextColor(colors.red)
for i=1, w do
term.write('-')
end
term.setTextColor(colors.white)
term.setCursorPos(1, h)
term.write(':')
end
end
function app:check_fuel(cnt)
if turtle.getFuelLevel() == "unlimited" or turtle.getFuelLevel() >= cnt then
return nil
end
app:log('Out of fuel!')
app.paused = true
end
function app:chop_or_place_tree()
-- chop_or_place_tree - Is air on the left? Yes -> Place sapling
-- No -> Is wewd on the left? Yes -> Chop tree
local inventory_slot_status = check_inventory_slots()
if inventory_slot_status ~= nil then
app:log(inventory_slot_status)
app.paused = true
end
turtle.turnLeft()
if not turtle.detect() then
app:log('Placing sapling.')
turtle.select(1)
turtle.place()
turtle.turnRight()
return nil
end
local _, block = turtle.inspect()
if string.find(block.name, 'log') then
local height = 0
while string.find(block.name, 'log') do
turtle.digUp()
turtle.dig()
turtle.up()
height = height+1
success, block = turtle.inspect()
end
while height ~= 0 do
turtle.down()
height = height-1
end
turtle.select(1)
turtle.place()
else
if not string.find(block.name, 'sapling') then
app:log('Inv. block, ignoring!')
end
end
turtle.turnRight()
end
function app:run_trajectory(trajectory)
if trajectory == nil then return nil end
while not turtle.detectDown() do turtle.down() end
if trajectory == 'forward' then
app:check_fuel(7)
turtle.up()
for i=1, app.config.tree_spacing do
if turtle.detect() then turtle.dig() end
if i == app.config.tree_spacing then
turtle.select(2)
turtle.down()
turtle.turnLeft()
turtle.place()
turtle.turnRight()
end
turtle.forward()
end
elseif trajectory == 'back' then
app:check_fuel(7)
turtle.up()
turtle.turnLeft()
turtle.turnLeft()
for i=1, app.config.tree_spacing do
if turtle.detect() then turtle.dig() end
turtle.forward()
end
turtle.turnLeft()
turtle.turnLeft()
turtle.down()
elseif trajectory == 'right' then
app:check_fuel(9)
turtle.up()
turtle.turnRight()
for i=1, app.config.tree_spacing do
turtle.forward()
end
turtle.down()
turtle.turnLeft()
elseif trajectory == 'left' then
app:check_fuel(9)
turtle.up()
turtle.turnLeft()
for i=1, app.config.tree_spacing do
turtle.forward()
end
turtle.down()
turtle.turnRight()
elseif trajectory == 'chop_or_place_tree' then
app:check_fuel(10)
app:chop_or_place_tree()
end
end
function app:run_loop()
local function run_trajectory_all()
while app.running == true do
if app.paused == false and app.input_mode == false then
local idx = app.state.instruction_index
app:run_trajectory(app.trajectories[idx])
app.state.instruction_index = idx + 1
if idx > #app.trajectories then
app.state.instruction_index = 1
end
if turtle.getItemDetail(15) ~= nil then
if turtle.getItemSpace(15) > 32 then
app:log('Inventory full')
app.paused = true
end
end
state:update(STATE_FILE, app.state)
else
coroutine.yield()
end
end
end
local function main_ui_loop()
while true do
app:draw()
if app.input_mode then
local command = read()
if command == 'quit' or command == 'exit' or command == 'q' then
app:log('Shutting down...')
app.running = false
break
elseif command == 'refuel' or command == 'rf' then
turtle.refuel()
elseif command == 'fuel' or command == 'f' then
app:log('Fuel level: ' .. turtle.getFuelLevel())
elseif command == 'continue' or command == 'c' then
app:log('Continuing...')
app.paused = false
end
app.input_mode = false
else
local event, char = os.pullEvent('char')
if char == ':' then
app.input_mode = true
end
end
end
end
parallel.waitForAll(run_trajectory_all, main_ui_loop)
term.clear()
term.setCursorPos(1, 1)
print('Run `startup` to start the farming robot')
end
function app:log(str)
str = os.date('[%X] ') .. str
print(str)
local file = fs.open('/log.txt', 'a')
file.write(str .. '\n')
file.close()
table.insert(app.logs, str)
app:draw()
end
function app:run()
fs.delete('/log.txt')
term.clear()
term.setCursorPos(1, 1)
app:draw()
app:log('Starting up')
app:log('Checking config')
if not fs.exists(CONFIG_FILE) then
app:log('Config not found.')
local file = fs.open(CONFIG_FILE, 'a')
term.write('Width of farm: ')
local width = read()
w = tonumber(width) or error('app:run() -> Invalid farm width')
term.write('Height of farm: ')
local height = read()
w = tonumber(height) or error('app:run() -> Invalid farm height')
term.write('Tree spacing (>1 or it will break): ')
local tree_spacing = read()
w = tonumber(tree_spacing) or error('app:run() -> Invalid tree spacing')
file.write(width .. '\n')
file.write(height .. '\n')
file.write(tree_spacing)
app:log('Config written.')
file.close()
end
app:log('Loading config.')
app.config = config:load(CONFIG_FILE)
app:log('Loading state.')
app.state = state:load(STATE_FILE)
app.trajectories = calculate_trajectories(app.config)
--term.clear()
--term.setCursorPos(1, 1)
--for i, j in ipairs(app.trajectories) do
-- print('' .. i .. ': ' .. j)
-- if i % 10 == 0 then read() end
--end
app:log('Checking inventory.')
local inventory_slot_status = check_inventory_slots()
if inventory_slot_status ~= nil then error(inventory_slot_status) end
app:log('Running app.')
app:run_loop()
end
app:run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment