【Minecraft】拡張性◯の自動農場を作る【CCの道も一行から#4】

YouTube とニコニコ動画で投稿中の動画シリーズで、動画に収まりきらなかったこぼれ話や詳細解説を掲載しています。

動画はこちらから

作成したプログラム

auto_farming.lua

動画内の自動農場で使っているプログラム。動作には動画と同じような目印となるブロックを設置する必要がある。

pastebin get XzBE6jWr auto_farming.luaでゲーム内からダウンロードできる。

コメント付き版

-- const

-- 床に設置する目印となるブロックを指定。
local BOTTOM_MARKERS = {
    ['minecraft:deepslate_tile_slab']    = {type = 'turn', direction = 'right'},
    ['minecraft:deepslate_brick_slab']   = {type = 'turn', direction = 'left'},
    ['minecraft:cobbled_deepslate_slab'] = {type = 'turn', direction = 'back'},
    ['minecraft:barrel']                 = {type = 'storage'},
}
-- 天井に設置する目印となるブロックを指定。対応する作物を収穫する成長段階もしていする。
local TOP_MARKERS = {
    ['minecraft:jungle_slab'] = {type = 'farm', age = 7, slot = 1}, -- minecraft:carrot
    ['minecraft:spruce_slab'] = {type = 'farm', age = 7, slot = 2}, -- minecraft:potato
    ['minecraft:oak_slab']    = {type = 'farm', age = 5, slot = 3}, -- tofucraft:seeds_soybeens
    ['minecraft:birch_slab']  = {type = 'farm', age = 7, slot = 4}, -- minecraft:wheat_seeds
}
-- 燃料補給はこの値以上になるまで行う。
local FUEL_MIN = 1000

local TURN_FUNCS = {
    left  = turtle.turnLeft,
    right = turtle.turnRight,
}


-- memory

local lastTurn


-- functions

-- 目印となるブロックから行動を決定する。
function getAction()
    local isTop, top = turtle.inspectUp()
    local isBottom, bottom = turtle.inspectDown()
    return (isTop and TOP_MARKERS[top.name]) or (isBottom and BOTTOM_MARKERS[bottom.name]) or nil
end

-- 正面が壁かを判定する。特定のブロックのみに反応するようにしてもよい。
function isWall()
    return turtle.detect()
end

function reset()
    turtle.select(1)
end

function step(isFirst)
    reset()
    local action = getAction()
    if action == nil then
        turtle.forward()
        lastTurn = nil
    elseif action.type == 'farm' then
        local isThere, crop = turtle.inspectDown()
        turtle.select(action.slot)
        -- 種が十分にあり、下が空気(何も植えられていない)とき
        if turtle.getItemCount() >= 2 and not isThere then
            turtle.placeDown()
        -- インベントリに余裕があり、作物が十分成長して植わっているとき
        elseif turtle.getItemCount(16) == 0 and isThere and crop.state.age >= action.age then
            turtle.digDown()
        -- それ以外
        else
            turtle.forward()
        end
        lastTurn = nil
    elseif action.type == 'turn' then
        if action.direction == 'back' then
            if lastTurn then
                TURN_FUNCS[lastTurn]()
                turtle.forward()
            else
                -- 壁を向くように回転
                while not isWall() do
                    turtle.turnRight()
                end
                -- 回れ左
                turtle.turnLeft()
                turtle.turnLeft()
                
                turtle.forward()
            end
        else
            if isFirst then
                -- 壁を向くように回転
                while not isWall() do
                    turtle.turnRight()
                end
            end
            TURN_FUNCS[action.direction]()
            turtle.forward()
            lastTurn = action.direction
        end
    elseif action.type == 'storage' then
        -- 種を入れておくスロットをメモ
        local seed_slots = {}
        for name, data in pairs(TOP_MARKERS) do
            seed_slots[data.slot] = true
        end
        
        for i = 1, 16 do
            turtle.select(i)
            if seed_slots[i] == true then
                -- 種スロットなら 16 個残す
                turtle.dropDown(math.max(0, turtle.getItemCount() - 16))
            else
                -- そうでなければ全部
                turtle.dropDown()
            end
        end
        
        -- 十分な燃料を補給するまで繰り返す
        while turtle.getFuelLevel() < FUEL_MIN do
            turtle.suckUp(1)
            if not turtle.refuel() then -- 燃料補給に失敗したとき
                print(("Fuel: %d"):format(turtle.getFuelLevel()))
                os.sleep(1)
            end
        end
        turtle.forward()
    else
        turtle.forward()
        lastTurn = nil
    end
