Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local vec3 = {}
- vec3.__index = vec3
- -- The constructor for a new vec3 object.
- -- @param x The x-component (number).
- -- @param y The y-component (number).
- -- @param z The z-component (number).
- -- @return A new vec3 object.
- function vec3.new(x, y, z)
- -- Create a new table for the vector.
- local newVec = {
- x = x or 0,
- y = y or 0,
- z = z or 0
- }
- -- Set its metatable to the vec3 type, allowing it to
- -- inherit methods and use operator overloading.
- return setmetatable(newVec, vec3)
- end
- -- Metamethod for the addition operator (+).
- -- This is called when you use the '+' operator on two vec3 objects.
- -- @param a The first vector.
- -- @param b The second vector.
- -- @return A new vector that is the sum of the two.
- function vec3.__add(a, b)
- return vec3.new(a.x + b.x, a.y + b.y, a.z + b.z)
- end
- -- Metamethod for converting the vector to a string.
- -- This is useful for printing the vector's values.
- -- @param v The vector to be converted.
- -- @return A formatted string representation of the vector.
- function vec3.__tostring(v)
- return string.format("vec3(x:%.2f, y:%.2f, z:%.2f)", v.x, v.y, v.z)
- end
- function vec3.serialize(v)
- return { typeid = "vec3", x = v.x, y = v.y, z = v.z }
- end
- local Stack = {}
- Stack.__index = Stack
- --[[
- Creates and returns a new Stack object.
- This is the constructor function.
- ]]
- function Stack.new()
- local self = {
- -- The internal data storage for the stack.
- -- We use a table to hold the elements.
- data = {}
- }
- -- Set up the metatable so that new instances can use the Stack methods.
- return setmetatable(self, Stack)
- end
- --[[
- Adds an element to the top of the stack.
- @param self The Stack object instance.
- @param element The element to add to the stack.
- ]]
- function Stack:push(element)
- -- The # operator gets the number of elements in the table (size).
- -- We add the new element at the next available index.
- self.data[#self.data + 1] = element
- end
- --[[
- Removes and returns the element at the top of the stack.
- Returns nil if the stack is empty.
- @param self The Stack object instance.
- @return The element that was removed, or nil.
- ]]
- function Stack:pop()
- if self:isEmpty() then
- return nil
- end
- -- Get the current top element.
- local topElement = self.data[#self.data]
- -- Remove the top element from the table.
- self.data[#self.data] = nil
- return topElement
- end
- --[[
- Returns the element at the top of the stack without removing it.
- Returns nil if the stack is empty.
- @param self The Stack object instance.
- @return The top element, or nil.
- ]]
- function Stack:peek()
- if self:isEmpty() then
- return nil
- end
- -- Simply return the element at the top.
- return self.data[#self.data]
- end
- --[[
- Checks if the stack is empty.
- @param self The Stack object instance.
- @return true if the stack is empty, false otherwise.
- ]]
- function Stack:isEmpty()
- -- The stack is empty if its size is 0.
- return #self.data == 0
- end
- --[[
- Returns the number of elements currently in the stack.
- @param self The Stack object instance.
- @return The size of the stack.
- ]]
- function Stack:size()
- return #self.data
- end
- function Stack:serialize()
- local data = self.data.map(function(v)
- if v.serialize then
- return v.serialize()
- end
- return v
- end)
- return { typeid = "stack", data = table.concat(data, ",") }
- end
- --- Set.lua
- -- A module for creating and manipulating Set data structures in Lua.
- -- Sets are implemented using Lua tables, where elements are keys.
- -- This provides O(1) average time complexity for add, remove, and contains operations.
- local Set = {}
- Set.__index = Set
- --- Creates a new empty set.
- -- @return table A new set instance.
- function Set.new()
- local newSet = {}
- -- Use a metatable to give the set object a custom type and methods.
- return setmetatable(newSet, Set)
- end
- --- Adds an element to the set.
- -- @param self table The set instance.
- -- @param element any The element to add.
- function Set:add(element)
- self[element] = true
- end
- --- Removes an element from the set.
- -- @param self table The set instance.
- -- @param element any The element to remove.
- function Set:remove(element)
- self[element] = nil
- end
- --- Checks if an element is in the set.
- -- @param self table The set instance.
- -- @param element any The element to check for.
- -- @return boolean True if the element is in the set, false otherwise.
- function Set:contains(element)
- return self[element] ~= nil
- end
- --- Returns the number of elements in the set.
- -- This iterates over the table, so it's O(n) complexity.
- -- For simple use cases, this is fine, but for performance-critical scenarios,
- -- you might want to maintain a separate count variable.
- -- @param self table The set instance.
- -- @return number The number of elements.
- function Set:size()
- local count = 0
- for _ in pairs(self) do
- count = count + 1
- end
- return count
- end
- --- Returns an iterator for the elements in the set.
- -- @param self table The set instance.
- -- @return function An iterator function.
- function Set:elements()
- local i = 0
- local keys = {}
- for k in pairs(self) do
- keys[#keys + 1] = k
- end
- return function()
- i = i + 1
- return keys[i]
- end
- end
- --- Creates a new set that is the union of two sets.
- -- @param self table The first set.
- -- @param otherSet table The second set.
- -- @return table The new set containing all elements from both sets.
- function Set:union(otherSet)
- local newSet = Set.new()
- for k in pairs(self) do
- newSet:add(k)
- end
- for k in pairs(otherSet) do
- newSet:add(k)
- end
- return newSet
- end
- --- Creates a new set that is the intersection of two sets.
- -- @param self table The first set.
- -- @param otherSet table The second set.
- -- @return table The new set containing only elements common to both sets.
- function Set:intersection(otherSet)
- local newSet = Set.new()
- for k in pairs(self) do
- if otherSet:contains(k) then
- newSet:add(k)
- end
- end
- return newSet
- end
- --- Creates a new set that is the difference of two sets (self - otherSet).
- -- @param self table The first set.
- -- @param otherSet table The second set.
- -- @return table The new set containing elements in the first set but not the second.
- function Set:difference(otherSet)
- local newSet = Set.new()
- for k in pairs(self) do
- if not otherSet:contains(k) then
- newSet:add(k)
- end
- end
- return newSet
- end
- --- Checks if this set is a subset of another set.
- -- @param self table The potential subset.
- -- @param otherSet table The potential superset.
- -- @return boolean True if the first set is a subset of the second, false otherwise.
- function Set:is_subset(otherSet)
- for k in pairs(self) do
- if not otherSet:contains(k) then
- return false
- end
- end
- return true
- end
- function Set:serialize()
- local data = self.map(function(v)
- if v.serialize then
- return v.serialize()
- end
- return v
- end)
- return { typeid = "set", data = table.concat(data, ",") }
- end
- -- MISC
- function sign(x)
- if x > 0 then
- return 1
- elseif x < 0 then
- return -1
- else
- return 0
- end
- end
- function table.map(f, t)
- local r = {}
- for i, v in ipairs(t) do
- r[i] = f(v)
- end
- return r
- end
- -- State Saving
- function Deserialize(data)
- if (data.typeid == "stack") then
- local stack = Stack.new()
- for i, v in ipairs(data.data:split(",")) do
- stack:push(Deserialize(v))
- end
- return stack
- elseif (data.typeid == "vec3") then
- return vec3.new(data.x, data.y, data.z)
- elseif (data.typeid == "set") then
- local set = Set.new()
- for i, v in ipairs(data.data:split(",")) do
- set:add(Deserialize(v))
- end
- return set
- end
- return data
- end
- function SaveState()
- local r = fs.open("resume", "w")
- r.write(path)
- r.close()
- local f = fs.open("save", "w")
- f.write(textutils.serialize(STATE))
- f.flush()
- f.close()
- end
- function LoadState()
- if not fs.exists("save") then
- return
- end
- local f = fs.open("save", "r")
- _G.STATE = Deserialize(textutils.unserialize(f.readAll()))
- f.close()
- resume()
- end
- function resume()
- if GetReturning() then
- ReturnHome()
- end
- if GetVeinMining() then
- moveto(GetVeinInitialPos())
- SetVeinMining(false)
- end
- print("Resuming Operation")
- end
- STATE = {}
- function UseState(key, initial)
- return function()
- if _G.STATE == nil then
- _G.STATE = {}
- end
- if _G.STATE[key] == nil then
- _G.STATE[key] = initial
- end
- return _G.STATE[key]
- end, function(v)
- _G.STATE[key] = v
- end
- end
- GetPosition, SetPosition = UseState("Position", vec3.new(0, 0, 0))
- GetFacing, SetFacing = UseState("Facing", 0)
- FORWARD = 0
- RIGHT = 1
- BACK = 2
- LEFT = 3
- DOWN = 4
- UP = 5
- function DirToString(dir)
- if dir == UP then
- return "UP"
- elseif dir == DOWN then
- return "DOWN"
- elseif dir == FORWARD then
- return "FORWARD"
- elseif dir == BACK then
- return "BACK"
- elseif dir == LEFT then
- return "LEFT"
- elseif dir == RIGHT then
- return "RIGHT"
- end
- return "UNKNOWN"
- end
- function DirToVec(dir)
- if dir == UP then
- return vec3.new(0, 0, 1)
- elseif dir == DOWN then
- return vec3.new(0, 0, -1)
- elseif dir == FORWARD then
- return vec3.new(1, 0, 0)
- elseif dir == BACK then
- return vec3.new(-1, 0, 0)
- elseif dir == LEFT then
- return vec3.new(0, -1, 0)
- elseif dir == RIGHT then
- return vec3.new(0, 1, 0)
- end
- end
- function VecToDir(vec)
- if vec.x > 0 and vec.y == 0 and vec.z == 0 then
- return FORWARD;
- end
- if vec.x < 0 and vec.y == 0 and vec.z == 0 then
- return BACK;
- end
- if vec.x == 0 and vec.y < 0 and vec.z == 0 then
- return LEFT;
- end
- if vec.x == 0 and vec.y > 0 and vec.z == 0 then
- return RIGHT;
- end
- return GetFacing()
- end
- function getMoveDir(mx, my)
- return VecToDir(vec3.new(mx, my, 0))
- end
- function rotate(dir)
- if dir == UP or dir == DOWN then
- return
- end
- while not (dir == GetFacing()) do
- if dir < GetFacing() then
- turtle.turnLeft()
- SetFacing(GetFacing() - 1)
- else
- turtle.turnRight()
- SetFacing(GetFacing() + 1)
- end
- end
- end
- function move(mx, my, mz, destructive)
- destructive = destructive or true
- print("Moving " .. mx .. ", " .. my .. ", " .. mz)
- function mv(z)
- function step()
- if z == "UP" then
- return turtle.up()
- elseif z == "DOWN" then
- return turtle.down()
- elseif z == "FORWARD" then
- return turtle.forward()
- end
- end
- function dig()
- if z == "UP" then
- turtle.digUp()
- turtle.attackUp()
- elseif z == "DOWN" then
- turtle.digDown()
- turtle.attackDown()
- elseif z == "FORWARD" then
- turtle.dig()
- turtle.attack()
- end
- end
- while not step() do
- if destructive then
- dig()
- end
- sleep(0.1)
- end
- checkReturn()
- checkInv()
- if not GetReturning() then
- checkForWorth(GetFacing())
- checkForWorth(UP)
- checkForWorth(DOWN)
- end
- end
- if not (mx == 0) then
- rotate(getMoveDir(mx, 0))
- local dist = math.abs(mx);
- while not (dist == 0) do
- dist = dist - 1;
- mv("FORWARD")
- SetPosition(GetPosition() + vec3.new(sign(mx), 0, 0))
- end
- end
- if not (my == 0) then
- rotate(getMoveDir(0, my))
- local dist = math.abs(my);
- while not (dist == 0) do
- dist = dist - 1;
- mv("FORWARD")
- SetPosition(GetPosition() + vec3.new(0, sign(my), 0))
- end
- end
- if not (mz == 0) then
- rotate(getMoveDir(0, 0))
- local dist = math.abs(mz);
- while not (dist == 0) do
- if mz < 0 then
- mv("DOWN")
- else
- mv("UP")
- end
- dist = dist - 1;
- SetPosition(GetPosition() + vec3.new(0, 0, sign(mz)))
- end
- end
- end
- function moveto(vec)
- print("Moveto")
- local pos = GetPosition()
- print("Moveto pos")
- move(vec.x - pos.x, vec.y - pos.y, vec.z - pos.z)
- end
- function place(dir)
- if dir == UP then
- return turtle.placeUp()
- elseif dir == DOWN then
- return turtle.placeDown()
- else
- rotate(dir)
- return turtle.place()
- end
- end
- function dig(dir)
- if dir == UP then
- return turtle.digUp()
- elseif dir == DOWN then
- return turtle.digDown()
- else
- rotate(dir)
- return turtle.dig()
- end
- end
- GetReturning, SetReturning = UseState("Returning", false)
- function getFuel()
- if turtleNeedFuel == 0 then
- return 99999
- end
- local fuel = turtle.getFuelLevel()
- if fuel < turtle.getFuelLimit() then
- turtle.refuel(1)
- end
- return fuel
- end
- function hasEnoughFuel()
- local pos = GetPosition()
- local fuel = getFuel()
- local dist = (pos.x + pos.y + pos.z) + 100
- if dist > fuel then
- return false
- end
- return true
- end
- function checkReturn()
- if not hasEnoughFuel() then
- print("Not enough fuel Returning")
- ReturnHome()
- exit()
- end
- end
- function ReturnHome()
- SetReturning(true)
- moveto(vec3.new(0, 0, 0))
- end
- GetVeinMining, SetVeinMining = UseState("VeinMining", false)
- GetVeinInitialPos, SetVeinInitialPos = UseState("VeinInitialPos", vec3.new(0, 0, 0))
- Worth = Set.new()
- Junk = Set.new()
- function inspect(dir)
- if dir == UP then
- local has, block = turtle.inspectUp()
- if not has then
- return nil
- end
- return block
- elseif dir == DOWN then
- local has, block = turtle.inspectDown()
- if not has then
- return nil
- end
- return block
- else
- rotate(dir)
- local has, block = turtle.inspect()
- if not has then
- return nil
- end
- return block
- end
- end
- function checkBlockWorth(block, tocheck)
- tocheck = tocheck or Worth
- if block == nil then
- return false
- end
- for v in tocheck:elements() do
- if string.find(block["name"], v) then
- return true
- end
- end
- return false
- end
- function isChest(block)
- if block == nil then
- return false
- end
- if block["name"] == nil then
- print("DEBUG BLOCK")
- print(block)
- return false
- end
- return string.find(block["name"], "chest")
- end
- function checkForWorth(dir)
- local block = inspect(dir)
- if block == nil then
- print(DirToString(dir) .. " is nil")
- return
- end
- print(DirToString(dir) .. " is " .. block["name"])
- if isChest(block) then
- lootChest(dir)
- return
- end
- if block == "lava" and block.state.level == 0 then
- if selectItem("bucket") then
- place(dir)
- turtle.refuel(1)
- end
- return
- end
- if checkBlockWorth(block) then
- veinmine(dir, Worth)
- end
- end
- local alldirs = {
- vec3.new(0, 0, -1),
- vec3.new(0, 0, 1),
- vec3.new(0, -1, 0),
- vec3.new(0, 1, 0),
- vec3.new(-1, 0, 0),
- vec3.new(1, 0, 0)
- }
- function veinmine(dir, tomine)
- local initpos = GetPosition()
- SetVeinInitialPos(initpos)
- SetVeinMining(true)
- print("Starting Veinmine")
- local stack = Stack.new()
- local checked = Set.new()
- print("Pushing initial position")
- stack:push(DirToVec(dir) + initpos)
- print("Pushed initial position")
- while not stack:isEmpty() do
- local vec = stack:pop()
- print("Moving to " .. vec.x .. ", " .. vec.y .. ", " .. vec.z)
- moveto(vec)
- for i, v in ipairs(alldirs) do
- local dir = VecToDir(v)
- local pos = GetPosition() + v
- if not checked:contains(pos) then
- checked:add(pos)
- print("Checking " .. pos.x .. ", " .. pos.y .. ", " .. pos.z)
- if checkBlockWorth(inspect(dir), tomine) then
- stack:push(vec + v)
- end
- end
- end
- end
- moveto(GetVeinInitialPos())
- SetVeinMining(false)
- end
- -- Inventory
- clearfrom = 2
- function lootChest(dir)
- if dir == UP then
- while turtle.suckUp() do end
- elseif dir == DOWN then
- while turtle.suckDown() do end
- else
- rotate(dir)
- while turtle.suck() do end
- end
- end
- function deposit(dir)
- local block = inspect(dir)
- if not isChest(block) then
- return false
- end
- for i = clearfrom, 16 do
- turtle.select(i)
- while turtle.drop() == false and turtle.getItemCount() ~= 0 do -- Waits until turtle can deposit item
- sleep(0.1)
- end
- turtle.drop()
- end
- turtle.select(1)
- return true
- end
- function isInvFull()
- local full = true
- for i = clearfrom, 16 do
- local count = turtle.getItemCount(i)
- if count == 0 then
- full = false
- end
- end
- return full
- end
- function clearInv()
- for i = clearfrom, 16 do
- while turtle.getItemCount(i) > 0 do
- turtle.select(i)
- local item = turtle.getItemDetail(i)
- for junk in Junk:elements() do
- if string.find(item["name"], junk) then
- turtle.select(i)
- turtle.drop()
- end
- end
- end
- end
- if isInvFull() then
- print("Going back to clear inventory")
- ReturnHome()
- for _, dir in pairs({ UP, DOWN, FORWARD, BACK, LEFT, RIGHT }) do
- local block = inspect(dir)
- if isChest(block) then
- deposit(dir)
- end
- end
- end
- if isInvFull() then
- print("Inventory is full")
- exit()
- end
- end
- function checkInv()
- if not isInvFull() then
- return
- end
- print("Inventory is full")
- clearInv()
- end
- function selectItem(name)
- for i = 1, 16 do
- if turtle.getItemCount(i) > 0 then
- if string.find(turtle.getItemDetail(i)["name"], name) then
- turtle.select(i)
- return true
- end
- end
- end
- return false
- end
- print("Library Loaded")
- print("Loading State")
- LoadState()
- print("State Loaded")
Advertisement
Add Comment
Please, Sign In to add comment