From 625f67182105e070cc315985aab2668e49e5a966 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Sat, 17 Dec 2022 16:15:34 +0100 Subject: [PATCH] Moved item stuff to itemscript. --- install.lua | 10 +++ itemscript.lua | 89 +++++++++++++++++++++++ movescript.lua | 194 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 install.lua create mode 100644 itemscript.lua create mode 100644 movescript.lua diff --git a/install.lua b/install.lua new file mode 100644 index 0000000..f059ac1 --- /dev/null +++ b/install.lua @@ -0,0 +1,10 @@ +--[[ +Installation script for installing all libraries. + +Run `wget run https://github.com/andrewlalis/movescript/blob/main/install.lua` +to run the installer on your device. +]]-- + +BASE_URL = "https://github.com/andrewlalis/movescript/blob/main" + +shell.run("wget " .. BASE_URL .. "/movescript.lua") diff --git a/itemscript.lua b/itemscript.lua new file mode 100644 index 0000000..0a0f9a6 --- /dev/null +++ b/itemscript.lua @@ -0,0 +1,89 @@ +--[[ +Itemscript - A simplified set of methods for item manipulation. + +Author: Andrew Lalis + + +]]-- +local t = turtle + +-- The itemscript module. Functions defined within this table are exported. +local itemscript = {} + +local function itemStackMatches(itemStack, name, fuzzy) + return itemStack ~= nil and + ( + (not fuzzy and itemStack.name == name) or + string.find(itemStack.name, name) + ) +end + +-- Gets the total number of items of a certain type in the turtle's inventory. +-- If fuzzy is set as true, then it'll match substrings matching the given name. +function itemscript.totalCount(name, fuzzy) + fuzzy = fuzzy or false + local count = 0 + for i = 1, 16 do + local item = t.getItemDetail(i) + if itemStackMatches(item, name, fuzzy) then + count = count + item.count + end + end + return count +end + +-- Selects a slot containing at least one of the given item type. +-- Returns a boolean indicating whether we could find and select the item. +function itemscript.select(name, fuzzy) + fuzzy = fuzzy or false + for i = 1, 16 do + local item = t.getItemDetail(i) + if itemStackMatches(item, name, fuzzy) then + t.select(i) + return true + end + end + return false +end + +local function itemMatchesFilter(item, name, fuzzy) + fuzzy = fuzzy or false + return (not fuzzy and item.name == name) or string.find(item.name, name) +end + +local function itemNotMatchesFilter(item, name, fuzzy) + return not itemMatchesFilter(item, name, fuzzy) +end + +local function dropFiltered(name, fuzzy, dropFunction, filterFunction) + for i = 1, 16 do + local item = t.getItemDetail(i) + if filterFunction(item, name, fuzzy) then + t.select(i) + dropFunction() + end + end +end + +function itemscript.dropAll(name, fuzzy) + dropFiltered(name, fuzzy or false, t.drop, itemMatchesFilter) +end + +function itemscript.dropAllDown(name, fuzzy) + dropFiltered(name, fuzzy or false, t.dropDown, itemMatchesFilter) +end + +function itemscript.dropAllUp(name, fuzzy) + dropFiltered(name, fuzzy or false, t.dropDown, itemMatchesFilter) +end + +function itemscript.dropAllExcept(name, fuzzy) + dropFiltered(name, fuzzy or false, t.drop, itemMatchesFilter) +end + +-- Cleans up the turtle's inventory by compacting all stacks of items. +function itemscript.organize() + error("Not yet implemented.") +end + +return itemscript \ No newline at end of file diff --git a/movescript.lua b/movescript.lua new file mode 100644 index 0000000..03db8d3 --- /dev/null +++ b/movescript.lua @@ -0,0 +1,194 @@ +--[[ +Movescript - A simplified robot script for ComputerCraft. + +Author: Andrew Lalis + +Movescript provides a simpler, conciser way to program "turtles" (robots), so +that you don't need to get tired of typing "turtle.forward()" over and over. + +]]-- +local t = turtle + +-- The movescript module. Functions defined within this table are exported. +local movescript = {} + +local function debug(msg, settings) + if settings and settings.debug then + print("[MS] " .. msg) + end +end + +-- Helper function for turtle to dig backwards. +function t.digBack(side) + t.turnRight() + t.turnRight() + t.dig(side) + t.turnRight() + t.turnRight() +end + +-- Helper function for turtle to detect backwards. +function t.detectBack() + t.turnRight() + t.turnRight() + local result = t.detect() + t.turnRight() + t.turnRight() + return result +end + +-- The default settings to apply to any robot movement, if none are specified. +local defaultMovementSettings = { + safe = true, + destructive = false, + fuels = {"minecraft:coal", "minecraft:charcoal"} +} + +local function goDirection(dirFunction, digFunction, detectFunction, settings) + settings = settings or defaultMovementSettings + safe = settings.safe or defaultMovementSettings.safe + destructive = settings.destructive or defaultMovementSettings.destructive + local success = dirFunction() + if not safe then return end + while not success do + debug("Unable to move.", settings) + if destructive and detectFunction() then + debug("Detected a block in the way; attempting to remove it.", settings) + digFunction() + end + success = dirFunction() + end +end + +local function goUp(settings) + debug("Moving up.", settings) + goDirection(t.up, t.digUp, t.detectUp, settings) +end + +local function goDown(settings) + debug("Moving down.", settings) + goDirection(t.down, t.digDown, t.detectDown, settings) +end + +local function goForward(settings) + debug("Moving forward.", settings) + goDirection(t.forward, t.dig, t.detect, settings) +end + +local function goBack(settings) + debug("Moving back.", settings) + goDirection(t.back, t.digBack, t.detectBack, settings) +end + +local function goRight(settings) + debug("Turning right.", settings) + t.turnRight() +end + +local function goLeft(settings) + debug("Turning left.", settings) + t.turnLeft() +end + +local actionMap = { + ["U"] = {f = goUp, needsFuel = true}, + ["D"] = {f = goDown, needsFuel = true}, + ["L"] = {f = goLeft, needsFuel = false}, + ["R"] = {f = goRight, needsFuel = false}, + ["F"] = {f = goForward, needsFuel = true}, + ["B"] = {f = goBack, needsFuel = true}, + ["P"] = {f = t.place, needsFuel = false}, + ["Pu"] = {f = t.placeUp, needsFuel = false}, + ["Pd"] = {f = t.placeDown, needsFuel = false}, + ["A"] = {f = t.attack, needsFuel = false}, + ["Au"] = {f = t.attackUp, needsFuel = false}, + ["Ad"] = {f = t.attackDown, needsFuel = false} +} + +-- Tries to refuel the turtle from all slots that contain a valid fuel. +-- Returns a boolean indicating if at least one piece of fuel was consumed. +local function refuelAll(settings) + debug("Refueling...", settings) + local fuels = settings.fuels or defaultMovementSettings.fuels + local refueled = false + for slot = 1, 16 do + local item = t.getItemDetail(slot) + for _, fuelName in pairs(fuels) do + if item.name == fuelName then + t.select(i) + if t.refuel(item.count) then refueled = true end + break + end + end + end + return refueled +end + +-- Blocks until the turtle's fuel level is at least at the required level. +local function refuelToAtLeast(requiredLevel, settings) + refuelAll(settings) + while t.getFuelLevel < requiredLevel do + print( + "[MS] Fuel level is too low. Level: " .. t.getFuelLevel() .. ". Required: " .. requiredLevel .. + ". Please add some of the following fuels:" + ) + local fuels = settings.fuels or defaultMovementSettings.fuels + for _, fuelName in pairs(fuels) do + print(" - " .. fuelName) + end + local fuelUpdated = false + while not fuelUpdated do + os.pullEvent("turtle_inventory") + fuelUpdated = refuelAll() + end + end +end + +-- Executes a single instruction. An instruction is a table with an "action" +-- and some attributes, such as if it needs fuel or not. +local function executeInstruction(instruction, settings) + local action = actionMap[instruction.action] + if action then + debug("Executing action \"" .. instruction.action .. "\" " .. instruction.count .. " times.", settings) + if action.needsFuel and instruction.count > t.getFuelLevel() then + local fuelRequired = instruction.count + refuelToAtLeast(fuelRequired, settings) + end + for i = 1, instruction.count do action.f() end + end +end + +-- Parses a movescript script into a series of instruction tables. +local function parseScript(script, settings) + local instructions = {} + for instruction in string.gfind(script, "%W*(%d*%u%l*)%W*") do + local countIdx, countIdxEnd = string.find(instruction, "%d+") + local actionIdx, actionIdxEnd = string.find(instruction, "%u%l*") + local count = 1 + if countIdx ~= nil then + count = tonumber(string.sub(instruction, countIdx, countIdxEnd)) + end + local action = string.sub(instruction, actionIdx, actionIdxEnd) + if count < 1 or count > t.getFuelLimit() then + error("Instruction at index " .. actionIdx .. " has an invalid count of " .. count .. ". It should be >= 1 and <= " .. t.getFuelLimit()) + end + if actionMap[action] == nil then + error("Instruction at index " .. actionIdx .. ", \"" .. action .. "\", does not refer to a valid action.") + end + table.insert(instructions, {action = action, count = count}) + debug("Parsed instruction: " .. instruction, settings) + end + return instructions +end + +function movescript.run(script, settings) + settings = settings or defaultMovementSettings + script = script or "" + debug("Executing script: " .. script, settings) + local instructions = parseScript(script, settings) + for idx, instruction in pairs(instructions) do + executeInstruction(instruction, settings) + end +end + +return movescript