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

Minecraftとタートルと僕

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

採掘タートルで整地する: (7)高さを自動認識して切土する整地プログラム

はじめに

  • 整地中
    • f:id:hevohevo:20140803012642j:plain:w400
  • 整地後
    • f:id:hevohevo:20140803122351j:plain:w400

他のことに熱中していたので連載が止まっていました。別に忘れていたわけではないのでご安心ください。

さて、前回までに、奥行き/幅/高さを指定して整地するプログラムを紹介しました。

言い換えると、指定した大きさの直方体の空洞を作るプログラムといっても過言ではありません。

実際このプログラムは、地上での整地以外にも、地下で本拠地を建設するときの空洞つくりに役立ちます。

「地下に農場作るために、奥行き16幅16高さ10の空間を作りたい」などと活躍します。

このように役立つ空洞作成プログラムですが、地上で凸凹具合に偏りがある地面を整地すると、少しだけ荒が目立ちます。

たとえば、高さ1から2程度のフラットな1チャンク程度の丘の端に高さ10程度の山が一つあるとしましょう。

先のプログラムでは、奥行き/幅/高さ = 16/16/10 とするしかありません。

でもそうなると、大部分がフラットであるにも関わらず、高さ10まで無駄に移動することになりますよね。

燃料と時間の無駄です。非効率です。

非効率はプログラマの敵ですよね。改善はプログラマの義務ですよ!

新しいアルゴリズム

高さをあらかじめ指定するのではなく、その場で自動調節するようにしましょう。

理想は凹凸のある地面および山の表面を、なめるように移動していくことです。

以下のような感じですね。

ではこれをどうやって実現するのでしょうか。

実はこれまでやってきた、「上下1往復で3山崩し」アルゴリズムに少し手を加えるだけで大丈夫です。

以下はこれまでのアルゴリズム

  • seichiThreeStep()
    • 真上を掘って真上移動
    • 指定された高さまで上ったら、正面掘って正面移動
    • 真下を堀り正面も掘って真下移動、を繰り返す
    • 最初の高さまで来たら、1歩前進して、1セット終了

これを次のように改造します。

  • seichiThreeStep()改
    • 真上を掘って真上移動
    • 正面と真上をチェックしつつ山の一番高いところまで上ったら、正面掘って正面移動
    • もう一度正面と真上をチェックしつつ山の一番高いところまで上る
    • 真下を堀り正面も掘って真下移動、を繰り返す
    • 最初の高さまで来たら、1歩前進して、1セット終了

この、正面と真上をチェックしつつ山の一番高いところまで上るという関数を作ることが今回の目玉です。

新しいアルゴリズムを実装

コードを示しましょう。

function goTop()
  while turtle.detectUp() or turtle.detect() do
    surelyUp()
  end
end

真上と正面にブロックがあるかをチェックして、どちらかにブロックがあればまだ頂上ではないので、真上に移動するという関数です。

真上にも正面にもブロックがなかったらそこは頂上と判断して、Whileループを抜け出します。

とても短いですね。

次に、元の高さまで降りてくる関数(goBottom())も作るのですが、ここで一つ問題が生じます。それは、どれだけの高さ上ったかをどこかに記録しておかないと、元の高さがわからないのです。

この変数の名前は、current_heightとしましょう。

確実に1歩上昇するsurelyUp()と一歩下降するsurelyDown()。 これらの関数の中で、この変数current_heightの値を増減させています。

最終的に元の高さまで降りてくるgoBottom()は次のようになります。

-- 引数は下降中に実行したい関数。例 surelyDig
function goBottom(func)
  while current_height > 1 do
    if func then func() end -- もしfuncが指定されたならばその関数を実行
    surelyDown()
  end
end

この関数goBottom()は通常、seichiThreeStep()の中でgoBottom(surelyDig)のように使います。降りてくるときに同時に正面も掘ってもらわないといけませんからね。

でも、降りてくるときに正面を掘らないseichiTwoStep()の中では、引数を指定せずに使います。

一つの関数を二つの場所で使いまわしているのがポイントですね。

ソースコード

http://pastebin.com/TBejsTqU

ソースコードの見所

前回のプログラムよりも少しだけ短くなりました。

注目して欲しいのは、

実際に掘り進めて行くseichiThreeStep()seichiTwoStep()seichiOneStep()の3つの関数です。

goBottom()goTop()を使うことでとても短くシンプルになりました。

これらOne、Two、Three関数がどういったことをしているか一目瞭然ですよね。

まとめ

あとはこのプログラムを使って地上を平らに均していきましょう。

> cutland 16 16

これで1チャンクがまっ平らに! すばらしい。

・・・といいたいところなのですが、このプログラムにも一つだけ欠点があります。

ヒント: 山の中にある空洞

次回はこれを解決していきましょう。お楽しみに。