Compare commits
2 Commits
749c32325f
...
b5cb13732e
| Author | SHA1 | Date | |
|---|---|---|---|
| b5cb13732e | |||
| 13b506923b |
324
controller/excavation_controller.lua
Normal file
324
controller/excavation_controller.lua
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
local Direction = require("lib.direction")
|
||||||
|
local TurtleController = require("controller.turtle_controller")
|
||||||
|
|
||||||
|
---@alias ExcavationControllerConfig {slice_length: number, slice_height: number, center_slice_width: number, slice_width: number, slice_padding: number, slices_left: number, slices_right: number}
|
||||||
|
|
||||||
|
---@class ExcavationController
|
||||||
|
---@field controller TurtleController
|
||||||
|
---@field config ExcavationControllerConfig
|
||||||
|
local ExcavationController = {}
|
||||||
|
ExcavationController.__index = ExcavationController
|
||||||
|
|
||||||
|
|
||||||
|
---@return ExcavationController
|
||||||
|
function ExcavationController:Create()
|
||||||
|
local t = {}
|
||||||
|
setmetatable(t, ExcavationController)
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
-- Fields
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
t.controller = TurtleController:Create()
|
||||||
|
t.config = {
|
||||||
|
slice_length = 0,
|
||||||
|
slice_height = 0,
|
||||||
|
center_slice_width = 0,
|
||||||
|
slice_width = 0,
|
||||||
|
slice_padding = 0,
|
||||||
|
slices_left = 0,
|
||||||
|
slices_right = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
-- Behavior Methods
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
---Excavates a single 1x1/1x2 tunnel of configured length.
|
||||||
|
---Will leave the turtle wherever it ends up.
|
||||||
|
---Only unstocks/refuels if required.
|
||||||
|
---@param mine_above boolean
|
||||||
|
---@param mine_below boolean
|
||||||
|
function ExcavationController:Excavate_1x1or2or3xL(mine_above, mine_below)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
if mine_above then
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
end
|
||||||
|
if mine_below then
|
||||||
|
self.controller:EnableMiningBelow()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.controller:MoveForward(self.config.slice_length)
|
||||||
|
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:DisableMiningBelow()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Excavates a single 1xH partial slice of configured length.
|
||||||
|
---Will leave the turtle in its starting position.
|
||||||
|
---Only unstocks/refuels if required.
|
||||||
|
function ExcavationController:Excavate_1xHxL()
|
||||||
|
self.controller:StorePosition()
|
||||||
|
|
||||||
|
-- We can mine 2 blocks heigh in a single go
|
||||||
|
local number_of_1x3xL = math.floor(self.config.slice_height / 3)
|
||||||
|
|
||||||
|
-- Prepare for mining the blocks below the turtle
|
||||||
|
if number_of_1x3xL > 0 then
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveVertical(1)
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Mine 1x3xL
|
||||||
|
for i = 1,number_of_1x3xL do
|
||||||
|
self:Excavate_1x1or2or3xL(true, true)
|
||||||
|
|
||||||
|
self.controller:TurnRelative(2)
|
||||||
|
|
||||||
|
-- Don't move upwards in the last iteration so we can decide
|
||||||
|
-- how much to move depending on how much we still have to excavate
|
||||||
|
if i == number_of_1x3xL then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveVertical(4)
|
||||||
|
self.controller:MoveVertical(-1)
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Mine remaining 1x2xL or 1x1xL
|
||||||
|
if self.config.slice_height % 3 == 2 then
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveVertical(3)
|
||||||
|
self.controller:MoveVertical(-1)
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
|
||||||
|
self:Excavate_1x1or2or3xL(true, false)
|
||||||
|
elseif self.config.slice_height % 3 == 1 then
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveVertical(3)
|
||||||
|
self.controller:MoveVertical(-1)
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
|
||||||
|
self:Excavate_1x1or2or3xL(false, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.controller:EnableMiningBelow()
|
||||||
|
self.controller:MoveBack()
|
||||||
|
self.controller:DisableMiningBelow()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Excavates a single WxH slice of configured length (EAST to WEST).
|
||||||
|
---Will leave the turtle in its starting position.
|
||||||
|
---Only unstocks/refuels if required.
|
||||||
|
---@param center_slice boolean | nil
|
||||||
|
function ExcavationController:Excavate_WxHxL(center_slice)
|
||||||
|
self.controller:StorePosition()
|
||||||
|
|
||||||
|
center_slice = center_slice or false
|
||||||
|
local width = center_slice and self.config.center_slice_width or self.config.slice_width
|
||||||
|
|
||||||
|
for i = 1,width do
|
||||||
|
self:Excavate_1xHxL()
|
||||||
|
|
||||||
|
if i == width then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
self.controller:TurnToDirection(Direction.WEST)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(1)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.controller:MoveBack()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Excavates all slices.
|
||||||
|
---Will leave the turtle refueled and unstocked in its 0x0x0 position.
|
||||||
|
function ExcavationController:Excavate()
|
||||||
|
-- Enter excavation area
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(1)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
|
||||||
|
-- Excavate center slice (start from right/back/bottom)
|
||||||
|
-- Uneven center widths will be centered, even center widths will have a block more on the right
|
||||||
|
print("Excavating center slice...")
|
||||||
|
local center_width_right = math.floor(self.config.center_slice_width / 2)
|
||||||
|
self.controller:StorePosition()
|
||||||
|
self.controller:TurnToDirection(Direction.EAST)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(center_width_right)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
self:Excavate_WxHxL(true)
|
||||||
|
self.controller:MoveBack() -- (0, 0, 1)
|
||||||
|
|
||||||
|
-- Move to right slices starting location
|
||||||
|
local padded_width_right = self.config.slices_right * (self.config.slice_width + self.config.slice_padding)
|
||||||
|
self.controller:StorePosition()
|
||||||
|
self.controller:TurnToDirection(Direction.EAST)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(center_width_right + padded_width_right)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
|
||||||
|
-- Excavate right slices
|
||||||
|
print("Excavating right slices")
|
||||||
|
for i = 1,self.config.slices_right do
|
||||||
|
self:Excavate_WxHxL()
|
||||||
|
|
||||||
|
if i == self.config.slices_right then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move to the next slice
|
||||||
|
self.controller:TurnToDirection(Direction.WEST)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(self.config.slice_width + self.config.slice_padding)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
end
|
||||||
|
self.controller:MoveBack() -- (0, 0, 1)
|
||||||
|
|
||||||
|
-- Move to left slices starting location
|
||||||
|
local center_width_left = self.config.center_slice_width - center_width_right
|
||||||
|
self.controller:StorePosition()
|
||||||
|
self.controller:TurnToDirection(Direction.WEST)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(center_width_left)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
|
||||||
|
-- Excavate left slices
|
||||||
|
print("Excavate left slices")
|
||||||
|
for i = 1,self.config.slices_left do
|
||||||
|
-- Move to the next slice
|
||||||
|
self.controller:TurnToDirection(Direction.WEST)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(self.config.slice_padding)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
|
||||||
|
self:Excavate_WxHxL()
|
||||||
|
|
||||||
|
if i == self.config.slices_left then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
self.controller:TurnToDirection(Direction.WEST)
|
||||||
|
self.controller:EnableMiningForward()
|
||||||
|
self.controller:EnableMiningAbove()
|
||||||
|
self.controller:MoveForward(self.config.slice_width)
|
||||||
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
end
|
||||||
|
self.controller:MoveBack() -- (0, 0, 1)
|
||||||
|
|
||||||
|
-- Finish up
|
||||||
|
self.controller:MoveToPosition(0, 0, 0, self.controller.config.storage_direction)
|
||||||
|
self.controller:DropInventory()
|
||||||
|
self.controller:TurnToDirection(Direction.NORTH)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
-- Management Methods
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function ExcavationController:Configure()
|
||||||
|
local config_complete = false
|
||||||
|
|
||||||
|
while not config_complete do
|
||||||
|
print("How long should each slice be?")
|
||||||
|
self.config.slice_length = tonumber(io.read()) or 3
|
||||||
|
|
||||||
|
print("How high should each slice be?")
|
||||||
|
self.config.slice_height = tonumber(io.read()) or 3
|
||||||
|
|
||||||
|
print("How wide should the center slice be?")
|
||||||
|
self.config.center_slice_width = tonumber(io.read()) or 1
|
||||||
|
|
||||||
|
print("How wide should the other slices be?")
|
||||||
|
self.config.slice_width = tonumber(io.read()) or 1
|
||||||
|
|
||||||
|
print("How many blocks should remain between each slice?")
|
||||||
|
self.config.slice_padding = tonumber(io.read()) or 0
|
||||||
|
|
||||||
|
print("How many slices should the turtle mine to its right?")
|
||||||
|
self.config.slices_right = tonumber(io.read()) or 1
|
||||||
|
|
||||||
|
print("How many slices should the turtle mine to its left?")
|
||||||
|
self.config.slices_left = tonumber(io.read()) or 1
|
||||||
|
|
||||||
|
local padded_width_left = self.config.slices_left * (self.config.slice_width + self.config.slice_padding)
|
||||||
|
local padded_width_right = self.config.slices_right * (self.config.slice_width + self.config.slice_padding)
|
||||||
|
local padded_width = padded_width_left + padded_width_right + self.config.center_slice_width
|
||||||
|
local mined_width_left = self.config.slices_left * self.config.slice_width
|
||||||
|
local mined_width_right = self.config.slices_right * self.config.slice_width
|
||||||
|
local mined_width = mined_width_left + mined_width_right + self.config.center_slice_width
|
||||||
|
|
||||||
|
print("Configuration complete!")
|
||||||
|
print(("Mining area spans %d x %d x %d (width x height x forward), totalling %d blocks."):format(
|
||||||
|
padded_width, self.config.slice_height, self.config.slice_length, padded_width * self.config.slice_height * self.config.slice_length
|
||||||
|
))
|
||||||
|
print(("Turtle will mine %d block wide slices (%d wide in the center) with %d blocks of padding, totalling %d mined blocks."):format(
|
||||||
|
self.config.slice_width, self.config.center_slice_width, self.config.slice_padding, mined_width * self.config.slice_height * self.config.slice_length
|
||||||
|
))
|
||||||
|
print("Do you want to accept the configuration (enter 1, otherwise 0)?")
|
||||||
|
config_complete = tonumber(io.read()) == 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
-- Main Method
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
function ExcavationController:Run()
|
||||||
|
self.controller:Configure()
|
||||||
|
self:Configure()
|
||||||
|
|
||||||
|
-- Consume our starting fuel and refuel to the full amount
|
||||||
|
turtle.select(1)
|
||||||
|
turtle.refuel()
|
||||||
|
self.controller:RefuelIfEmpty()
|
||||||
|
|
||||||
|
self:Excavate()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return ExcavationController
|
||||||
@ -1,148 +0,0 @@
|
|||||||
local Direction = require("lib.direction")
|
|
||||||
local TurtleController = require("controller.turtle_controller")
|
|
||||||
|
|
||||||
---@alias NetheriteControllerConfig {mine_forward: number, slices_left: number, slices_right: number, slices_padding: number}
|
|
||||||
|
|
||||||
---@class NetheriteController
|
|
||||||
---@field controller TurtleController
|
|
||||||
---@field config NetheriteControllerConfig
|
|
||||||
local NetheriteController = {}
|
|
||||||
NetheriteController.__index = NetheriteController
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: This controller can't return to unstock/refuel if stuck in the middle of a slice
|
|
||||||
|
|
||||||
|
|
||||||
---@return NetheriteController
|
|
||||||
function NetheriteController:Create()
|
|
||||||
local t = {}
|
|
||||||
setmetatable(t, NetheriteController)
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Fields
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
t.controller = TurtleController:Create()
|
|
||||||
t.config = {
|
|
||||||
mine_forward = 0,
|
|
||||||
slices_left = 0,
|
|
||||||
slices_right = 0,
|
|
||||||
slices_padding = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Behavior Methods
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function NetheriteController:Excavate()
|
|
||||||
-- Enter the excavation area
|
|
||||||
self.controller:EnableMining()
|
|
||||||
self.controller:MoveRelative(1)
|
|
||||||
|
|
||||||
local right_padded_width = self.config.slices_right * (self.config.slices_padding + 1)
|
|
||||||
local left_padded_width = self.config.slices_left * (self.config.slices_padding + 1)
|
|
||||||
|
|
||||||
-- Move to the bottom right corner of the layer
|
|
||||||
self.controller:TurnToDirection(Direction.EAST)
|
|
||||||
self.controller:MoveRelative(right_padded_width)
|
|
||||||
self.controller:TurnToDirection(Direction.NORTH)
|
|
||||||
self.controller:MoveRelative(self.config.mine_forward)
|
|
||||||
self.controller:TurnToDirection(Direction.WEST)
|
|
||||||
self.controller:MoveRelative(left_padded_width + right_padded_width)
|
|
||||||
self.controller:TurnToDirection(Direction.SOUTH)
|
|
||||||
self.controller:MoveRelative(self.config.mine_forward)
|
|
||||||
self.controller:TurnToDirection(Direction.EAST)
|
|
||||||
self.controller:MoveRelative(left_padded_width + right_padded_width)
|
|
||||||
self.controller:TurnToDirection(Direction.NORTH)
|
|
||||||
|
|
||||||
-- Zig zag mine the full width from back to front
|
|
||||||
local turn_dir = -1
|
|
||||||
for i = 1,self.config.slices_right + self.config.slices_left do
|
|
||||||
self.controller:MoveRelative(self.config.mine_forward)
|
|
||||||
|
|
||||||
-- Skip the last turn, as we won't mine that slice
|
|
||||||
if i == self.config.slices_right + self.config.slices_left then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
self.controller:TurnRelative(turn_dir)
|
|
||||||
self.controller:MoveRelative(self.config.slices_padding + 1)
|
|
||||||
self.controller:TurnRelative(turn_dir)
|
|
||||||
|
|
||||||
turn_dir = -1 * turn_dir
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.controller.position.z > 1 then
|
|
||||||
self.controller:TurnToDirection(Direction.SOUTH)
|
|
||||||
self.controller:MoveRelative(self.controller.position.z - 1)
|
|
||||||
self.controller:MoveToPosition(0, 0, 0, Direction.NORTH)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Unload before doing the next layer
|
|
||||||
self.controller:TurnToDirection(self.controller.config.storage_direction)
|
|
||||||
self.controller:DropInventory()
|
|
||||||
self.controller:TurnToDirection(Direction.NORTH)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Management Methods
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function NetheriteController:Configure()
|
|
||||||
local config_complete = false
|
|
||||||
|
|
||||||
while not config_complete do
|
|
||||||
print("How many blocks should the turtle mine forward?")
|
|
||||||
self.config.mine_forward = tonumber(io.read()) or 3
|
|
||||||
|
|
||||||
print("How many slices should the turtle to its right?")
|
|
||||||
self.config.slices_right = tonumber(io.read()) or 3
|
|
||||||
|
|
||||||
print("How many blocks should the turtle mine to its left?")
|
|
||||||
self.config.slices_left = tonumber(io.read()) or 3
|
|
||||||
|
|
||||||
print("How many blocks should the turtle leave between the slices?")
|
|
||||||
self.config.slices_padding = tonumber(io.read()) or 3
|
|
||||||
|
|
||||||
local width = self.config.slices_left + self.config.slices_right + 1
|
|
||||||
local height = 3
|
|
||||||
|
|
||||||
print("Configuration complete!")
|
|
||||||
print(("Turtle will mine an area of %d x %d x %d (forward x width x height, excluding padding) totalling %d blocks."):format(
|
|
||||||
self.config.mine_forward, width, height, self.config.mine_forward * width * height
|
|
||||||
))
|
|
||||||
print("Do you want to accept the configuration (enter 1, otherwise 0)?")
|
|
||||||
config_complete = tonumber(io.read()) == 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Main Method
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function NetheriteController:Run()
|
|
||||||
self.controller:Configure()
|
|
||||||
self:Configure()
|
|
||||||
|
|
||||||
-- Consume our starting fuel and refuel to the full amount
|
|
||||||
turtle.select(1)
|
|
||||||
turtle.refuel()
|
|
||||||
self.controller:RefuelIfEmpty()
|
|
||||||
|
|
||||||
self:Excavate()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return NetheriteController
|
|
||||||
@ -26,21 +26,24 @@ end
|
|||||||
function TestingController:TestRelativeMovementWithRelativeRotation()
|
function TestingController:TestRelativeMovementWithRelativeRotation()
|
||||||
print("Testing relative movement with relative rotation...")
|
print("Testing relative movement with relative rotation...")
|
||||||
|
|
||||||
-- N: BotCenter
|
-- N: BackCenter (Center)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnRelative(1) -- E: TopCenter
|
self.controller:TurnRelative(1) -- E: FrontCenter (Center)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnRelative(2) -- W: TopRight
|
self.controller:TurnRelative(2) -- W: FrontRight (Center)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveVertical(3)
|
||||||
self.controller:TurnRelative(10) -- E: TopCenter
|
self.controller:TurnRelative(8) -- W: FrontRight (Top)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnRelative(-3) -- S: TopRight
|
self.controller:TurnRelative(3) -- S: FrontCenter (Top)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnRelative(1) -- W: BotRight
|
self.controller:TurnRelative(9) -- W: BackCenter (Top)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveVertical(-3)
|
||||||
self.controller:TurnRelative(1) -- N: BotCenter
|
self.controller:TurnRelative(1) -- N: BackCenter (Center)
|
||||||
|
|
||||||
print("The turtle should be in its original location.")
|
print("The turtle should be in its original location.")
|
||||||
|
print(("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
|
||||||
|
self.controller.position.x, self.controller.position.y, self.controller.position.z, self.controller.position.dir
|
||||||
|
))
|
||||||
print("Press Enter to continue")
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
end
|
end
|
||||||
@ -49,21 +52,24 @@ end
|
|||||||
function TestingController:TestRelativeMovementWithAbsoluteRotation()
|
function TestingController:TestRelativeMovementWithAbsoluteRotation()
|
||||||
print("Testing relative movement with absolute rotation...")
|
print("Testing relative movement with absolute rotation...")
|
||||||
|
|
||||||
-- N: BotCenter
|
-- N: BackCenter (Center)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnToDirection(Direction.EAST) -- E: TopCenter
|
self.controller:TurnToDirection(Direction.EAST) -- E: FrontCenter (Center)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnToDirection(Direction.WEST) -- W: TopRight
|
self.controller:TurnToDirection(Direction.WEST) -- W: FrontRight (Center)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveVertical(3)
|
||||||
self.controller:TurnToDirection(Direction.EAST) -- E: TopCenter
|
self.controller:TurnToDirection(Direction.WEST) -- W: FrontRight (Top)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnToDirection(Direction.SOUTH) -- S: TopRight
|
self.controller:TurnToDirection(Direction.SOUTH) -- S: FrontCenter (Top)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveForward(3)
|
||||||
self.controller:TurnToDirection(Direction.WEST) -- W: BotRight
|
self.controller:TurnToDirection(Direction.WEST) -- W: BackCenter (Top)
|
||||||
self.controller:MoveRelative(3)
|
self.controller:MoveVertical(-3)
|
||||||
self.controller:TurnToDirection(Direction.NORTH) -- N: BotCenter
|
self.controller:TurnToDirection(Direction.NORTH) -- N: BackCenter (Center)
|
||||||
|
|
||||||
print("The turtle should be in its original location.")
|
print("The turtle should be in its original location.")
|
||||||
|
print(("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
|
||||||
|
self.controller.position.x, self.controller.position.y, self.controller.position.z, self.controller.position.dir
|
||||||
|
))
|
||||||
print("Press Enter to continue")
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
end
|
end
|
||||||
@ -72,20 +78,18 @@ end
|
|||||||
function TestingController:TestAbsoluteMovementWithoutStack()
|
function TestingController:TestAbsoluteMovementWithoutStack()
|
||||||
print("Testing absolute movement without stack...")
|
print("Testing absolute movement without stack...")
|
||||||
|
|
||||||
-- N: BotCenter
|
-- N: BackCenter (Center)
|
||||||
self.controller:MoveToPosition(0, 0, 3, Direction.EAST) -- E: TopCenter
|
self.controller:MoveToPosition(0, 0, 3, Direction.EAST) -- E: FrontCenter (Center)
|
||||||
_ = io.read()
|
self.controller:MoveToPosition(3, 0, 3, Direction.WEST) -- W: FrontRight (Center)
|
||||||
self.controller:MoveToPosition(3, 0, 3, Direction.WEST) -- W: TopRight
|
self.controller:MoveToPosition(3, 3, 3, Direction.WEST) -- W: FrontRight (Top)
|
||||||
_ = io.read()
|
self.controller:MoveToPosition(0, 3, 3, Direction.SOUTH) -- S: FrontCenter (Top)
|
||||||
self.controller:MoveToPosition(0, 0, 3, Direction.EAST) -- E: TopCenter
|
self.controller:MoveToPosition(0, 3, 0, Direction.WEST) -- W: BackCenter (Top)
|
||||||
_ = io.read()
|
self.controller:MoveToPosition(0, 0, 0, Direction.NORTH) -- N: BackCenter (Center)
|
||||||
self.controller:MoveToPosition(3, 0, 3, Direction.SOUTH) -- S: TopRight
|
|
||||||
_ = io.read()
|
|
||||||
self.controller:MoveToPosition(3, 0, 0, Direction.WEST) -- W: BotRight
|
|
||||||
_ = io.read()
|
|
||||||
self.controller:MoveToPosition(0, 0, 0, Direction.NORTH) -- N: BotCenter
|
|
||||||
|
|
||||||
print("The turtle should be in its original location.")
|
print("The turtle should be in its original location.")
|
||||||
|
print(("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
|
||||||
|
self.controller.position.x, self.controller.position.y, self.controller.position.z, self.controller.position.dir
|
||||||
|
))
|
||||||
print("Press Enter to continue")
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
end
|
end
|
||||||
@ -94,16 +98,16 @@ end
|
|||||||
function TestingController:TestAbsoluteMovementWithStack()
|
function TestingController:TestAbsoluteMovementWithStack()
|
||||||
print("Testing absolute movement with stack...")
|
print("Testing absolute movement with stack...")
|
||||||
|
|
||||||
-- N: BotCenter
|
-- N: BotCenter (Center)
|
||||||
self.controller:MoveToPosition(0, 0, 3, Direction.EAST) -- E: TopCenter
|
self.controller:MoveToPosition(0, 0, 3, Direction.EAST) -- E: TopCenter (Center)
|
||||||
_ = io.read()
|
self.controller:MoveBack() -- N: BotCenter (Center)
|
||||||
self.controller:MoveBack() -- N: BotCenter
|
self.controller:MoveToPosition(3, 3, 3, Direction.WEST) -- W: TopRight (Top)
|
||||||
_ = io.read()
|
self.controller:MoveBack() -- N: BotCenter (Center)
|
||||||
self.controller:MoveToPosition(3, 0, 3, Direction.WEST) -- W: TopRight
|
|
||||||
_ = io.read()
|
|
||||||
self.controller:MoveBack() -- N: BotCenter
|
|
||||||
|
|
||||||
print("The turtle should be in its original location.")
|
print("The turtle should be in its original location.")
|
||||||
|
print(("The turtle has internal position (%d, %d, %d) and internal direction %d"):format(
|
||||||
|
self.controller.position.x, self.controller.position.y, self.controller.position.z, self.controller.position.dir
|
||||||
|
))
|
||||||
print("Press Enter to continue")
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
end
|
end
|
||||||
@ -111,12 +115,13 @@ end
|
|||||||
|
|
||||||
function TestingController:TestUnstocking()
|
function TestingController:TestUnstocking()
|
||||||
print("Testing inventory unloading...")
|
print("Testing inventory unloading...")
|
||||||
print("Please fill multiple inventory slots with items.")
|
|
||||||
_ = io.read()
|
|
||||||
|
|
||||||
self.controller:MoveToPosition(3, 0, 3, Direction.WEST)
|
self.controller:MoveToPosition(3, 0, 3, Direction.WEST)
|
||||||
|
print("Please fill the entire inventory with items.")
|
||||||
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
self.controller:UnstockIfFull(true)
|
self.controller:UnstockIfFull(true)
|
||||||
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
self.controller:MoveBack()
|
self.controller:MoveBack()
|
||||||
|
|
||||||
@ -128,12 +133,13 @@ end
|
|||||||
|
|
||||||
function TestingController:TestRefueling()
|
function TestingController:TestRefueling()
|
||||||
print("Testing refueling...")
|
print("Testing refueling...")
|
||||||
print("Please fill multiple inventory slots with items.")
|
|
||||||
_ = io.read()
|
|
||||||
|
|
||||||
self.controller:MoveToPosition(3, 0, 3, Direction.WEST)
|
self.controller:MoveToPosition(3, 0, 3, Direction.WEST)
|
||||||
|
print("Please fill multiple inventory slots with items.")
|
||||||
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
self.controller:RefuelIfEmpty(true)
|
self.controller:RefuelIfEmpty(true)
|
||||||
|
print("Press Enter to continue")
|
||||||
_ = io.read()
|
_ = io.read()
|
||||||
self.controller:MoveBack()
|
self.controller:MoveBack()
|
||||||
|
|
||||||
@ -150,7 +156,9 @@ end
|
|||||||
|
|
||||||
function TestingController:Run()
|
function TestingController:Run()
|
||||||
self.controller:Configure()
|
self.controller:Configure()
|
||||||
self.controller:DisableMining()
|
self.controller:DisableMiningForward()
|
||||||
|
self.controller:DisableMiningAbove()
|
||||||
|
self.controller:DisableMiningBelow()
|
||||||
|
|
||||||
print("There are multiple tests available:")
|
print("There are multiple tests available:")
|
||||||
print("1: Relative movement with relative rotation")
|
print("1: Relative movement with relative rotation")
|
||||||
|
|||||||
@ -8,15 +8,13 @@ local Stack = require("lib.stack")
|
|||||||
---@field config TurtleControllerConfig
|
---@field config TurtleControllerConfig
|
||||||
---@field position Position
|
---@field position Position
|
||||||
---@field last_positions Stack
|
---@field last_positions Stack
|
||||||
---@field mine boolean
|
---@field mine_forward boolean
|
||||||
|
---@field mine_above boolean
|
||||||
|
---@field mine_below boolean
|
||||||
local TurtleController = {}
|
local TurtleController = {}
|
||||||
TurtleController.__index = TurtleController
|
TurtleController.__index = TurtleController
|
||||||
|
|
||||||
|
|
||||||
-- TODO: StackOverflow once the inventory is full...
|
|
||||||
-- TODO: Test if there's a chest when dropping/sucking/mining (don't mine chests!)
|
|
||||||
|
|
||||||
|
|
||||||
---@return TurtleController
|
---@return TurtleController
|
||||||
function TurtleController:Create()
|
function TurtleController:Create()
|
||||||
local t = {}
|
local t = {}
|
||||||
@ -37,7 +35,9 @@ function TurtleController:Create()
|
|||||||
}
|
}
|
||||||
t.position = Position:Empty()
|
t.position = Position:Empty()
|
||||||
t.last_positions = Stack:Create()
|
t.last_positions = Stack:Create()
|
||||||
t.mine = false
|
t.mine_forward = false
|
||||||
|
t.mine_above = false
|
||||||
|
t.mine_below = false
|
||||||
|
|
||||||
|
|
||||||
return t
|
return t
|
||||||
@ -52,21 +52,19 @@ end
|
|||||||
---Positive numbers turn clockwise, negative numbers turn counterclockwise
|
---Positive numbers turn clockwise, negative numbers turn counterclockwise
|
||||||
---@param number_of_turns number
|
---@param number_of_turns number
|
||||||
function TurtleController:TurnRelative(number_of_turns)
|
function TurtleController:TurnRelative(number_of_turns)
|
||||||
if number_of_turns == 0 then
|
if number_of_turns % 4 == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
self:RefuelIfEmpty()
|
|
||||||
|
|
||||||
-- Turn turtle
|
-- Turn turtle
|
||||||
local turns = number_of_turns % 4
|
local turns = number_of_turns % 4
|
||||||
if turns == 3 then
|
if turns == 3 then
|
||||||
print(("Turtle is turning by %d (shortened to %d)..."):format(number_of_turns, -1))
|
-- print(("Turtle is turning by %d (shortened to %d)..."):format(number_of_turns, -1))
|
||||||
|
|
||||||
-- If we're rotating by 3, we could turn faster by rotating by 1 in the opposite direction
|
-- If we're rotating by 3, we could turn faster by rotating by 1 in the opposite direction
|
||||||
turtle.turnLeft()
|
turtle.turnLeft()
|
||||||
else
|
else
|
||||||
print(("Turtle is turning by %d (shortened to %d)..."):format(number_of_turns, turns))
|
-- print(("Turtle is turning by %d (shortened to %d)..."):format(number_of_turns, turns))
|
||||||
|
|
||||||
for _ = 1,turns do
|
for _ = 1,turns do
|
||||||
turtle.turnRight()
|
turtle.turnRight()
|
||||||
@ -90,31 +88,41 @@ end
|
|||||||
|
|
||||||
---Move forward by a number of blocks depending on the current rotation
|
---Move forward by a number of blocks depending on the current rotation
|
||||||
---@param number_of_blocks number
|
---@param number_of_blocks number
|
||||||
function TurtleController:MoveRelative(number_of_blocks)
|
---@param skip_unstocking boolean | nil
|
||||||
|
---@param skip_refueling boolean | nil
|
||||||
|
function TurtleController:MoveForward(number_of_blocks, skip_unstocking, skip_refueling)
|
||||||
|
skip_unstocking = skip_unstocking or false
|
||||||
|
skip_refueling = skip_refueling or false
|
||||||
if number_of_blocks == 0 then
|
if number_of_blocks == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
print(("Turtle is moving forward by %d blocks..."):format(number_of_blocks))
|
-- print(("Turtle is moving forward by %d blocks..."):format(number_of_blocks))
|
||||||
|
|
||||||
for _ = 1,math.abs(number_of_blocks) do
|
for _ = 1,math.abs(number_of_blocks) do
|
||||||
self:RefuelIfEmpty()
|
if not skip_refueling then
|
||||||
self:UnstockIfFull()
|
self:RefuelIfEmpty()
|
||||||
|
end
|
||||||
|
if not skip_unstocking then
|
||||||
|
self:UnstockIfFull()
|
||||||
|
end
|
||||||
|
|
||||||
-- Break blocks
|
-- Mine/Move
|
||||||
if self.mine then
|
if self.mine_forward then
|
||||||
while not turtle.forward() do
|
while not turtle.forward() do
|
||||||
turtle.dig()
|
turtle.dig()
|
||||||
end
|
end
|
||||||
|
elseif not turtle.forward() then
|
||||||
|
error("Turtle failed to move forward!")
|
||||||
|
end
|
||||||
|
if self.mine_above then
|
||||||
turtle.digUp()
|
turtle.digUp()
|
||||||
|
end
|
||||||
|
if self.mine_below then
|
||||||
turtle.digDown()
|
turtle.digDown()
|
||||||
else
|
|
||||||
if not turtle.forward() then
|
|
||||||
printError("Turtle wants to move without mining but is blocked!")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update current_position
|
-- Update current position
|
||||||
if self.position.dir == Direction.NORTH then
|
if self.position.dir == Direction.NORTH then
|
||||||
self.position.z = self.position.z + 1
|
self.position.z = self.position.z + 1
|
||||||
elseif self.position.dir == Direction.SOUTH then
|
elseif self.position.dir == Direction.SOUTH then
|
||||||
@ -127,35 +135,77 @@ function TurtleController:MoveRelative(number_of_blocks)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Positive numbers move up, negative numbers move down.
|
||||||
|
---@param number_of_blocks number
|
||||||
|
---@param skip_unstocking boolean | nil
|
||||||
|
---@param skip_refueling boolean | nil
|
||||||
|
function TurtleController:MoveVertical(number_of_blocks, skip_unstocking, skip_refueling)
|
||||||
|
skip_unstocking = skip_unstocking or false
|
||||||
|
skip_refueling = skip_refueling or false
|
||||||
|
if number_of_blocks == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- print(("Turtle is moving vertically by %d blocks..."):format(number_of_blocks))
|
||||||
|
|
||||||
|
local move_function = number_of_blocks > 0 and turtle.up or turtle.down
|
||||||
|
local mine_function = number_of_blocks > 0 and turtle.digUp or turtle.digDown
|
||||||
|
local mine_enabled = number_of_blocks > 0 and self.mine_above or self.mine_below
|
||||||
|
|
||||||
|
for _ = 1,math.abs(number_of_blocks) do
|
||||||
|
if not skip_refueling then
|
||||||
|
self:RefuelIfEmpty()
|
||||||
|
end
|
||||||
|
if not skip_unstocking then
|
||||||
|
self:UnstockIfFull()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Mine
|
||||||
|
if mine_enabled then
|
||||||
|
mine_function()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move
|
||||||
|
if not move_function() then
|
||||||
|
error("Turtle failed to move vertically!")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update current position
|
||||||
|
if number_of_blocks > 0 then
|
||||||
|
self.position.y = self.position.y + 1
|
||||||
|
elseif number_of_blocks < 0 then
|
||||||
|
self.position.y = self.position.y - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Stores the current position on the stack so we can return using TurtleController:MoveBack()
|
||||||
|
function TurtleController:StorePosition()
|
||||||
|
self.last_positions:Push(Position:Copy(self.position))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Move to an absolute position. Stores the current position on the stack so we can return using TurtleController:MoveBack()
|
||||||
---@param x number The EAST/WEST axis (grows from WEST to EAST)
|
---@param x number The EAST/WEST axis (grows from WEST to EAST)
|
||||||
---@param y number The UP/DOWN axis (grows from DOWN to UP)
|
---@param y number The UP/DOWN axis (grows from DOWN to UP)
|
||||||
---@param z number The NORTH/SOUTH axis (grows from SOUTH to NORTH)
|
---@param z number The NORTH/SOUTH axis (grows from SOUTH to NORTH)
|
||||||
---@param dir Direction
|
---@param dir Direction
|
||||||
function TurtleController:MoveToPosition(x, y, z, dir)
|
---@param skip_unstocking boolean | nil
|
||||||
print(("Turtle is moving to (%d, %d, %d)..."):format(x, y, z))
|
---@param skip_refueling boolean | nil
|
||||||
|
function TurtleController:MoveToPosition(x, y, z, dir, skip_unstocking, skip_refueling)
|
||||||
|
-- print(("Turtle is moving to (%d, %d, %d)..."):format(x, y, z))
|
||||||
|
|
||||||
self:DisableMining()
|
-- Store the current position on the stack, so we can return using TurtleController:MoveBack()
|
||||||
self.last_positions:Push(Position:Copy(self.position))
|
self.last_positions:Push(Position:Copy(self.position))
|
||||||
|
|
||||||
if self.position.z > 1 then
|
-- EAST/WEST axis (do first to not interfere with chests)
|
||||||
-- Move south once (if we're at the top) to not be blocked by the slice that is currently mined.
|
|
||||||
-- This assumes that we mine the full width back to front.
|
|
||||||
self:TurnToDirection(Direction.SOUTH)
|
|
||||||
self:MoveRelative(1)
|
|
||||||
elseif self.position.z == 0 then
|
|
||||||
-- Move north once (if we're at the bottom) to not be blocked by the chests
|
|
||||||
self:TurnToDirection(Direction.NORTH)
|
|
||||||
self:MoveRelative(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- EAST/WEST axis (do first to not interfere with chests or unmined walls)
|
|
||||||
if self.position.x > x then
|
if self.position.x > x then
|
||||||
self:TurnToDirection(Direction.WEST)
|
self:TurnToDirection(Direction.WEST)
|
||||||
elseif self.position.x < x then
|
elseif self.position.x < x then
|
||||||
self:TurnToDirection(Direction.EAST)
|
self:TurnToDirection(Direction.EAST)
|
||||||
end
|
end
|
||||||
self:MoveRelative(math.abs(self.position.x - x))
|
self:MoveForward(math.abs(x - self.position.x), skip_unstocking, skip_refueling)
|
||||||
|
|
||||||
-- NORTH/SOUTH axis
|
-- NORTH/SOUTH axis
|
||||||
if self.position.z > z then
|
if self.position.z > z then
|
||||||
@ -163,28 +213,47 @@ function TurtleController:MoveToPosition(x, y, z, dir)
|
|||||||
elseif self.position.z < z then
|
elseif self.position.z < z then
|
||||||
self:TurnToDirection(Direction.NORTH)
|
self:TurnToDirection(Direction.NORTH)
|
||||||
end
|
end
|
||||||
self:MoveRelative(math.abs(self.position.z - z))
|
self:MoveForward(math.abs(z - self.position.z), skip_unstocking, skip_refueling)
|
||||||
|
|
||||||
|
-- UP/DOWN axis
|
||||||
|
self:MoveVertical(y - self.position.y, skip_unstocking, skip_refueling)
|
||||||
|
|
||||||
-- Direction
|
-- Direction
|
||||||
self:TurnToDirection(dir or Direction.NORTH)
|
self:TurnToDirection(dir or Direction.NORTH)
|
||||||
|
|
||||||
-- Sanity check
|
-- Sanity check
|
||||||
if not(self.position.x == x and self.position.y == y and self.position.z == z and self.position.dir == dir) then
|
if not(self.position.x == x and self.position.y == y and self.position.z == z and self.position.dir == dir) then
|
||||||
printError("TurtleController:MoveToPosition failed to move to target position!")
|
error("TurtleController:MoveToPosition failed to move to target position!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function TurtleController:MoveBack()
|
---Move by a vector. Stores the current position on the stack so we can return using TurtleController:MoveBack()
|
||||||
local target_position = self.last_positions:Pop()
|
---@param x number The EAST/WEST axis (grows from WEST to EAST)
|
||||||
|
---@param y number The UP/DOWN axis (grows from DOWN to UP)
|
||||||
|
---@param z number The NORTH/SOUTH axis (grows from SOUTH to NORTH)
|
||||||
|
---@param dir Direction
|
||||||
|
---@param skip_unstocking boolean | nil
|
||||||
|
---@param skip_refueling boolean | nil
|
||||||
|
function TurtleController:MoveByVector(x, y, z, dir, skip_unstocking, skip_refueling)
|
||||||
|
self:MoveToPosition(self.position.x + x, self.position.y + y, self.position.z + z, dir, skip_unstocking, skip_refueling)
|
||||||
|
end
|
||||||
|
|
||||||
if target_position == nil then
|
|
||||||
shell.exit()
|
---Move to the previously stored position and pop this position from the stack.
|
||||||
|
---@param skip_unstocking boolean | nil
|
||||||
|
---@param skip_refueling boolean | nil
|
||||||
|
function TurtleController:MoveBack(skip_unstocking, skip_refueling)
|
||||||
|
local last_position = self.last_positions:Pop()
|
||||||
|
|
||||||
|
if last_position == nil then
|
||||||
|
error("Failed to obtain last_position to move back!")
|
||||||
else
|
else
|
||||||
self:MoveToPosition(target_position.x, target_position.y, target_position.z, target_position.dir)
|
self:MoveToPosition(last_position.x, last_position.y, last_position.z, last_position.dir, skip_unstocking, skip_refueling)
|
||||||
|
|
||||||
|
-- Pop the stack because MoveToPosition pushes our current position
|
||||||
self.last_positions:Pop()
|
self.last_positions:Pop()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -193,6 +262,27 @@ end
|
|||||||
-----------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
---@return boolean
|
||||||
|
function TurtleController:HasFuel()
|
||||||
|
local level = turtle.getFuelLevel()
|
||||||
|
local distance_home = self.position.x + self.position.y + self.position.z
|
||||||
|
|
||||||
|
return level > distance_home + self.config.refuel_safety_margin
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---@return boolean
|
||||||
|
function TurtleController:HasInventorySpace()
|
||||||
|
for slot = 1,16 do
|
||||||
|
if turtle.getItemDetail(slot) == nil then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
---@param slot number
|
---@param slot number
|
||||||
---@param count number
|
---@param count number
|
||||||
---@return boolean
|
---@return boolean
|
||||||
@ -241,14 +331,17 @@ function TurtleController:UnstockIfFull(skip_inventory_check)
|
|||||||
if not skip_inventory_check and self:HasInventorySpace() then
|
if not skip_inventory_check and self:HasInventorySpace() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if skip_inventory_check then
|
||||||
|
print(("HasInventorySpace() returned %s"):format(self:HasInventorySpace()))
|
||||||
|
end
|
||||||
|
|
||||||
print("Turtle is unstocking...")
|
print("Turtle is unstocking...")
|
||||||
|
|
||||||
self:MoveToPosition(0, 0, 0, self.config.storage_direction)
|
self:MoveToPosition(0, 0, 0, self.config.storage_direction, true, true)
|
||||||
self:DropInventory()
|
self:DropInventory()
|
||||||
self:RefuelIfEmpty()
|
self:RefuelIfEmpty()
|
||||||
|
|
||||||
self:MoveBack()
|
self:MoveBack(true, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -258,11 +351,14 @@ function TurtleController:RefuelIfEmpty(skip_fuel_check)
|
|||||||
if not skip_fuel_check and self:HasFuel() then
|
if not skip_fuel_check and self:HasFuel() then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if skip_fuel_check then
|
||||||
|
print(("HasFuel() returned %s"):format(self:HasFuel()))
|
||||||
|
end
|
||||||
|
|
||||||
print("Turtle is refueling...")
|
print("Turtle is refueling...")
|
||||||
|
|
||||||
-- Clear our inventory into the storage chest
|
-- Clear our inventory into the storage chest
|
||||||
self:MoveToPosition(0, 0, 0, self.config.storage_direction)
|
self:MoveToPosition(0, 0, 0, self.config.storage_direction, true, true)
|
||||||
self:DropInventory()
|
self:DropInventory()
|
||||||
|
|
||||||
-- Prepare refueling
|
-- Prepare refueling
|
||||||
@ -274,7 +370,7 @@ function TurtleController:RefuelIfEmpty(skip_fuel_check)
|
|||||||
local target_fuel_level = self.config.refuel_amount
|
local target_fuel_level = self.config.refuel_amount
|
||||||
local last_position = self.last_positions:Peek()
|
local last_position = self.last_positions:Peek()
|
||||||
if last_position == nil then
|
if last_position == nil then
|
||||||
shell.exit()
|
error("Failed to obtain last_position while refueling!")
|
||||||
else
|
else
|
||||||
target_fuel_level = target_fuel_level + last_position.x + last_position.y + last_position.z
|
target_fuel_level = target_fuel_level + last_position.x + last_position.y + last_position.z
|
||||||
end
|
end
|
||||||
@ -283,14 +379,13 @@ function TurtleController:RefuelIfEmpty(skip_fuel_check)
|
|||||||
local before_level = turtle.getFuelLevel()
|
local before_level = turtle.getFuelLevel()
|
||||||
repeat
|
repeat
|
||||||
if not self:SuckItem(1, 1) then
|
if not self:SuckItem(1, 1) then
|
||||||
printError("Failed to suck fuel out of fuel chest!")
|
error("Failed to suck fuel out of fuel chest!")
|
||||||
shell.exit()
|
|
||||||
end
|
end
|
||||||
turtle.refuel()
|
turtle.refuel()
|
||||||
until turtle.getFuelLevel() >= target_fuel_level
|
until turtle.getFuelLevel() >= target_fuel_level
|
||||||
local after_level = turtle.getFuelLevel()
|
local after_level = turtle.getFuelLevel()
|
||||||
|
|
||||||
self:MoveBack()
|
self:MoveBack(true, true)
|
||||||
|
|
||||||
print(("Refuelled %d units, current level is %d (old level was %d)"):format(after_level - before_level, after_level, before_level))
|
print(("Refuelled %d units, current level is %d (old level was %d)"):format(after_level - before_level, after_level, before_level))
|
||||||
end
|
end
|
||||||
@ -334,32 +429,34 @@ function TurtleController:Configure()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function TurtleController:EnableMining()
|
function TurtleController:EnableMiningForward()
|
||||||
self.mine = true
|
self.mine_forward = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function TurtleController:DisableMining()
|
function TurtleController:DisableMiningForward()
|
||||||
self.mine = false
|
self.mine_forward = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function TurtleController:HasFuel()
|
function TurtleController:EnableMiningAbove()
|
||||||
local level = turtle.getFuelLevel()
|
self.mine_above = true
|
||||||
local distance_home = self.position.x + self.position.y + self.position.z
|
|
||||||
|
|
||||||
return level > distance_home + self.config.refuel_safety_margin
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function TurtleController:HasInventorySpace()
|
function TurtleController:DisableMiningAbove()
|
||||||
for slot = 1,16 do
|
self.mine_above = false
|
||||||
if turtle.getItemDetail(slot) == nil then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TurtleController:EnableMiningBelow()
|
||||||
|
self.mine_below = true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TurtleController:DisableMiningBelow()
|
||||||
|
self.mine_below = false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
return TurtleController
|
return TurtleController
|
||||||
@ -1,131 +0,0 @@
|
|||||||
local Direction = require("lib.direction")
|
|
||||||
local TurtleController = require("controller.turtle_controller")
|
|
||||||
|
|
||||||
---@alias VolumeExcavationControllerConfig {mine_forward: number, mine_left: number, mine_right: number}
|
|
||||||
|
|
||||||
---@class VolumeExcavationController
|
|
||||||
---@field controller TurtleController
|
|
||||||
---@field config VolumeExcavationControllerConfig
|
|
||||||
local VolumeExcavationController = {}
|
|
||||||
VolumeExcavationController.__index = VolumeExcavationController
|
|
||||||
|
|
||||||
|
|
||||||
---@return VolumeExcavationController
|
|
||||||
function VolumeExcavationController:Create()
|
|
||||||
local t = {}
|
|
||||||
setmetatable(t, VolumeExcavationController)
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Fields
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
t.controller = TurtleController:Create()
|
|
||||||
t.config = {
|
|
||||||
mine_forward = 0,
|
|
||||||
mine_left = 0,
|
|
||||||
mine_right = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Behavior Methods
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function VolumeExcavationController:Excavate()
|
|
||||||
-- Enter the excavation area
|
|
||||||
self.controller:EnableMining()
|
|
||||||
self.controller:MoveRelative(1)
|
|
||||||
|
|
||||||
-- Move to the bottom right corner of the layer
|
|
||||||
self.controller:TurnToDirection(Direction.EAST)
|
|
||||||
self.controller:MoveRelative(self.config.mine_right)
|
|
||||||
self.controller:TurnToDirection(Direction.WEST)
|
|
||||||
|
|
||||||
-- Zig zag mine the full width from back to front
|
|
||||||
-- The direction is important so we can travel to start without colliding with unminded walls
|
|
||||||
local turn_dir = 1
|
|
||||||
for i = 1,self.config.mine_forward do
|
|
||||||
self.controller:MoveRelative(self.config.mine_left + self.config.mine_right)
|
|
||||||
|
|
||||||
-- Skip the last turn, as we won't mine that slice
|
|
||||||
-- We want to stay in the mined area so we can move back freely
|
|
||||||
if i == self.config.mine_forward then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Skip the turning if we're mining in a straight line
|
|
||||||
if self.config.mine_left + self.config.mine_right > 0 then
|
|
||||||
self.controller:TurnRelative(turn_dir)
|
|
||||||
self.controller:MoveRelative(1)
|
|
||||||
self.controller:TurnRelative(turn_dir)
|
|
||||||
end
|
|
||||||
|
|
||||||
turn_dir = -1 * turn_dir
|
|
||||||
end
|
|
||||||
|
|
||||||
self.controller:MoveToPosition(0, 0, 0, Direction.NORTH)
|
|
||||||
|
|
||||||
-- Unload before doing the next layer
|
|
||||||
self.controller:TurnToDirection(self.controller.config.storage_direction)
|
|
||||||
self.controller:DropInventory()
|
|
||||||
self.controller:TurnToDirection(Direction.NORTH)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Management Methods
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function VolumeExcavationController:Configure()
|
|
||||||
local config_complete = false
|
|
||||||
|
|
||||||
while not config_complete do
|
|
||||||
print("How many blocks should the turtle mine forward?")
|
|
||||||
self.config.mine_forward = tonumber(io.read()) or 3
|
|
||||||
|
|
||||||
print("How many blocks should the turtle to its right?")
|
|
||||||
self.config.mine_right = tonumber(io.read()) or 3
|
|
||||||
|
|
||||||
print("How many blocks should the turtle mine to its left?")
|
|
||||||
self.config.mine_left = tonumber(io.read()) or 3
|
|
||||||
|
|
||||||
local width = self.config.mine_left + self.config.mine_right + 1
|
|
||||||
local height = 3
|
|
||||||
|
|
||||||
print("Configuration complete!")
|
|
||||||
print(("Turtle will mine an area of %d x %d x %d (forward x width x height) totalling %d blocks."):format(
|
|
||||||
self.config.mine_forward, width, height, self.config.mine_forward * width * height
|
|
||||||
))
|
|
||||||
print("Do you want to accept the configuration (enter 1, otherwise 0)?")
|
|
||||||
config_complete = tonumber(io.read()) == 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
-- Main Method
|
|
||||||
-----------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
function VolumeExcavationController:Run()
|
|
||||||
self.controller:Configure()
|
|
||||||
self:Configure()
|
|
||||||
|
|
||||||
-- Consume our starting fuel and refuel to the full amount
|
|
||||||
turtle.select(1)
|
|
||||||
turtle.refuel()
|
|
||||||
self.controller:RefuelIfEmpty()
|
|
||||||
|
|
||||||
self:Excavate()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return VolumeExcavationController
|
|
||||||
18
main.lua
18
main.lua
@ -1,18 +1,15 @@
|
|||||||
local TestingController = require("controller.testing_controller")
|
local TestingController = require("controller.testing_controller")
|
||||||
local VolumeExcavationController = require("controller.volume_excavation_controller")
|
local ExcavationController = require("controller.excavation_controller")
|
||||||
local NetheriteController = require("controller.netherite_controller")
|
|
||||||
|
|
||||||
|
|
||||||
local controllers = {
|
local controllers = {
|
||||||
TestingController:Create(),
|
TestingController:Create(),
|
||||||
VolumeExcavationController:Create(),
|
ExcavationController:Create(),
|
||||||
NetheriteController:Create(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Multiple controllers are available:")
|
print("Multiple controllers are available:")
|
||||||
print("1: Testing Mode")
|
print("1: Testing Mode")
|
||||||
print("2: Volume Excavation")
|
print("2: Volume Excavation")
|
||||||
print("3: Netherite Excavation")
|
|
||||||
|
|
||||||
local choice = 0
|
local choice = 0
|
||||||
while choice < 1 or choice > #controllers do
|
while choice < 1 or choice > #controllers do
|
||||||
@ -20,4 +17,13 @@ while choice < 1 or choice > #controllers do
|
|||||||
choice = tonumber(io.read()) or 0
|
choice = tonumber(io.read()) or 0
|
||||||
end
|
end
|
||||||
|
|
||||||
controllers[choice]:Run()
|
controllers[choice]:Run()
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: StackOverflow once the inventory is full, unstocking doesn't work...
|
||||||
|
-- Is the InventoryFull check wrong?
|
||||||
|
-- TODO: Test if there's a chest when dropping/sucking/mining (don't mine chests!)
|
||||||
|
-- TODO: Add controller to build rooms with walls of a specified material
|
||||||
|
-- TODO: Support specifying the mining height
|
||||||
|
-- TODO: Add configurable trash_list with items that won't be picked up
|
||||||
|
-- TODO: Add a speaker to the turtle (listen to music while mining)
|
||||||
Reference in New Issue
Block a user