面白ければいいんじゃない?

やくたいのないこと、痛々しいことばかり書きます。

ComputerCraftでQuarryのような何かを実装した(MC1.7.10 CC1.65)

はじめに

というわけで、greg環境でBCのクァーリーのコストが異常に高騰しているので、コストの安いComputerCraftのMinningTrutleに露天掘りさせるプログラムを書きました。
はじめてluaを書いたんですが、簡単でいいですね、これ。今度、ルーター*1で動かす何かでも書きたいなーとか少し思いました。
あと動作保障は一切ないので何が起きても文句言わないでください。

使い方

動作環境

  • Minecraft 1.7.10
  • ComputerCraft 1.65
  • まぁ、以前からあるAPIしか使ってないはずなので以前のバージョンでも動くと思われ…

仕様

  • パラメータで指定した範囲を掘りぬく
  • 燃料がなくなると戻ってきて補充する
  • インベントリが残り3枠を切ると戻ってきてチェストに納品
  • 納品や燃料補充がうまくいかないと一時停止してユーザの入力を待つ
  • 掘りぬいたら戻ってくる
  • MOBに当たるなどして引っかかるとリトライする
    • 何度リトライしてもダメなら停止する
  • 当たり前だけどチャンクロード範囲外に出るとプログラムごと終了する

設置方法

f:id:yoshizawa81:20141109225852p:plain
タートルの後ろに空のアイテム搬出用チェスト。下のチェストには燃料の木炭とか突っ込んでください。ただ念のため1スタック以上の空きスペースを作ってください*2
また、最初の燃料をタートルの一番右下のインベントリに入れてください。

コマンド

f:id:yoshizawa81:20141109230142p:plain
pestbinからとってきて保存したファイルを実行してください。コマンドライン・パラメータとして「奥行き」「横幅」「掘る深さ」の三つのパラメータを入力してください。

途中で止まった時

f:id:yoshizawa81:20141109230604p:plain
アイテムをチェストに搬出したり、チェストから燃料補充をしますが、これに失敗すると一時停止します。チェストの中身をチェックして処置してから、タートルのシェルで何かキーを入力すれば再開します。

実際に掘る姿

f:id:yoshizawa81:20141109230804p:plain
これは4x4の範囲を掘っている姿です。
設置場所の1マス前方を左に向かって指定領域を掘ります。

ソースコード

http://pastebin.com/T0vmSEZH

------------------------------------
-- Quarry modoki
-- by yoshizawa81
-- version 0.1

-- Set backside chest empty. Turtle dump items this chest.
-- Set underchest fuel. Need one (or lager) empty slot in this chest.
-- Set turtle's inventory 16th slot (the lower right) fuel.
-- This program need just 3 parameters.(depth width hight)
-- Enjoy minecraft !
------------------------------------


------------------------------------
-- config
------------------------------------

refuel_level = 1024
fuel_inventory = 16

max_x = 64
max_y = 64
max_z = 128

-- moving config
retry = 10
wait = 3

------------------------------------
-- global vars
------------------------------------

-- turtle position
x = 0 --depth
y = 0 --width
z = 0 --hight
face = 0 --0:forword 1:right 2:back 3:left

-- digging position 
dx = 0 --depth
dy = 0 --width
dz = 0 --hight
dface = 0 --0:forword 1:right 2:back 3:left

-- target position
tgt_x = 0
tgt_y = 0
tgt_z = 0

------------------------------------
-- command line parameter include
------------------------------------

args = {...}

------------------------------------
-- functions
------------------------------------

