Created
November 19, 2022 23:42
-
-
Save slendidev/b4c5fee305c5b03825ecba8967dedc02 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
-- 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