Implement wood farm

This commit is contained in:
Kai Vogelgesang 2020-07-08 05:43:50 +02:00
parent 784106e5b7
commit 1f765d59a7
2 changed files with 330 additions and 38 deletions

View File

@ -1,5 +1,5 @@
-- Do not lose state when reset (chunkloading etc) -- Do not lose state when reset (chunkloading etc)
state = (function () local state = (function ()
local path = ".state" local path = ".state"
local state_table = {} local state_table = {}
@ -21,6 +21,8 @@ state = (function ()
}) })
end)() end)()
-- Not sure whether this is a good idea
--[[
if state.x == nil or state.y == nil or state.z == nil or state.o == nil then if state.x == nil or state.y == nil or state.z == nil or state.o == nil then
printError("[lib] position is not set") printError("[lib] position is not set")
printError("[lib] defaulting to 0, 0, 0, +z") printError("[lib] defaulting to 0, 0, 0, +z")
@ -29,6 +31,21 @@ if state.x == nil or state.y == nil or state.z == nil or state.o == nil then
state.z = 0 state.z = 0
state.o = 0 state.o = 0
end end
]]
local function setPosition(x, y, z, direction)
local o = ({
["+z"] = 0,
["-x"] = 1,
["-z"] = 2,
["+x"] = 3,
})[direction]
state.x = x
state.y = y
state.z = z
state.o = o
end
--[[ --[[
orientation: orientation:
@ -38,11 +55,7 @@ end
3 = East (+x) 3 = East (+x)
]] ]]
function getOrientation() local function move(raw_move, position_update)
return ({"+z", "-x", "-z", "+x"})[1 + state.o]
end
function move(raw_move, position_update)
return function() return function()
success, err = raw_move() success, err = raw_move()
if not success then if not success then
@ -53,40 +66,80 @@ function move(raw_move, position_update)
end end
end end
local fwd = move(turtle.forward, function()
if state.o == 1 or state.o == 3 then
state.x = state.x + ((state.o == 1) and -1 or 1)
elseif state.o == 0 or state.o == 2 then
state.z = state.z + ((state.o == 2) and -1 or 1)
end
end)
local back = move(turtle.back, function()
if state.o == 1 or state.o == 3 then
state.x = state.x + ((state.o == 1 and 1 or -1))
elseif state.o == 0 or state.o == 2 then
state.z = state.z + ((state.o == 2) and 1 or -1)
end
end)
local up = move(turtle.up, function()
state.y = state.y + 1
end)
local down = move(turtle.down, function()
state.y = state.y - 1
end)
local left = move(turtle.turnLeft, function()
state.o = (state.o - 1) % 4
end)
local right = move(turtle.turnRight, function()
state.o = (state.o + 1) % 4
end)
local function getOrientation()
return ({"+z", "-x", "-z", "+x"})[1 + state.o]
end
local function rotateTowards(direction)
local target_o = ({
["+z"] = 0,
["-x"] = 1,
["-z"] = 2,
["+x"] = 3,
})[direction]
if not target_o then
error(tostring(direction) .. " is not a valid direction.")
end
local delta_o = (target_o - state.o) % 4
if delta_o == 0 then
-- orientation already correct
elseif delta_o == 1 then
right()
elseif delta_o == 2 then
right()
right()
elseif delta_o == 3 then
left()
end
end
return { return {
state = state, state = state,
fwd = fwd,
back = back,
up = up,
down = down,
left = left,
right = right,
setPosition = setPosition,
getOrientation = getOrientation, getOrientation = getOrientation,
rotateTowards = rotateTowards,
fwd = move(turtle.forward, function()
if state.o == 1 or state.o == 3 then
state.x = state.x + ((state.o == 1) and -1 or 1)
elseif state.o == 0 or state.o == 2 then
state.z = state.z + ((state.o == 2) and -1 or 1)
end
end),
back = move(turtle.back, function()
if state.o == 1 or state.o == 3 then
state.x = state.x + ((state.o == 1 and 1 or -1))
elseif state.o == 0 or state.o == 2 then
state.z = state.z + ((state.o == 2) and 1 or -1)
end
end),
up = move(turtle.up, function()
state.y = state.y + 1
end),
down = move(turtle.down, function()
state.y = state.y - 1
end),
left = move(turtle.turnLeft, function()
state.o = (state.o - 1) % 4
end),
right = move(turtle.turnRight, function()
state.o = (state.o + 1) % 4
end),
} }

239
kai/woodfarm.lua Normal file
View File

