Day28 小乌龟自动掘井挖隧道

介绍过 CC: Tweaked Turtle 的特性和指令後
今天来直接看看,怎麽让 Mining Turtle 挖矿龟为我们工作
假设你还不知道怎麽写程序让 Turtle 工作
可以先参考在 /rom/programs/turtle 有两支专为挖矿龟写好的指令
excavate.lua 和 tunnel.lua
tunnel 是用来挖隧道用的,隧道宽度固定为 3 格,高度固定为 2 格,长度可自订
例如输入

tunnel 5

就是让小龟往前挖出 宽3 x 高2 x 长5 的隧道,其中长度 5 是从目前小龟所在那一格开始算起
这个程序很方便我们快速挖出一条通道
而如果你嫌高度 2 格不够怎办?
那就放两只小龟同时挖啊 XD
接下来看看 tunnel.lua 的程序码

local collected = 0

local function collect()
    collected = collected + 1
    if math.fmod(collected, 25) == 0 then
        print("Mined " .. collected .. " items.")
    end
end

每次开挖,都会呼叫 collect(),计算目前挖到的物品总数,并且每 25 个回报一次

local function tryDig()
    while turtle.detect() do
        if turtle.dig() then
            collect()
            sleep(0.5)
        else
            return false
        end
    end
    return true
end

挖掘函数有 tryDig, tryDigUp, tryDigDown 我们看 tryDig 就够了
turtle.detect() 就是判断前方是否可以挖,回传 true / false,相关函数有 turtle.detectUp(), turtle.detectDown()
turtle.dig() 当然就是挖掘前面方块了,回传 true / false,相关函数有 turtle.digUp(), turtle.digDown()

local function refuel()
    local fuelLevel = turtle.getFuelLevel()
    if fuelLevel == "unlimited" or fuelLevel > 0 then
        return
    end

    local function tryRefuel()
        for n = 1, 16 do
            if turtle.getItemCount(n) > 0 then
                turtle.select(n)
                if turtle.refuel(1) then
                    turtle.select(1)
                    return true
                end
            end
        end
        turtle.select(1)
        return false
    end

    if not tryRefuel() then
        print("Add more fuel to continue.")
        while not tryRefuel() do
            os.pullEvent("turtle_inventory")
        end
        print("Resuming Tunnel.")
    end
end

refuel 就是补充燃料了
首先判断是否有足够燃料,不够的话才会试着寻找储物箱内,是否有适合当燃料的物品
可以看出补充燃料的方式,就是要先选择某一格
turtle.select(n)
然後 turtle.refuel(1),这里设计成一次只补充一份,因为我们不知道到底还有多少燃料可以拿来用

然後当燃料不够,就会持续等着物品放进小乌龟储物箱的事件 turtle_inventory 发生
此时会再次试着补充让料

local function tryUp()
    refuel()
    while not turtle.up() do
        if turtle.detectUp() then
            if not tryDigUp() then
                return false
            end
        elseif turtle.attackUp() then
            collect()
        else
            sleep(0.5)
        end
    end
    return true
end

再来看看 tryUp,相关函数有 tryDown, tryForward
try 函数每次都先补充燃料确保可以动作
接下来 turtle.up() 试着往上移动
如果失败了,就用 turtle.detectUp() 判断上方是否有方块?如果有,就试着挖开
如果不是方块,那麽就可能是怪物了,就试着攻击

最後来看看主程序

for n = 1, length do
    turtle.placeDown()
    tryDigUp()
    turtle.turnLeft()
    tryDig()
    tryUp()
    tryDig()
    turtle.turnRight()
    turtle.turnRight()
    tryDig()
    tryDown()
    tryDig()
    turtle.turnLeft()

    if n < length then
        tryDig()
        if not tryForward() then
            print("Aborting Tunnel.")
            break
        end
    else
        print("Tunnel complete.")
    end

end

turtle.placeDown() 一开始先在下方放置任意方块,相关函数有 place(), placeUp()
接下来挖掘方块的顺序就是上、左、左上、右上、右下
然後转正准备挖下一个深度,如果这时侯挖掘失败了,就会中断,否则就会一直挖开到玩家指定的长度

