Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- 指定した方向のブロックをcompare_fnが返すスロットのアイテムと置換する
- ---@param direction integer 方向。0=正面,1=上,2=下,3=右,4=左
- ---@param compare_fn "fun(re: boolean, v: table|string, direction: number):integer" 比較関数。inspectの結果(bool, any)が渡される。設置に使用するアイテムのあるスロット番号か設置しない場合nilを返す
- local function replace(direction, compare_fn)
- ---@param inspect_fn "fun():boolean, table|string"
- ---@param dig_fn "fun(toolSide:? integer): boolean, string|nil"
- ---@param place_fn any
- ---@return boolean
- ---@return string|nil
- local function impl(inspect_fn, dig_fn, place_fn)
- local inspect_re, inspect_table = inspect_fn()
- local use_slot = compare_fn(inspect_re, inspect_table, direction)
- if not (nil ~= use_slot) then
- print("replace:impl:: skip replace", use_slot)
- return true
- end
- -- 砂のような落下してくるブロック対策
- repeat
- local dig_re, dig_message = dig_fn()
- inspect_re, inspect_table = inspect_fn()
- print(dig_re, inspect_re)
- -- 空気ブロックの採掘にエラーを出さない
- if (not dig_re) and (inspect_re) then
- print("replace:impl:: unexpected block!")
- return false, dig_message
- end
- until inspect_re == false
- local slot = turtle.getSelectedSlot() -- 退避
- turtle.select(use_slot)
- local place_re, place_message = place_fn()
- turtle.select(slot) -- recover
- if not place_re then
- print("replace:impl:: fail to place")
- return false, place_message
- end
- print("replace:impl:: return true")
- return true
- end
- if (direction == 0) then
- return impl(turtle.inspect, turtle.dig, turtle.place)
- elseif (direction == 1) then
- return impl(turtle.inspectUp, turtle.digUp, turtle.placeUp)
- elseif (direction == 2) then
- return impl(turtle.inspectDown, turtle.digDown, turtle.placeDown)
- elseif (direction == 3) then
- turtle.turnRight()
- local re, message = impl(turtle.inspect, turtle.dig, turtle.place)
- turtle.turnLeft()
- return re, message
- elseif (direction == 4) then
- turtle.turnLeft()
- local re, message = impl(turtle.inspect, turtle.dig, turtle.place)
- turtle.turnRight()
- return re, message
- end
- return false, string.format("unknown direction: %d", direction)
- end
- local function turn_back()
- turtle.turnLeft()
- turtle.turnLeft()
- end
- -- 通路断面を左下から初めて時計回りに置換する
- ---@param height integer 通路の高さ
- ---@param width integer 通路の幅
- ---@param compare_fn "fun(re: boolean, v: table|string):integer" 比較関数。inspectの結果(bool, any)が渡される。設置に使用するアイテムのあるスロット番号か設置しない場合nilを返す
- local function ring_replace(height, width, compare_fn)
- ---@param direction integer 方向。0=正面,1=上,2=下,3=右,4=左
- local function impl(direction, size, detect_fn, dig_fn, move_fn, detect_cond_fn)
- print(string.format("ring_replace:impl %d", size))
- for i = 1, size do
- local re, message = replace(direction, compare_fn)
- if not re then return re, message end
- if (i == size) then
- print("ring_replace:impl:: chnage direction")
- return true
- end
- if detect_fn() then
- dig_fn()
- end
- print(string.format("ring_replace:impl:: i: %d(%s), size: %d(%s)", i, type(i), size, type(size)))
- re, message = move_fn()
- if not re then return re, message end
- end
- return true
- end
- local re, message = impl(0, height, turtle.detectUp, turtle.digUp, turtle.up)
- if not re then return re, message end
- turn_back()
- re, message = impl(1, width, turtle.detect, turtle.dig, turtle.forward)
- if not re then return re, message end
- re, message = impl(0, height, turtle.detectDown, turtle.digDown, turtle.down)
- if not re then return re, message end
- turn_back()
- re, message = impl(2, width, turtle.detect, turtle.dig, turtle.forward)
- if not re then return re, message end
- return true
- end
- -- 通路壁面を置換する。障害物は採掘される。左下壁面を向いている状態でスタート
- ---@param height integer 通路の高さ
- ---@param width integer 通路の幅
- ---@param depth integer 通路の奥行き
- ---@param compare_fn "fun(re: boolean, v: table|string):integer" 比較関数。inspectの結果(bool, any)が渡される。設置に使用するアイテムのあるスロット番号か設置しない場合nilを返す
- local function tunnel_replacer(height, width, depth, compare_fn)
- for i = 1, depth do
- local re, message = ring_replace(height, width, compare_fn)
- if not re then return re, message end
- turtle.turnRight()
- if turtle.detect() then
- print("tunnel_replacer:: block detect")
- re, message = turtle.dig()
- if not re then return re, message end
- end
- re, message = turtle.forward()
- if not re then return re, message end
- turtle.turnLeft()
- end
- return true
- end
- -- 燃料の総消費量を計算する
- ---@param height integer 通路の高さ
- ---@param width integer 通路の幅
- ---@param depth integer 通路の奥行き
- local function calc_total_fuel_consumption(height, width, depth)
- return (height * 2 + (width - 2) * 2) * depth
- end
- -- 燃料の確認。条件を満たさなければassert
- ---@param required integer 必要燃料消費量
- local function assert_fuel(required)
- assert(required <= turtle.getFuelLimit(), string.format("fuel limit exceed.(limit: %d, required: %d)", turtle.getFuelLimit(), required))
- assert(required <= turtle.getFuelLevel(), string.format("not enough fuel.(current: %d, required: %d)", turtle.getFuelLevel(), required))
- end
- local function assert_inventory()
- local slot_1 = turtle.getItemDetail(1)
- assert((slot_1 ~= nil) and (slot_1.name == "minecraft:stone"), string.format("unexpected inventory item detected.(expected: minecraft:stone, actual: %s)", slot_1.name))
- local slot_2 = turtle.getItemDetail(2)
- assert((slot_2 ~= nil) and (slot_2.name == "minecraft:glass"), string.format("unexpected inventory item detected.(expected: minecraft:glass, actual: %s)", slot_2.name))
- end
- ---焼石とガラスのあるスロットを列挙する
- ---@return integer[]
- ---@return integer[]
- local function init_inventory_serch()
- assert_inventory()
- local init_slot = turtle.getSelectedSlot() -- 退避
- ---@type integer[]
- local stone_slots = { 1 }
- ---@type integer[]
- local glass_slots = { 2 }
- for i = 3, 16 do
- turtle.select(i)
- if turtle.compareTo(1) then
- print(string.format("slot %d is stone", i))
- table.insert(stone_slots, i)
- end
- if turtle.compareTo(2) then
- print(string.format("slot %d is glass", i))
- table.insert(glass_slots, i)
- end
- end
- return stone_slots, glass_slots
- end
- ---@class InspectResultState
- ---@field variant string
- ---@class InspectResult
- ---@field state InspectResultState|nil
- ---@field name string
- ---@field metadata integer
- -------------------------------------------------------------
- local height, width, depth = ...
- assert_fuel(calc_total_fuel_consumption(tonumber(height), tonumber(width), tonumber(depth)))
- local stone_slots, glass_slots = init_inventory_serch()
- function table_back(t)
- return t[#t]
- end
- function wait_block_supply_and_select(get_item_slots)
- if #get_item_slots() == 1 and turtle.getItemCount(table_back(get_item_slots())) < 2 then
- print(string.format("please add %s to turtle inventry", turtle.getItemDetail(get_item_slots()[0]).name))
- end
- while #get_item_slots() == 1 and turtle.getItemCount(table_back(get_item_slots())) < 2 do
- print(string.format("waiting %s...(slot: %d, count: %d)", turtle.getItemDetail(table_back(get_item_slots())).name, table_back(get_item_slots()), #get_item_slots()))
- stone_slots, glass_slots = init_inventory_serch()
- sleep(1)
- end
- -- 最後の一つのアイテムは残す
- if turtle.getItemCount(table_back(get_item_slots())) == (#get_item_slots() == 1 and 1 or 0) then
- table.remove(get_item_slots(), #get_item_slots())
- end
- return table_back(get_item_slots())
- end
- ---replace_cond
- ---@param i_re boolean
- ---@param i_v InspectResult|string
- ---@param direction number
- ---@return integer|nil
- function replace_cond(i_re, i_v, direction)
- if (not i_re) or (not i_v.name) then
- -- 床は石にする
- return wait_block_supply_and_select(function() return direction == 2 and stone_slots or glass_slots end)
- end
- if ((i_v.name == "minecraft:stone") and (i_v.state.variant == "stone")) or (i_v.name == "minecraft:glass") then
- return nil
- end
- return wait_block_supply_and_select(function() return stone_slots end)
- end
- tunnel_replacer(tonumber(height), tonumber(width), tonumber(depth), replace_cond)
Add Comment
Please, Sign In to add comment