読者です 読者をやめる 読者になる 読者になる

Minecraftとタートルと僕

PCゲームMinecraftのMOD「ComputerCraft」の情報を集めたニッチなブログです。

農業タートルプログラミング チュートリアル(6)

チュートリアル Lua ComputerCraft Minecraft

帰宅時間が遅くてゲームする暇がないよ(泣)
プログラム書いてもそれを検証するにはminecraft起動しなくてはならないというのがつらいね。

CCのシミュレーション環境があるといいのに。
仕事場のPCで動かしてもばれにくいテキストベースのやつがw

とりあえず前回のサトウキビ収穫プログラムの改善だよ。

改善方針

  • プログラム実行時に畑の奥行きサイズと横方向の繰り返し回数を指定できるようにする。
  • サイズ指定しなかった場合はデフォルトの値(奥行き5、繰り返し1)を使う。デフォ値はプログラム中のconfig項目。
# harvest_millet <Z_SIZE> <COUNT>
> harvest_millet 5 1 

# あるいは引数省略
> harvest_millet
  • 収穫作業開始前に、ホームポジションの真上のチェストから燃料アイテムを入手し、燃料補給する。
    • 燃料用チェストにはあらかじめ燃料アイテムを詰めておくこと。
    • 燃料用チェストからアイテムを入手し燃料補給しても、まだ最低限燃料に満たない場合はプログラム停止。

プログラム解説

上記の改善方針に従って次のような修正を施しているよ。

  • args = {...} うんぬん。
    • プログラム実行時の引数が2個のときはその値をそれぞれZ_SIZEとCOUNTに代入
    • 引数がないときにはデフォ値を使うよ。
    • え?引数が数字でなかった時のエラー処理? 気にスンナ!
  • fuelItUp() メソッドの追加
    • 燃料補給関係の処理をすべてこのメソッドで処理しているよ。
    • 燃料補給して最低限燃料に満たない場合はfalseを返すんだ。
    • もちろんfalseの場合はプログラムを停止するよ。

プログラム

  • pastebin
  • (2013/11/30追記)現在燃料値と必要燃料値を表示する部分が逆になっていたのでこっそり修正。ついでに待機時間30分は長い気がしたので20分に修正。
-- ####################################
-- harvest_millet
-- version 0.21
-- http://hevohevo.hatenablog.com/


-- #########################
-- TOP view
-- T: turtle, o: millet, W: water

-- Z_SIZE=5, COUNT=1
-- oWo
-- oWo
-- oWo
-- oWo
-- oWo
-- T     

-- Z_SIZE=5, COUNT=3
-- oWooWooWo
-- oWooWooWo
-- oWooWooWo
-- oWooWooWo
-- oWooWooWo
-- T
 
-- #########################
-- Side view
-- Y position is 3, same as the top of the millet.
-- T: turtle, o: millet, F: Chest for Fuel items, C: Chest for droping down millets

--  F
-- oT
-- oC
-- o


-- ####################
-- config

FUEL_SLOT = 16
Z_SIZE = 5
COUNT = 1

-- ####################
-- define functions

function goForward(n)
  for i=1,n do
    turtle.dig()
    turtle.forward()
    turtle.digDown()
  end
end

function goRightLine()
  turtle.turnRight()
  goForward(2)
  turtle.turnRight()
end
function goLeftLine()
  turtle.turnLeft()
  goForward(1)
  turtle.turnLeft()
end

function harvest()
  for i=1,COUNT do
    goForward(Z_SIZE)
    goRightLine()
    goForward(Z_SIZE)
    goLeftLine()
  end
end

function backToChest()
  turtle.turnLeft()
  for i=1,COUNT*3 do
    turtle.forward()
  end
  turtle.turnRight()
end

function dropItems(begin_slot, end_slot)
  print('drop items: slots ',begin_slot,'-',end_slot)
  for i=begin_slot, end_slot do
    turtle.select(i)
    turtle.dropDown()
  end
  turtle.select(1)
end


function fuelItUp()
  turtle.select(FUEL_SLOT)
  turtle.refuel()
  
  if (turtle.getFuelLevel() < minFuelLevel) then
    turtle.suckUp()
    turtle.refuel()
    if (turtle.getFuelLevel() < minFuelLevel) then
      print("Please insert fuel into slot ",FUEL_SLOT)
      return false
    end
  end

  print('Succeed: fuelItUp()')
  return true
end

-- ###################
-- Main

args = {...}
if args and #args == 2 then
  Z_SIZE = tonumber(args[1])
  COUNT = tonumber(args[2])
end
minFuelLevel = ((Z_SIZE + 2 + Z_SIZE + 1) * COUNT) + (3 * COUNT)

print('harvest_millet ', Z_SIZE,' ', COUNT))
print(' FuelLevel (current/needed)')
print('  = ',turtle.getFuelLevel(),'/',minFuelLevel)

while true do
  if fuelItUp() == false then break end

  print('Starting harvest!')
  turtle.select(1)
  harvest()
  backToChest()
  dropItems(1,16)
  print('Finished!')
  
  sleep(1200)
end

このプログラムを実際に使うときのTIPS

「プログラム名が長すぎてゲーム開始時に毎回打ち込むの面倒なんですけど……」

解決法1

コピーしてファイル名を変えればいいんじゃね?

> cp harvest_millet hm
解決法2

このプログラムを実行するためのプログラム(スクリプト)を書けばいいんじゃね?
たとえば次のようなプログラムを「hm」という名前で保存したらいいと思うよ。
引数を自由に書き換えられるので場合によって使い分けできるし。
ちなみにshell.run()の引数は1番目がファイル名(パスも含む)、2番目以降がそのプログラムを実行するときに指定する引数だよ。

shell.run("harvest_millet",5,1)

「そうじゃなくてゲーム開始するたびにプログラム名を打ち込んで実行すること自体が面倒なんです!」

解決(?)法

上記のプログラムを「startup」というファイル名にしておけばゲーム起動時(あるいはタートル設置時)に自動的に実行されるのだけど、これはあまりお勧めしないよ。
移動しないCCコンピュータなら問題ないけど、動き回るタートルだと迷子になってしまうことがあるんだ。具体的に言うと次のような感じ。

  1. タートルが収穫作業をしている途中でゲームを終了する
  2. 次回ゲームを開始したらstartupを実行するのだけど、さきほど終了した位置をホームポジションと勘違いして収穫作業開始
  3. 暴走&迷子(泣)

今回は農業タートルだから壁に突き当たれば停止するけど採掘タートルだとどこまでも行ってしまうね。
下手すると大事な拠点を破壊貫通して突き進むかもw

迷子対策としては、タートルに現在位置を認識させる必要があるね。少なくとも現在位置がホームポジションかどうかだけでも判定できるなら迷子だけは避けることができる。

タートル自身が現在位置を知る方法として一番確実なのは、GPS機能を使うことだけどこれは前準備が大変なので今回は言及しないよ。
ホームポジションかどうかを認識させるだけなら、一つのアイデアとして上下方向に物体(チェスト)があるかどうかを調べさせるのがいいかもね。つまり、真上と真下に何か物体があるなら(turtle.detectUp()とturtle.detectDown())そこはホームポジションと判断する方法だね。

プログラムの先頭にこの判断ルーチンを仕込んでおいて、ホームポジションならそのまま作業実行、そうでないならそれは前回作業中にゲーム終了してしまったということなのでプログラムを停止してしまえばいい。タートル君を手作業で回収してまたホームポジションへの再設置からやろうね。

では、このアイデアの実装は自分でやってみてね。宿題だ。

次回の予定

次回はCrafty turtleを使ってみようね。