看完 tunnel.lua 之後,其实就几乎学会小乌龟 80% 的函数了!
足以撰写大部分的挖掘指令
这是实际挖隧道时小乌龟的电脑画面
CC: Tweaked Mining Turtle tunnel

小乌龟掘深井

接下来看看 excavate.lua
tunnel.lua 是往前挖出隧道,excavate.lua 则是往下挖井,长宽为玩家自订
会挖得非常深,直达地底遇到基岩才停止
接着就会自动往上移动回到地面上

这是执行过程小乌龟的电脑画面
CC: Tweaked Mining Turtle excavate

假设输入

excavate 3

就是往下挖出 3 x 3 的深井直达地底
来看看 excavate 的程序码

local function unload(_bKeepOneFuelStack)
    print("Unloading items...")
    for n = 1, 16 do
        local nCount = turtle.getItemCount(n)
        if nCount > 0 then
            turtle.select(n)
            local bDrop = true
            if _bKeepOneFuelStack and turtle.refuel(0) then
                bDrop = false
                _bKeepOneFuelStack = false
            end
            if bDrop then
                turtle.drop()
                unloaded = unloaded + nCount
            end
        end
    end
    collected = 0
    turtle.select(1)
end

这是小乌龟挖井结束後,返回到地面时,把挖到的东西都「吐」出来的函数
就是这个画面 XD
CC: Tweaked Mining Turtle excavate finish
这段程序码逻辑其实很简单,就是把小乌龟储物箱的16格一一检查过
如果有东西就 drop 到地上
而中间有一段用到 _bKeepOneFuelStack 变数,是告诉小乌龟卸货时,是否保留一格燃料,毕竟燃料还要用嘛!

local function returnSupplies()
    local x, y, z, xd, zd = xPos, depth, zPos, xDir, zDir
    print("Returning to surface...")
    goTo(0, 0, 0, 0, -1)

    local fuelNeeded = 2 * (x + y + z) + 1
    if not refuel(fuelNeeded) then
        unload(true)
        print("Waiting for fuel")
        while not refuel(fuelNeeded) do
            os.pullEvent("turtle_inventory")
        end
    else
        unload(true)
    end

    print("Resuming mining...")
    goTo(x, y, z, xd, zd)
end

这个 returnSupplies 函数则是让小乌龟「回到」地面後,等待更多燃料并卸货
然後回到原本的位置继续开挖
从下面 tryForwards(), tryDown() 可以看出,小乌龟有两种情况会做这件事

  1. 燃料不够
  2. 储物箱满了(所以必须回到地面把东西吐出来)

goTo() 则很明显是直接移动小乌龟到指定位置的函数,用的是相对座标
goTo(0, 0, 0, 0, 1) 便是回到一开始的位置和方向

最後来个掘井画面
CC: Tweaked Mining Turtle excavate

以上是今天对 Mining Turtle 的分享
下一回我会继续探索更多小乌龟的操作~


<<:  【Day 28】NumPy (5):sum(), power(), transpose()

>>:  Day 28 - 实战演练 — Pagination

I Want To Know React - Context 语法

回顾 Context 在上一章节中,我们介绍了何谓 context。 Context 是一种利用向下...

Day18-D3 的 Axis( ) & ticks( ) 轴线与刻度

本篇大纲:轴线的组成、建立轴线的必备工具、绘制轴线的API、ticks 刻度、XY 轴范例 讲了好...

前端工程师也能开发全端网页:挑战 30 天用 React 加上 Firebase 打造社群网站|Day11 上传文章图片

连续 30 天不中断每天上传一支教学影片,教你如何用 React 加上 Firebase 打造社群...

[Day6] 渗透测试证照 - OSCP 小分享

前言 前面几篇写了一些有趣没什麽人讨论的攻击手法,中场休息偷懒一下 之前在PTT上看到有人讨论OSC...

予焦啦!问题分析

本节是以 Golang 上游 8854368cb076ea9a2b71c8b3c8f675a8e1...