diff --git a/dominic/pairingtool.lua b/dominic/pairingtool.lua new file mode 100644 index 0000000..bd82746 --- /dev/null +++ b/dominic/pairingtool.lua @@ -0,0 +1,703 @@ +args = {...} +x, z, direction = 0, 0, 0 +turtlestate = { + fuel = "", + state = "init", + job = nil, + ores = {} +} + +function noop() end + +function pair(x, y) + return math.floor((x + y) * (x + y + 1)/2 + y) +end + +function unpairX(z) + local j = math.floor(math.sqrt(0.25 + 2*z) - 0.5) + return j - (z - j*(j+1)/2) +end + + +function unpairZ(z) + local j = math.floor(math.sqrt(0.25 + 2*z) - 0.5) + return z - j * (j+1)/2; +end + +lookup = {4, 1, 3, 0, 2} +local function isDiggingSpot(x, y) + local val = lookup[(y % 5) + 1] + return (x % 5) == val +end + +offset = 10 +function ithSpot(i) + j = offset + while true do + x, z = unpairX(j), unpairZ(j) + if isDiggingSpot(x, z) then + if i <= 1 then + return x, z + else + i = i - 1 + end + end + j = j + 1 + end +end + +function adjustToQuadrant(i, x, z) + if i % 4 == 0 then + return x, z + elseif i % 4 == 1 then + return -z-1, x + elseif i % 4 == 2 then + return z, -x-1 + elseif i % 4 == 3 then + return -z-1, -x-1 + end +end + +function iTo2Dcoords(j) + i = math.floor(j / 4) + quadrantI = j % 4 -- 0-3 quadrant + counter = 0 -- number of digging spots found + j = 0 -- enumerate 2D plane + while true do + x, z = unpairX(j), unpairZ(j) -- coords in first quadrant + x, z = adjustToQuadrant(quadrantI, x, z) -- map coords correctly into other quadrants + if isDiggingSpot(x, z) then + if counter == i then + return x, z + end + counter = counter + 1 + end + j = j + 1 + end +end + +function digSafe(inspectAction, digAction) + while true do + local status, block = inspectAction() + if status then + if block["name"]:lower():find("turtle") then + -- turtle in front of me. its free space + break + else + digAction() + -- gravel may take time to fall. + sleep(1) + end + else + -- No block in front of me. good + break + end + end +end + +-- move safely into the direction, not hurting other turtles, but freeing the path if needed. +function moveSafe(moveAction, inspectAction, digAction) + while true do + local status, block = inspectAction() + if status then + if block["name"]:lower():find("turtle") then + -- turtle in front of me. lets wait for it to move + sleep(0.6) + elseif block["name"]:lower():find("water") or block["name"]:lower():find("lava") then + if moveAction() then + break + else + digAction() + updateState({ state = "I am stuck trying to walk into a liquid." }) + end + else + digAction() + end + else + -- nothing in the way, try to move + if moveAction() then + break + end + end + end +end + +-- If the block in front of the turtle is desired, take it. +function grabOres() + local status, block = turtle.inspect() + if status and block["name"]:lower():find("ore") then + ore = block["name"]:lower() + if turtlestate["ores"][ore] then + turtlestate["ores"][ore] = turtlestate["ores"][ore] + 1 + else + turtlestate["ores"][ore] = 1 + end + turtle.dig() + end +end + +-- dig all the way down to bedrock, collect ores +-- Parameters: +-- * moveAction: the **vertical** move action, eg turtle.down +-- * digAction: the **vertical** dig action, eg turtle.digDown +-- * inpectAction: the **vertical** inspect action, eg turtle.inspectDown +-- * limit: if >= 0 * the number of blocks to dig +-- * dig until bedrock is hit +-- +-- +-- Returns: the depth dug +function digDeep(moveAction, digAction, inspectAction, limit) + local depth = 0 + grabOres() + while true do + -- termination condition: + -- * if limit != -1: limit > 0 + -- * otherwise : bedrock beneath + if limit < 0 then + local status, nextblock = inspectAction() + if status and nextblock["name"] == "minecraft:bedrock" then + return depth + end + else + if limit == 0 then + return depth + end + end + -- Limit not reached: keep digging + depth = depth + 1 + limit = limit - 1 + digAction() + moveAction() + grabOres() -- inspect block in front of turtle, take if neccessary + end +end + +function selectCobble() + for i = 1,16 do + turtle.select(i) + item = turtle.getItemDetail() + if item and item["name"] == "minecraft:cobblestone" then + break + end + end +end + +function selectFuel() + for i = 1,16 do + turtle.select(i) + item = turtle.getItemDetail() + if item and (item["name"] == "minecraft:coal" or item["name"] == "minecraft:charcoal") then + break + end + end +end + +function digShaft() + --turtle.digDown() + --selectCobble() + --turtle.placeUp() + moveSafe(turtle.down, turtle.inspectDown, turtle.digDown) + --turtle.down() + depth = digDeep(turtle.down, turtle.digDown, turtle.inspectDown, -1) + turtle.turnLeft() + digDeep(turtle.up, noop, noop, depth) + turtle.turnLeft() + digDeep(turtle.down, noop, noop, depth) + turtle.turnLeft() + digDeep(turtle.up, noop, noop, depth) + turtle.turnLeft() + selectCobble() + turtle.up() + turtle.placeDown() + --turtle.digUp() + --turtle.up() + --faceDir(0) +end + +function digTo(x, z) + --print("Digging to rel. coord ("..tostring(x)..", "..tostring(z)..")") + while z > 0 do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + z = z - 1 + repeat sleep(0.6) + until (not turtle.digUp()) + end + turtle.turnRight() + while x > 0 do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + x = x - 1 + repeat sleep(0.6) + until (not turtle.digUp()) + end +end + +function goToSpawn(x, z) + moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) + while z > 0 do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + z = z - 1 + end + turtle.turnRight() + while x > 0 do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + x = x - 1 + end +end + +function moveSafeForward() + moveSafe(turtle.forward, turtle.inspect, noop) +end + +function goToBarrel(path) + if path == 0 then + turtle.turnLeft() + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnRight() + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnRight() + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + else + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnRight() + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnLeft() + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + turtle.turnRight() + end +end + +function leaveBarrel(path) + if path == 0 then + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnRight() + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnRight() + else + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnRight() + moveSafe(turtle.forward, turtle.inspect, noop) + turtle.turnRight() + end +end + +function reportDuty(id, fuelconsumed) + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafeForward() + moveSafeForward() + moveSafeForward() + moveSafeForward() + moveSafeForward() + moveSafeForward() + moveSafeForward() + moveSafeForward() + rednet.open("bottom") + --print("Proto: Sending completed Job id") + rednet.broadcast(tostring(id), "jobs") + sleep(0.6) + --print("Proto: Sending fuel status") + rednet.broadcast(tostring(fuelconsumed), "fuel") + while true do + --print("Proto: Awaiting thanks") + sender, message, proto = rednet.receive("jobcomplete") + if message == "thanks" then + break + else + sleep(1) + end + end + --print("Proto: Received thanks") +end + +function enqueueTurtle() + moveSafe(turtle.up, turtle.inspectUp, noop) + moveSafe(turtle.up, turtle.inspectUp, noop) + moveSafe(turtle.up, turtle.inspectUp, noop) + turtle.turnLeft() + moveSafeForward() + moveSafeForward() + moveSafeForward() + turtle.turnRight() + while true do + local status, block = turtle.inspectDown() + if not status then + if turtle.down() then + break -- we moved in line + end + else + if turtle.forward() then + -- pass, thats ok + else + local status, block = turtle.inspect() + if status and not block["name"]:lower():find("turtle") then + turtle.dig() + turtle.forward() + turtle.digUp() + turtle.digDown() + end + end + end + end + -- we moved into line + turtle.turnLeft() + turtle.turnLeft() +end + +function doRefuel() + moveSafeForward() + turtle.turnRight() + while turtle.getFuelLevel() < 1500 do + turtle.suck(4) + selectFuel() + turtle.refuel() + end + turtle.turnLeft() +end + +function goToJob() + moveSafeForward() + moveSafeForward() + moveSafeForward() +end + +function waitForJob() + --print("Waiting for job...") + while true do + status, block = turtle.inspectDown() + if status and block["name"] == "computercraft:wired_modem_full" then + break + else + moveSafeForward() + end + end + rednet.open("bottom") + local retrying = false + while true do + rednet.broadcast("gibjob", "jobs") + sender, message, proto = rednet.receive("newjob", 2) + if message then + job = tonumber(message) + --print("Received job "..tostring(job)) + return job + else + if not retrying then + retrying = true + --print("No job received. I will keep retrying.") + turtlestate["state"] = "Waiting for job... (retrying)" + end + end + end +end + +function emptyToBarrel() + sleep(0.4) + for i = 1,16 do + turtle.select(i) + sleep(0.1) + turtle.dropDown() + end +end + +function drawStatus() + print("Turtle ("..tostring(turtlestate["id"])..")") + print() + print(" \""..turtlestate["name"].."\"") + print() + if turtlestate["job"] then + print("Current job: "..tostring(turtlestate["job"])) + else + print("Current job: ") + end + print() + if turtlestate["startfuel"] then + print("Starting Fuel: "..tostring(turtlestate["startfuel"])) + else + print("Starting Fuel: ") + end + if turtlestate["job"] then + print("Recent fuel usage: "..tostring(turtlestate["fuel"])) + else + print("Recent fuel usage: ") + end + print() + print("Status:") + print(" "..turtlestate["state"]) + if turtlestate["morestate"] then + print(" "..turtlestate["morestate"]) + else + print() + end + --print(" "..turtlestate["state"]) + turtlestate["morestate"] = nil +end + +function turtleAI() + while true do + turtlestate["state"] = "Waiting for job..." + drawStatus() + thejob = waitForJob() + turtlestate["job"] = thejob + turtlestate["state"] = "Refueling..." + drawStatus() + doRefuel() + fuel = turtle.getFuelLevel() + turtlestate["state"] = "Headed to the jobsite..." + drawStatus() + goToJob() + x, z = ithSpot(thejob) + digTo(x,z) + turtlestate["state"] = "Digging the Shaft..." + drawStatus() + digShaft() + turtlestate["state"] = "Returning to the station..." + drawStatus() + goToSpawn(x, z) + path = math.floor(math.random() + 0.5) + turtlestate["state"] = "Unloading Inventory..." + drawStatus() + goToBarrel(path) + emptyToBarrel() + leaveBarrel(path) + fuelconsumed = fuel - turtle.getFuelLevel() + --print("I consumed "..tostring(fuelconsumed).." fuel") + --print("Reporting Duty") + turtlestate["fuel"] = fuelconsumed + turtlestate["state"] = "Reporting duty..." + drawStatus() + reportDuty(thejob, fuelconsumed) + turtlestate["job"] = nil + turtlestate["state"] = "Going back in line..." + drawStatus() + enqueueTurtle() + end +end + +function updateState(update) + for k,v in pairs(update) do + turtlestate[k] = v + end + drawStatus() +end + +function enqueueForJob2() + updateState({ state = "Waiting for job..." }) + while true do + status, block = turtle.inspectDown() + if status and block["name"] == "computercraft:wired_modem_full" then + break + else + moveSafeForward() + end + end + turtle.turnLeft() + rednet.open("bottom") + + local retrying = false + while true do + rednet.broadcast("syn") + server, message, proto = rednet.receive(2) -- ACK + if not message then + retrying = true + else + rednet.send(server, "gibjob") + _, job, _ = rednet.receive() + if job then + if job == "nojobs" then + updateState({ state = "Waiting for job... (retrying)" }) + sleep(3) + else + return tonumber(job) + end + end + end + end +end + +function faceDir(dir) + if ((direction - dir) % 4 == 2) then + turtle.turnRight() + turtle.turnRight() + direction = (direction + 2) % 4 + elseif ((direction - dir) % 4 == 1) then + turtle.turnLeft() + direction = (direction -1) % 4 + elseif ((direction - dir) % 4 == 3) then + turtle.turnRight() + direction = (direction + 1) % 4 + end +end +-- directions: 0, 1, 2, 3 -> x, z, -x, -z +function goToCoordXZ2(targetX, targetZ, extraaction) + if targetX > x then + faceDir(0) + while (targetX > x) do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + x = x + 1 + extraaction() + end + end + if targetX < x then + faceDir(2) + while (targetX < x) do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + x = x - 1 + extraaction() + end + end + if targetZ > z then + faceDir(1) + while (targetZ > z) do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + z = z + 1 + extraaction() + end + end + if targetZ < z then + faceDir(3) + while (targetZ < z) do + moveSafe(turtle.forward, turtle.inspect, turtle.dig) + z = z - 1 + extraaction() + end + end +end + +function goToJob2(job) + jobX, jobZ = iTo2Dcoords(job) -- this does all the magic + updateState({ state = "Going on the job...", morestate = "Jobsite is at ("..tostring(jobX)..", "..tostring(jobZ)..")" }) + -- move to hole + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + -- reset coords, descend + x, z, direction = 0, 0, 0 + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + -- go to job + function extraaction() + digSafe(turtle.inspectUp, turtle.digUp) + end + goToCoordXZ2(jobX, jobZ, extraaction) +end + +function unloadStuffs() + updateState({ state = "Now unloading..." }) + sleep(0.4) + for i = 1,16 do + turtle.select(i) + sleep(0.1) + turtle.drop() + end +end + +function doRefuel2() + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + moveSafe(turtle.forward, turtle.inspect, noop) + curfuel = turtle.getFuelLevel() + targetfuel = 1500 + if turtlestate["fuel"] ~= "" then + targetfuel = 4 * turtlestate["fuel"] + end + if curfuel > targetfuel then + return + end + updateState({ state = "Refueling... "..tostring(curfuel).." -> "..tostring(targetfuel) }) + coalneeded = math.ceil((targetfuel - curfuel) / 80) + turtle.select(1) + while turtle.getFuelLevel() < targetfuel do + grabnow = math.min(coalneeded, 64) + if turtle.suckDown(grabnow) then + -- turtle can grab + turtle.refuel() + coalneeded = coalneeded - grabnow + else + -- blabla error + updateState({ state = "Refueling... Error: Out of coal" }) + sleep(5) + end + end + updateState({ startfuel = turtle.getFuelLevel() }) +end + +slots = { {7,-6}, {7, -7}, {7, -8}, {7,-5}, {7,-4} } +function goToUnloading() + updateState({ state = "Going to unload resources..." }) + moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) + goToCoordXZ2(7, -6, noop) + moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) + slot = math.ceil(math.random()*5) + storageX, storageZ = slots[slot][1], slots[slot][2] + goToCoordXZ2(storageX, storageZ, noop) + moveSafe(turtle.up, turtle.inspectUp, turtle.digUp) + faceDir(2) + moveSafe(turtle.forward, turtle.inspect, noop) +end + +function reportDuty2() + updateState({ state = "Returning to report duty..." }) + moveSafe(turtle.up, turtle.inspectUp, noop) + moveSafe(turtle.up, turtle.inspectUp, noop) + moveSafe(turtle.up, turtle.inspectUp, noop) + moveSafe(turtle.up, turtle.inspectUp, noop) + for i = 1,12 do + moveSafeForward() + end + rednet.open("top") + id = turtlestate["job"] + fuelconsumed = turtlestate["startfuel"] - turtle.getFuelLevel() + turtlestate["fuel"] = fuelconsumed + + rednet.broadcast("syn") + server, _, _ = rednet.receive() -- ACK + rednet.send(server, "report") + rednet.send(server, tostring(id)) + rednet.send(server, tostring(fuelconsumed)) + for k, v in pairs(turtlestate["ores"]) do + rednet.send(server, k) + rednet.send(server, v) + end + turtlestate["ores"] = {} + rednet.broadcast("done", "ores") + server, _, _ = rednet.receive() -- thanks +end + +function turtleAI2() + while true do + local job = enqueueForJob2() + turtlestate["job"] = job + doRefuel2() + --turtlestate["startfuel"] = turtle.getFuelLevel() + goToJob2(job) + digShaft() + goToUnloading() + unloadStuffs() + reportDuty2() + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + moveSafe(turtle.down, turtle.inspectDown, noop) + turtle.turnLeft() + end +end +-- turtleAI() + +for i = 1, 10 do + print(iTo2Dcoords(i)) +end diff --git a/dominic/pairingtool.py b/dominic/pairingtool.py index c626017..54a68fd 100644 --- a/dominic/pairingtool.py +++ b/dominic/pairingtool.py @@ -1,4 +1,5 @@ import math +import time def pair(x, y): return math.floor((x + y) * (x + y + 1)/2 + y) @@ -12,6 +13,12 @@ def unpairZ(z): j = math.floor(math.sqrt(0.25 + 2*z) - 0.5) return z - j * (j+1)/2; +def unpair2D(j): + quadrantI = j % 4 # 0-3 quadrant + x, z = int(unpairX(j)), int(unpairZ(j)) # coords in first quadrant + x, z = adjustToQuadrant(quadrantI, x, z) # map coords correctly into other quadrants + return x, z + lookup = [-10, 4, 1, 3, 0, 2] def isDiggingSpot(x, y): x, y = int(x), int(y) @@ -58,7 +65,22 @@ def iTo2Dcoords(j): counter += 1 j += 1 -print(iTo2Dcoords(3)) +def findIfor(coords): + j = 0 + counter = 0 + while True: + x, z = unpair2D(j) + print(j, x, z) + if isDiggingSpot(x, z): + if (x, z) in coords: + print(f"{j} -> {x}, {z}") + coords.remove((x,z)) + counter += 1 + if not coords: + break + j += 1 + time.sleep(0.6) -# for i in range(10): -# print(iTo2Dcoords(i)) +findIfor([ + (4, 0), + ])