From c2491f53a8a40ca563945f81e6eccef718144b4a Mon Sep 17 00:00:00 2001 From: kepler155c Date: Fri, 15 Sep 2017 00:45:05 -0400 Subject: [PATCH] reorganization --- apis/itemDB.lua | 2 +- apis/turtle/craft.lua | 166 ++++++++++++++++++++++++++++++++++++++++++ apis/turtle/level.lua | 165 +++++++++++++++++++++++++++++++++++++++++ apps/chestManager.lua | 4 +- apps/treefarm.lua | 2 +- 5 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 apis/turtle/craft.lua create mode 100644 apis/turtle/level.lua diff --git a/apis/itemDB.lua b/apis/itemDB.lua index 5545cf0..d36ba73 100644 --- a/apis/itemDB.lua +++ b/apis/itemDB.lua @@ -1,7 +1,7 @@ local Util = require('util') local TableDB = require('tableDB') -local itemDB = TableDB({ fileName = 'usr/etc/items.db' }) +local itemDB = TableDB({ fileName = 'usr/config/items.db' }) function itemDB:get(key) diff --git a/apis/turtle/craft.lua b/apis/turtle/craft.lua new file mode 100644 index 0000000..abedcdd --- /dev/null +++ b/apis/turtle/craft.lua @@ -0,0 +1,166 @@ +local itemDB = require('itemDB') +local Util = require('util') + +local Craft = { } + +local function clearGrid(chestAdapter) + for i = 1, 16 do + local count = turtle.getItemCount(i) + if count > 0 then + chestAdapter:insert(i, count) + if turtle.getItemCount(i) ~= 0 then + return false + end + end + end + return true +end + +local function splitKey(key) + local t = Util.split(key, '(.-):') + local item = { } + if #t[#t] > 2 then + item.nbtHash = table.remove(t) + end + item.damage = tonumber(table.remove(t)) + item.name = table.concat(t, ':') + return item +end + +local function getItemCount(items, key) + local item = splitKey(key) + for _,v in pairs(items) do + if v.name == item.name and + v.damage == item.damage and + v.nbtHash == item.nbtHash then + return v.count + end + end + return 0 +end + +local function turtleCraft(recipe, qty, chestAdapter) + + clearGrid(chestAdapter) + + for k,v in pairs(recipe.ingredients) do + local item = splitKey(v) + chestAdapter:provide(item, qty, k) + if turtle.getItemCount(k) == 0 then -- ~= qty then + -- FIX: ingredients cannot be stacked + return false + end + end + + return turtle.craft() +end + +function Craft.craftRecipe(recipe, count, chestAdapter) + + local items = chestAdapter:listItems() + + local function sumItems(items) + -- produces { ['minecraft:planks:0'] = 8 } + local t = {} + for _,item in pairs(items) do + t[item] = (t[item] or 0) + 1 + end + return t + end + + count = math.ceil(count / recipe.count) + + local maxCount = recipe.maxCount or math.floor(64 / recipe.count) + local summedItems = sumItems(recipe.ingredients) + + for key,icount in pairs(summedItems) do + local itemCount = getItemCount(items, key) + if itemCount < icount * count then + local irecipe = Craft.recipes[key] + if irecipe then +Util.print('Crafting %d %s', icount * count - itemCount, key) + if not Craft.craftRecipe(irecipe, + icount * count - itemCount, + chestAdapter) then + turtle.select(1) + return + end + end + end + end + repeat + if not turtleCraft(recipe, math.min(count, maxCount), chestAdapter) then + turtle.select(1) + return false + end + count = count - maxCount + until count <= 0 + + turtle.select(1) + return true +end + +-- given a certain quantity, return how many of those can be crafted +function Craft.getCraftableAmount(recipe, count, items) + + local function sumItems(recipe, items, summedItems, count) + + local canCraft = 0 + + for i = 1, count do + for _,item in pairs(recipe.ingredients) do + local summedItem = summedItems[item] or getItemCount(items, item) + + local irecipe = Craft.recipes[item] + if irecipe and summedItem <= 0 then + summedItem = summedItem + sumItems(irecipe, items, summedItems, 1) + end + if summedItem <= 0 then + return canCraft + end + summedItems[item] = summedItem - 1 + end + canCraft = canCraft + recipe.count + end + + return canCraft + end + + return sumItems(recipe, items, { }, math.ceil(count / recipe.count)) +end + +function Craft.canCraft(item, count, items) + return Craft.getCraftableAmount(Craft.recipes[item], count, items) == count +end + +function Craft.setRecipes(recipes) + Craft.recipes = recipes +end + +function Craft.getCraftableAmountTest() + local results = { } + Craft.setRecipes(Util.readTable('usr/etc/recipes.db')) + + local items = { + { name = 'minecraft:planks', damage = 0, count = 5 }, + { name = 'minecraft:log', damage = 0, count = 2 }, + } + results[1] = { item = 'chest', expected = 1, got = Craft.getCraftableAmount(Craft.recipes['minecraft:chest:0'], 2, items) } + + items = { + { name = 'minecraft:log', damage = 0, count = 1 }, + { name = 'minecraft:coal', damage = 1, count = 1 }, + } + results[2] = { item = 'torch', expected = 4, got = Craft.getCraftableAmount(Craft.recipes['minecraft:torch:0'], 4, items) } + + return results +end + +function Craft.craftRecipeTest(name, count) + local ChestAdapter = require('chestAdapter18') + local chestAdapter = ChestAdapter({ wrapSide = 'top', direction = 'down' }) + Craft.setRecipes(Util.readTable('usr/etc/recipes.db')) + return { Craft.craftRecipe(Craft.recipes[name], count, chestAdapter) } +end + +return Craft diff --git a/apis/turtle/level.lua b/apis/turtle/level.lua new file mode 100644 index 0000000..bce7145 --- /dev/null +++ b/apis/turtle/level.lua @@ -0,0 +1,165 @@ +local Point = require('point') +local Util = require('util') + +local checkedNodes = { } +local nodes = { } +local box = { } +local oldCallback + +local function toKey(pt) + return table.concat({ pt.x, pt.y, pt.z }, ':') +end + +local function addNode(node) + + for i = 0, 5 do + local hi = turtle.getHeadingInfo(i) + local testNode = { x = node.x + hi.xd, y = node.y + hi.yd, z = node.z + hi.zd } + + if Point.inBox(testNode, box) then + local key = toKey(testNode) + if not checkedNodes[key] then + nodes[key] = testNode + end + end + end +end + +local function dig(action) + + local directions = { + top = 'up', + bottom = 'down', + } + + -- convert to up, down, north, south, east, west + local direction = directions[action.side] or + turtle.getHeadingInfo(turtle.point.heading).direction + + local hi = turtle.getHeadingInfo(direction) + local node = { x = turtle.point.x + hi.xd, y = turtle.point.y + hi.yd, z = turtle.point.z + hi.zd } + + if Point.inBox(node, box) then + + local key = toKey(node) + checkedNodes[key] = true + nodes[key] = nil + + if action.dig() then + addNode(node) + repeat until not action.dig() -- sand, etc + return true + end + end +end + +local function move(action) + if action == 'turn' then + dig(turtle.getAction('forward')) + elseif action == 'up' then + dig(turtle.getAction('up')) + dig(turtle.getAction('forward')) + elseif action == 'down' then + dig(turtle.getAction('down')) + dig(turtle.getAction('forward')) + elseif action == 'back' then + dig(turtle.getAction('up')) + dig(turtle.getAction('down')) + end + + if oldCallback then + oldCallback(action) + end +end + +-- find the closest block +-- * favor same plane +-- * going backwards only if the dest is above or below +function closestPoint(reference, pts) + local lpt, lm -- lowest + for _,pt in pairs(pts) do + local m = Point.turtleDistance(reference, pt) + local h = Point.calculateHeading(reference, pt) + local t = Point.calculateTurns(reference.heading, h) + if pt.y ~= reference.y then -- try and stay on same plane + m = m + .01 + end + if t ~= 2 or pt.y == reference.y then + m = m + t + if t > 0 then + m = m + .01 + end + end + if not lm or m < lm then + lpt = pt + lm = m + end + end + return lpt +end + +local function getAdjacentPoint(pt) + local t = { } + table.insert(t, pt) + for i = 0, 5 do + local hi = turtle.getHeadingInfo(i) + local heading + if i < 4 then + heading = (hi.heading + 2) % 4 + end + table.insert(t, { x = pt.x + hi.xd, z = pt.z + hi.zd, y = pt.y + hi.yd, heading = heading }) + end + + return closestPoint(turtle.getPoint(), t) +end + +return function(startPt, endPt, firstPt, verbose) + + checkedNodes = { } + nodes = { } + box = { } + + box.x = math.min(startPt.x, endPt.x) + box.y = math.min(startPt.y, endPt.y) + box.z = math.min(startPt.z, endPt.z) + box.ex = math.max(startPt.x, endPt.x) + box.ey = math.max(startPt.y, endPt.y) + box.ez = math.max(startPt.z, endPt.z) + + if not turtle.pathfind(firstPt) then + error('failed to reach starting point') + end + + turtle.setPolicy("attack", { dig = dig }, "assuredMove") + + oldCallback = turtle.getMoveCallback() + turtle.setMoveCallback(move) + + repeat + local key = toKey(turtle.point) + + checkedNodes[key] = true + nodes[key] = nil + + dig(turtle.getAction('down')) + dig(turtle.getAction('up')) + dig(turtle.getAction('forward')) + + if verbose then + print(string.format('%d nodes remaining', Util.size(nodes))) + end + + if Util.size(nodes) == 0 then + break + end + + local node = closestPoint(turtle.point, nodes) + node = getAdjacentPoint(node) + if not turtle.gotoPoint(node) then + break + end + until turtle.abort + + turtle.resetState() + turtle.setMoveCallback(oldCallback) +end diff --git a/apps/chestManager.lua b/apps/chestManager.lua index 03f2a38..d8b7d4b 100644 --- a/apps/chestManager.lua +++ b/apps/chestManager.lua @@ -34,8 +34,8 @@ end local chestAdapter = ChestAdapter({ direction = 'west', wrapSide = 'back' }) local turtleChestAdapter = ChestAdapter({ direction = 'up', wrapSide = 'bottom' }) -local RESOURCE_FILE = 'usr/etc/resources.db' -local RECIPES_FILE = 'sys/etc/recipes.db' +local RESOURCE_FILE = 'usr/config/resources.db' +local RECIPES_FILE = 'usr/etc/recipes.db' local jobListGrid local craftingPaused = false diff --git a/apps/treefarm.lua b/apps/treefarm.lua index e593991..cbd1bd5 100644 --- a/apps/treefarm.lua +++ b/apps/treefarm.lua @@ -76,7 +76,7 @@ local state = Util.readTable('usr/config/treefarm') or { } local clock = os.clock() -local recipes = Util.readTable('sys/etc/recipes.db') or { } +local recipes = Util.readTable('usr/etc/recipes.db') or { } Craft.setRecipes(recipes)