@ -0,0 +1,239 @@
local T = require("lib.lua")
--[[
States:
- MOVE_TO_TREE
- CHECK_TREE
- ASCEND_TREE
- FINALIZE_TREE
- OUTPUT
- RESUPPLY_SAPS
- RESUPPLY_FUEL
Persistent Variables:
- current_state
- current_tree [1,14]
- current_row [1,6]
Inventory:
64 + 20 Saplings in Slots 1 and 2
]]
local MAX_TREE = 14
local MAX_ROW = 6
local OUTPUT_TARGET = { x = 2, z = 0, o = "+z" }
local SAPS_TARGET = { x = 1, z = 0, o = "+z" }
local FUEL_TARGET = { x = 0, z = 0, o = "+z" }
local TREE_MAX_HEIGHT = 7
-- Saplings are at y = -1 (and coordinates are zero-based)
local TREE_MAX_Y = TREE_MAX_HEIGHT - 2
local LOG_NAME = "minecraft:birch_log"
local SAP_SLOT = 1
local BACKUP_SAP_SLOT = 2
local REFUEL_SLOT = 3
local SAP_SLOT_TARGET_COUNT = 64
local BACKUP_SAP_SLOT_TARGET_COUNT = 20
-- Should be enough even if every tree is fully grown
local FUEL_LEVEL_TARGET = 1000
local function calculate_tree_position(row_index, tree_index)
local x = (row_index - 1) * 5
local z
if row_index % 2 == 0 then
z = -2 * tree_index
else
z = -30 + 2 * tree_index
end
return x, z
end
local function greedy_move(x, z, o)
if z ~= T.state.z then
if z > T.state.z then
T.rotateTowards("+z")
else:
T.rotateTowards("-z")
end
for _ = 1, math.abs(z - T.state.z) do
T.fwd()
end
end
if x ~= T.state.x then
if x > T.state.x then
T.rotateTowards("+x")
else:
T.rotateTowards("-x")
end
for _ = 1, math.abs(x - T.state.x) do
T.fwd()
end
end
T.rotateTowards(o)
end
local function ensure_item_count(count)
if turtle.getItemCount() >= count then
return
end
turtle.suck(count - turtle.getItemCount())
-- turtle.suck might not suck enough items if the target container does not have them
-- but it won't tell us if this happened...
while turtle.getItemCount() ~= count do
sleep(1)
turtle.suck(count - turtle.getItemCount())
end
end
local state_machine = {
["MOVE_TO_TREE"] = function()
-- get target tree coordinates
-- and move such that we are facing it
local x, z = calculate_tree_position(T.state.current_row, T.state.current_tree)
local o
if T.state.current_row ~= 1 and T.state.current_tree == 1 then
-- we just turned towards a new row and are approaching in positive x direction
x = x - 1
o = "+x"
else
-- we are approaching in negative z direction
z = z + 1
o = "-z"
end
greedy_move(x, z, o)
return "CHECK_TREE"
end
["CHECK_TREE"] = function()
if not turtle.detect() then
-- no tree, so skip ascending
T.fwd()
return "FINALIZE_TREE"
else
-- tree present, chop it down
turtle.dig()
T.fwd()
turtle.digDown()
return "ASCEND_TREE"
end
end
["ASCEND_TREE"] = function()
local success, data = turtle.inspectUp()
if not s and T.state.y < TREE_MAX_Y - 1 then
-- probably reset after chopping a block
T.up()
end
while true do
local success, data = turtle.inspectUp()
if not s or data.name ~= LOG_NAME then
-- chopped all the wood
break
end
turtle.digUp()
if T.state.y == TREE_MAX_Y - 1 then
-- we are below the last log, no need to move up
break
end
T.up()
end
return "FINALIZE_TREE"
end
["FINALIZE_TREE"] = function()
-- make sure we are directly above the sapling target
while T.state.y > 0 do
T.down()
end
turtle.select(SAP_SLOT)
-- make sure we have a sapling
if turtle.getItemCount() == 0 then
turtle.select(BACKUP_SAP_SLOT)
turtle.transferTo(SAP_SLOT)
turtle.select(SAP_SLOT)
end
if T.state.current_tree < MAX_TREE then
-- go to the next tree in this row
T.state.current_tree = T.state.current_tree + 1
return "MOVE_TO_TREE"
elseif T.state.current_row < MAX_ROW then
-- go to the first tree in the next row
T.state.current_tree = 0
T.state.current_row = T.state.current_row + 1
return "MOVE_TO_TREE"
else
-- went through the entire farm once
return "OUTPUT"
end
["OUTPUT"] = function()
greedy_move(OUTPUT_TARGET.x, OUTPUT_TARGET.z, OUTPUT_TARGET.o)
-- Drop all logs
for slot = 1, 16 do
turtle.select(slot)
data = turtle.getItemDetail()
if data and data.name == LOG_NAME then
turtle.drop()
end
end
return "RESUPPLY_SAPS"
end
["RESUPPLY_SAPS"] = function()
greedy_move(SAPS_TARGET.x, SAPS_TARGET.z, SAPS_TARGET.o)
turtle.select(SAP_SLOT)
ensure_item_count(SAP_SLOT_TARGET_COUNT)
turtle.select(BACKUP_SAP_SLOT)
ensure_item_count(BACKUP_SAP_SLOT_TARGET_COUNT)
return "RESUPPLY_FUEL"
end
["RESUPPLY_FUEL"] = function()
greedy_move(FUEL_TARGET.x, FUEL_TARGET.z, FUEL_TARGET.o)
local fuel_count = math.ceil(FUEL_LEVEL_TARGET - turtle.getFuelLevel() / 80)
turtle.select(REFUEL_SLOT)
ensure_item_count(fuel_count)
turtle.refuel()
T.state.current_row = 0
T.state.current_tree = 0
return "MOVE_TO_TREE"
end
}
-- initial setup
if not T.state.current_state then
T.setPosition(0, 0, 0, "-z")
T.state.current_state = "RESUPPLY_FUEL"
end
-- main loop
while true do
T.state.current_state = state_machine[T.state.current_state]()
end