-- command line parameter check
function cmdline_check()
	
	if #args > 3 then
		print("This program need just 3 parameters. depth width hight")
		os.queueEvent("terminate")
		sleep(1) --bad know haw...
	end
	
	tgt_x = tonumber(args[1])
	tgt_y = tonumber(args[2])
	tgt_z = tonumber(args[3]) 
	
	if tgt_x > max_x then
		print("Set depth less than "..max_x)
		os.queueEvent("terminate")
		sleep(1) --bad know haw...
	end
	
	if tgt_y > max_y then
		print("Set width less than "..max_y)
		os.queueEvent("terminate")
		sleep(1) --bad know haw...
	end
	
	if tgt_z > max_z then
		print("Set hight less than "..max_z)
		os.queueEvent("terminate")
		sleep(1) --bad know haw...
	end
	
	tgt_y = tgt_y - 1
	
end

function my_forword()
	
	local tf = true
	local cause = "string"
	local i = 0
	
	tf,cause=turtle.forward()
	
	if tf==false then
		if cause=="Movement obstructed" then
			while i < retry do
				tf=turtle.forward()
				if tf == true then
					break
				end
			sleep(wait)
			i = i + 1
			end
			
			if tf == false then
				print("Error. Obstructed.")
				os.queueEvent("terminate")
				sleep(1) --bad know haw...
			end
		end
	end
end

-- Came back home position.
function back_home()
	while z > 0 do
		turtle.up()
		z = z - 1
	end
	
	if face == 0 then
		turtle.turnRight()
		face = 1
		while y > 0 do
			my_forword()
			y = y - 1
		end
	elseif face == 1 then
		while y > 0 do
			my_forword()
			y = y - 1
		end
	elseif face == 2 then
		turtle.turnLeft()
		face = 1
		while y > 0 do
			my_forword()
			y = y - 1
		end
	elseif face == 3 then
		turtle.turnRight()
		turtle.turnRight()
		face = 1
		while y > 0 do
			my_forword()
			y = y - 1
		end
	end
	
	turtle.turnRight()
	face = 2
	while x > 0 do
			my_forword()
			x = x - 1
	end

end

function my_down()
	
	local tf = true
	local cause = "string"
	local i = 0
	
	tf,cause=turtle.down()
	
	if tf==false then
		if cause=="Movement obstructed" then
			while i < retry do
				tf=turtle.down()
				if tf == true then
					break
				end
			end
			sleep(wait)
			i = i + 1
		end
			
		if tf == false then
			back_home()
			print("Error. Obstructed? End?")
			os.queueEvent("terminate")
			sleep(1) --bad know haw...
		end
	end
end

-- Go digging position.
function go_digpos()
	turtle.turnRight()
	turtle.turnRight()
	
	face = 0
	
	while x < dx do
		my_forword()
		x = x + 1
	end
	
	turtle.turnLeft()
	
	face = 3
	
	while y < dy do
		my_forword()
		y = y + 1
	end
	
	while z < dz do
		my_down()
		z = z + 1
	end
	
	if dface==0 then
		turtle.turnRight()
		face=0
	elseif dface==1 then
		turtle.turnRight()
		turtle.turnRight()
		face=1
	elseif dface==2 then
		turtle.turnLeft()
		face=2
	end
end

-- Get fuel from chest.
function get_fuel()
	turtle.select(fuel_inventory)
	
	local tf = false
	local cause = "string"
	
	tf,cause = turtle.dropDown()
	
	if tf == false and cause == "Inventory full" then
		print("After check chests, hit any key.")
		os.pullEvent(key)
		get_fuel()
	end	
	
	if turtle.suckDown() == false then
		print("After check chests, hit any key.")
		os.pullEvent(key)
		get_fuel()
	end
end

-- Dump items to chest.
function dump_items()
	
	local i = 1
	
	while i < 16 do
		turtle.select(i)
		turtle.drop()
		i = i + 1
	end
	
	if not(turtle.getItemSpace(15) == 64 and turtle.getItemSpace(14) == 64 and turtle.getItemSpace(13) == 64) then
		print("After check chests, hit any key.")
		os.pullEvent(key)
		dump_items()
	end
	
end