end

function main()
    step(true) -- first step
    
    -- メインループ
    while true do
        step()
    end
end


-- main

main()
Lua
Expand

使い方

まず、耕地の3ブロック上に、植える作物の目印となるブロックを設置する。デフォルトでは各木材のハーフブロックが指定されている。このとき、畑に高低差があってはならない。あとは、全ての耕地を通るように、床に目印となるブロックを設置する。デフォルトでは、深層岩レンガのハーフが左回転〈壁に向かって左を向く〉、深層岩タイルのハーフが右回転〈壁に向かって右を向く〉、深層岩の丸石ハーフが直前の動作と同じ方向にもう一度回転(直前の動作が回転でなければ壁を背にするように回転)〈壁を背にするように回転〉。(起動時には〈山括弧〉内の動作をする。)そして、移動経路を環状になるように指定したら、そのどこか一か所の上下を樽にする。上は燃料補給用、下は収穫物の回収用。なお、回収用の樽が満杯だと予期せぬ動作を行うかもしれない。最後に、タートルのインベントリの対応するスロットにタネを少量持たせ、プログラムを起動する。(最初は手動で耕地に種をまいておくとなお良い。)

詳細解説

動画に登場した要素を詳しく解説します。

用語集

動画内に出てきた専門用語やアイテムなどの解説です。

農業タートル

クワを持たせたタートル。農作物や適性ツールがクワのブロックの破壊の他、土を耕すことができる。ツルハシよりもクワの方がダイヤの要求量も少ないので、自動農場を作るなら採掘タートルよりこっちがいいだろう。耕すにはturtle.dig()を使うことに注意。

フローチャート

アルゴリズム(ある目的を達成するための手順)などを視覚的に分かりやすく表現した図。ひし形は条件分岐を表すなど、その形によって、各プロセスの種類を示す。

状態遷移

ゲームで例えてみる。あるゲームでは、タイトル画面で決定ボタンを押すとゲームが開始され、開始後一分経つとタイトルに戻ってくるとする。このとき、"タイトル画面"と"ゲーム中"という二つの状態があり、ボタン操作や時間経過をきっかけに、その状態が移り変わる。これを状態遷移という。当然ながら、これには現在の状態を記憶しておく必要があり、ワールドから出ると再起動してしまうCCとの相性はあまり良くない。そのため、今回の自動農場では記憶の必要が無いように、天井や床に目印となるブロックを設置することによって、この問題を解決している。

コマンド

動画内で使用した、CC のコンピューターなどで実行可能なコマンドの解説です。

id コマンド

その機械に割り当てられたID(不変)と、label(可変)を確認する。CCのコンピューターなど保存されたデータは、[プロファイルディレクトリ]/saves/[ワールドフォルダー]/computercraft/computers/[ID]に保存される。そのため、ここにあるファイルを開けば、任意のテキストエディタで編集することもできる。

プログラム関連

実際に CC でプログラミングするときに必要な知識です。基本的にプログラミング経験者向けの情報になります。

turtle.detect()

正面に障害物があるかを取得する。

turtle.inspectUp()/turtle.inspectDown()

上下のブロックの情報を取得する。正面版にturtle.inspect()がある。第一戻り値としてブロックが存在するか、第二戻り値としてその情報を返す。ブロックが存在した際には、その情報を持つテーブル(=nameブロックIDstateブロック状態tagsにそのブロックが持つブロックタグをキーに持ち値がすべてtrueのテーブルを持つ)を返す。

turtle.suckUp(count)

上に落ちているアイテムを拾う。あるいは、上にチェストなどがあれば、そこからアイテムを取る。countが省略されるときは1スタック取る。

turtle.getFuelLevel()

現在の燃料補給量を返す。

turtle.refuel(count)

燃料補給をする。refuel コマンドとほぼ同じ。成功でtrueを返す。

編集後記

ちょっとした裏話として、最後のカットでタートルがニンジンを収穫してますが、植えてるのはジャガイモです。つまり、バグです。(もちろん修正済み)

Verified by MonsterInsights