commit fd40a52ddc66a47ea43f3bcf93637c64c0517f68 Author: Guillaume ARM Date: Wed May 8 18:27:47 2024 +0200 chore: save diff --git a/miner.lua b/miner.lua new file mode 100644 index 0000000..7266051 --- /dev/null +++ b/miner.lua @@ -0,0 +1,241 @@ +local robotApi = require('robot') +local turtleUtils = require('turtle-utils') + +local config = { + startY = 109, + targetY = 109, + height = 1, + size = 4 +} + +local TARGET_Y = config.targetY - config.startY +local TARGET_Z = config.size - 1 +local TARGET_X = config.size - 1 + +local MAX_X = TARGET_X +local MAX_Y = TARGET_Y + (config.height - 1) +local MAX_Z = TARGET_Z + +local LOWER_LIMIT = 2; +local HIGHER_LIMIT = 128; + +local robot = robotApi.create() + +local MAX_INVENTORY_BLOCKS = 16 * 64 +local ADDITIONAL_FUEL_NEEDED = 512 +local MIN_FUEL_NEEDED = (size * 2) + TARGET_Y + MAX_INVENTORY_BLOCKS + ADDITIONAL_FUEL_NEEDED + +local miner = { + robot = robot, + mission = 'unload', -- "unload" | "refuel" | "mine" | "return-home" | "return-mine" | nil + finished = false + lastPositionState = nil -- { x, y, z, dir } +} + +local function isOdd(x) + return (x % 2) == 1 +end + +local function checkConfig() + if config.targetY > config.startY then + error('targetY cannot be higher that startY') + end + + if config.height < 1 then + error('height cannot be lower than 1') + end + + if config.size < LOWER_LIMIT then + error('size cannot be lower than ' .. LOWER_LIMIT) + end + + if config.size > HIGHER_LIMIT then + error('size is too large (higher limit is ' .. HIGHER_LIMIT .. ')') + end + + if isOdd(config.size) then + error('configured size should be even') + end +end + +local function prepareTurtle() + turtle.select(1) +end + +local function isProgramFinished() + if miner.mission ~= nil then + return false + end + + local robotState = miner.robot.getSate() + + return robotState.x == 0 and robotState.y == 0 and robotState.z == 0 +end + + +local function unloadProcedure() + print('> Starting unload procedure...') + turtleUtils.waitForInventory('front') + + for i=1, 16, 1 do + turtle.select(i) + turtleUtils.tryDrop() + end + + turtle.select(1) + + miner.mission = 'refuel' +end + +local function refuelProcedure() + print('> Starting refuel procedure (' .. turtleUtils.getFuelPercentage() .. '%)') + turtleUtils.waitForInventory('top') + + turtle.select(1) + + while turtle.getFuelLevel() < MIN_FUEL_NEEDED do + turtleUtils.trySuckUp() + + local ok = turtle.refuel() + if not ok then + turtleUtils.tryDrop() + end + end + + print('> Refuel done.') + miner.mission = 'return-mine' +end + +local function returnMineProcedure() + if miner.robot.finished then + miner.mission = nil -- it will stop the loop + return + end + + if robot.lastPositionState then + local robotState = miner.robot.getState() + + if robotState.y > miner.lastPositionState.y then + miner.robot.down() + elseif robotState.z < miner.lastPositionState.z then + miner.robot.forward() + else + miner.robot.turnRight() + + for i=1, miner.lastPositionState.x, 1 do + miner.robot.forward() + end + + while miner.robot.getState().dir ~= miner.lastPositionState.dir do + miner.robot.turnRight() + end + + miner.mission = 'mine' + end + else + miner.mission = 'mine' + end +end + +local function mineProcedure() + print('> Starting mine procedure...') + local robotState = miner.robot.getState() + local targetY = TARGET_Y + local targetZ = TARGET_Z + + -- 1. Move + if robotState.y > targetY then + turtle.digDown() + miner.robot.down() + elseif robotState.dir == 'FORWARD' and robotState.z < targetZ then + turtleUtils.digAll() + miner.robot.forward() + elseif robotState.dir == 'FORWARD' and robotState.z == targetZ then + miner.robot.turnRight() + turtleUtils.digAll() + miner.robot.forward() + miner.robot.turnRight() + elseif robotState.dir == 'BACKWARD' and robotState.z > 0 then + turtleUtils.digAll() + miner.robot.forward() + elseif robotState.dir == 'BACKWARD' and robotState.z == 0 then + miner.robot.turnLeft() + turtleUtils.digAll() + miner.robot.forward() + miner.robot.turnLeft() + end + + -- 2. Check + if robotState.x == MAX_X and robotState.y == MAX_Y and robotState.z == MAX_Z then + miner.finished = true + miner.mission = 'return-home' + miner.lastPositionState = miner.robot.getState() + elseif robotState.x == MAX_X and robotState.z == MAX_Z then + -- this part assume that the size of the mine is even + miner.robot.turnRight() + + for i=1, config.size - 1, 1 do + miner.robot.forward() + end + + miner.robot.turnRight() + miner.robot.up() + end + + if turtleUtils.countFreeSlots() < 1 then + miner.mission = 'return-home' + miner.lastPositionState = miner.robot.getState() + end +end + +local function returnHomeProcedure() + print('> Starting return home procedure...') + local robotState = miner.robot.getState() + + if robotState.x == 0 and robotState.y == 0 and robotState.z == 0 then + miner.mission = 'unload' + elseif robotState.x == 0 and robotState.z == 0 then + miner.robot.up() + elseif robotState.x > 0 then + if robotState.dir == 'FORWARD' then + miner.robot.turnLeft() + elseif robotState.dir == 'BACKWARD' then + miner.robot.turnRight() + end + + for i=1, robotState.x, 1 do + miner.robot.forward() + end + + miner.robot.turnLeft() + elseif robotState.z > 0 then + for i=1, robotState.z, 1 do + miner.robot.forward() + end + + miner.robot.turnLeft() + miner.robot.turnLeft() + end +end + + +checkConfig() +prepareTurtle() + +print("> Miner program started, minimum fuel needed: " .. MIN_FUEL_NEEDED) + +while not isProgramFinished() do + if miner.mission == 'unload' then + unloadProcedure() + elseif miner.mission == 'refuel' then + refuelProcedure() + elseif miner.mission == 'mine' then + mineProcedure() + elseif miner.mission == 'return-home' then + returnHomeProcedure() + elseif miner.mission == 'return-mine' then + returnMineProcedure() + end +end + +print("> Miner program finished!") \ No newline at end of file diff --git a/robot.lua b/robot.lua new file mode 100644 index 0000000..02d44e0 --- /dev/null +++ b/robot.lua @@ -0,0 +1,114 @@ +-- robot api + +local api = {} + +api.create = function() + local state = { + y = 0, + x = 0, + z = 0, + -- | BACKWARD | LEFT | RIGHT + dir = 'FORWARD' + } + + local mutateRobotPosition = function(isBackward) + local incValue = 1 + if isBackward then invValue = -1 end + + if dir == 'FORWARD' then + state.z = state.z + incValue + elseif dir == 'BACKWARD' then + state.z = state.z - incValue + elseif dir == 'LEFT' then + state.x = state.x - incValue + elseif dir == 'RIGHT' then + state.x = state.x + incValue + end + end + + local robot = {} + + robot.forward = function() + local ok, err = turtle.forward() + + if ok then + mutateRobotPosition(false) + end + + return ok, err + end + + robot.backward = function() + local ok, err = turtle.back() + + if ok then + mutateRobotPosition(true) + end + + return ok, err + end + + robot.up = function() + local ok, err = turtle.up() + + if ok then + state.y = state.y + 1 + end + + return ok, err + end + + robot.down = function() + local ok, err = turtle.down() + + if ok then + state.y = state.y - 1 + end + + return ok, err + end + + robot.turnLeft = function() + local ok, err = turtle.turnLeft() + + if ok then + if state.dir == 'FORWARD' then + state.dir = 'LEFT' + elseif state.dir == 'LEFT' then + state.dir = 'BACKWARD' + elseif state.dir == 'RIGHT' then + state.dir = 'FORWARD' + elseif state.dir == 'BACKWARD' then + state.dir = 'RIGHT' + end + end + + return ok, err + end + + robot.turnRight = function() + local ok, err = turtle.turnRight() + + if ok then + if state.dir == 'FORWARD' then + state.dir = 'RIGHT' + elseif state.dir == 'LEFT' then + state.dir = 'FORWARD' + elseif state.dir == 'RIGHT' then + state.dir = 'BACKWARD' + elseif state.dir == 'BACKWARD' then + state.dir = 'LEFT' + end + end + + return ok, err + end + + robot.getState = function() + return state + end + + return robot +end + +return api \ No newline at end of file diff --git a/turtle-utils.lua b/turtle-utils.lua new file mode 100644 index 0000000..90f74a2 --- /dev/null +++ b/turtle-utils.lua @@ -0,0 +1,53 @@ +local turtleUtils = {} + +local IDLE_TIME = 2 + +turtleUtils.waitForInventory = function(side) + local inv = nil + + while true do + inv = peripheral.wrap(side) + + if inv and peripheral.hasType(inv, 'inventory') then + break + end + + os.sleep(IDLE_TIME) + end + + return inv +end + +turtleUtils.trySuckUp = function() + while not turtle.suckUp() do + os.sleep(IDLE_TIME) + end +end + +turtleUtils.tryDrop = function() + while not turtle.drop() do + os.sleep(IDLE_TIME) + end +end + +turtleUtils.digAll = function() + while turtle.dig() do end +end + +turtleUtils.countFreeSlots = function() + local freeSlots = 0 + + for i=1, 16, 1 do + if turtle.getItemCount(i) == 0 then + freeSlots = freeSlots + 1 + end + end + + return freeSlots +end + +turtleUtils.getFuelPercentage = function() + return (turtle.getFuelLevel() / turtle.getFuelLimit()) * 100 +end + +return turtleUtils \ No newline at end of file