-- error trap of empty fuel or full items.
function error_trap()
	if (x == 0 and y ==0 and z == 0) then
		print("After check chests, hit any key.")
		os.pullEvent(key)
	else
		back_home()
	end
	dump_items()
	get_fuel()
	
	go_digpos()
end

-- refuel from inventory
function refuel_inv()
	turtle.select(fuel_inventory)
	while turtle.getFuelLevel() < refuel_level do
		if turtle.refuel(1) == false then
			error_trap()
		end
	end
	turtle.select(1)
end

-- Check inventry space.
function check_inv()
	if not(turtle.getItemSpace(15) == 64 and turtle.getItemSpace(14) == 64 and turtle.getItemSpace(13) == 64) then 
		error_trap()
	end
	turtle.select(1)
end

------------------------------------
-- main program
------------------------------------

cmdline_check()

while z <= tgt_z do

	while y <= tgt_y do
		
		if face == 0 then
			while x < tgt_x do
				refuel_inv()
				check_inv()
				
				turtle.dig()
				my_forword()
				x = x+1
				dx=dx+1
			end
		end
		
		if y == tgt_y then
			break
		end
		
		if face == 0 then
			turtle.turnLeft()
			face=3
			dface=3
			
			turtle.dig()
			my_forword()
			y = y + 1
			dy = dy + 1
			
			turtle.turnLeft()
			face=2
			dface=2
		end
		
		if face == 2 then
			while x > 1 do
				refuel_inv()
				check_inv()
				
				turtle.dig()
				my_forword()
				x = x - 1
				dx = dx - 1
			end
		end
		
		if y == tgt_y then
			break
		end
		
		if face == 2 then
			turtle.turnRight()
			face=3
			dface=3
			
			turtle.dig()
			my_forword()
			y = y + 1
			dy = dy + 1
			
			turtle.turnRight()
			face=0
			dface=0
		end
		
	end
	
	if z == tgt_z then
		break
	end
	
	turtle.digDown()
	my_down()
	z=z+1
	dz=dz+1
	
	turtle.turnRight()
	turtle.turnRight()
	
	if face == 0 then
		face=2
		dface=2
	elseif face == 2 then
		face=0
		dface=0
	end
	
	while y >= 0 do
		
		if face == 0 then
			while x < tgt_x do
				refuel_inv()
				check_inv()
				
				turtle.dig()
				my_forword()
				x = x + 1
				dx = dx + 1
			end
		end
		
		if y == 0 then
			break
		end
		
		if face == 0 then
			turtle.turnRight()
			face=1
			dface=1
			
			turtle.dig()
			my_forword()
			y = y - 1
			dy = dy - 1
			
			turtle.turnRight()
			face=2
			dface=2
		end
		
		if face == 2 then
			while x > 1 do
				refuel_inv()
				check_inv()
				
				turtle.dig()
				my_forword()
				x = x-1
				dx = dx - 1
			end
		end
		
		if y == 0 then
			break
		end
		
		if face == 2 then
			turtle.turnLeft()
			face=1
			dface=1
			
			turtle.dig()
			my_forword()
			y = y - 1
			dy = dy - 1
			
			turtle.turnLeft()
			face=0
			dface=0
		end
		
	end
	
	if z == tgt_z then
		break
	end
	
	turtle.digDown()
	my_down()
	z = z + 1
	dz = dz + 1
	
	turtle.turnRight()
	turtle.turnRight()
	
	if face == 0 then
		face=2
		dface=2
	elseif face == 2 then
		face=0
		dface=0
	end

end

back_home()

謝辞

id:hevohevo氏の記事をいろいろと参考にしました。多謝。

*1:うちのルーターYamahaのRTX810ですが、Yamahaルーターluaスクリプトが書けるそうです。

*2:燃料を一回吐き出してから、再度1スタック取り込む仕様のため

注意:ここに書かれていることは筆者の個人的見解であり所属する組織などの意志を表すものではありません。