Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- ###################################################################
- -- Turtle AI API
- -- (You can enjoy rule-based programming)
- -- (c) 2014 hevohevo. MIT-Style license
- -- http://hevohevo.hatenablog.com/
- -- Twitter: @hevohevo
- -- ##################################################################
- -- 使い方
- --[[
- os.loadAPI("turtleAI")
- -- turtleAI APIを使って新しいAIを作る
- local ai = turtleAI.newAI()
- -- turtleAI APIを使って新しいタスクを作る。「前へ進む」
- -- 第1引数はタスクの名前、第2引数は実行優先度。低いほうが優先度高い
- -- タスクはcan_execute()とexecute()メソッドが必要
- -- can_execute()は、現在の状況においてそのタスクを実行するかどうかの判断。true/falseを返すこと
- -- execute()は、実際に実行する行動。trueを返すとそのままターンが進み、falseを返すとターンは進まない。
- local fwd_task = turtleAI.newTask('fwd', 0)
- fwd_task.can_execute = function(task)
- return true -- 常に実行可能とする
- end
- fwd_task.execute = function(task)
- -- 現在座標の把握のために、task.xxxx() のように移動系関数を使うこと
- task.forward()
- return true
- end
- -- 同じくturtleAI APIを使って新しいタスクを作る。「z座標が3と0のときに180度回転」
- local turn_around_task = turtleAI.newTask('turn_around', 0)
- turn_around_task.can_execute = function(task)
- -- z座標が3または0のときだけ実行可能。なお、プログラムスタート地点を基準に、x:横、y:高さ、z:縦(奥行き)
- if task.coord.z == 3 or task.coord.z == 0 then
- return true
- else
- return false
- end
- end
- turn_around_task.execute = function(task)
- task.turnRight()
- task.turnRight()
- return true
- end
- -- 同じくturtleAI APIを使って新しいタスクを作る。「燃料を15使ったら終了」
- local quit_task = turtleAI.newTask('quit', 0)
- quit_task.can_execute = function(task)
- if task.initial_fuel - turtle.getFuelLevel() == 15 then
- return true
- else
- return false
- end
- end
- quit_task.execute = function(task)
- return "quit" -- 文字列"quit"を返すと終了とする
- end
- -- 作成した2つのタスクをAIに追加する。 ai:addTask(fwd_task)でも良い
- ai.addTask(ai, fwd_task)
- ai.addTask(ai, turn_around_task)
- ai.addTask(ai, quit_task)
- -- 実行は ai:iterate()というイテレータ関数を使用。
- --
- for task_executed, turn, ai in ai.iterate(ai) do
- print("Turn ",turn)
- print(" executed: ",task_executed.name)
- task_executed.ppPos()
- end
- print("quit")
- --]]
- -- ##################################################################
- -- Turtle Move クラス
- TurtleMove = {
- -- Class変数、メソッド
- initial_fuel = turtle.getFuelLevel(),
- turn = 1,
- coord = {x=0,y=0,z=0}, -- y:depth, x:width, z:height
- direction = 0, -- 0,1,2,3, 時計周り
- ppPos = function() -- プログラムスタート時を基準として、現在の位置と方角を表示する
- print(string.format(" x/y/z=%d/%d/%d, dir=%d, fuel=%d/%d", TurtleMove.coord.x, TurtleMove.coord.y, TurtleMove.coord.z, TurtleMove.direction, turtle.getFuelLevel(), TurtleMove.initial_fuel))
- end
- }
- local FwHelper = {{ x = 0, z = 1 }, { x = 1, z = 0 }, { x = 0, z = -1 }, { x = -1, z = 0 }}
- TurtleMove.forward = function(n)
- n = n or 1
- for i=1,n do
- if turtle.forward() then
- TurtleMove.coord.x = TurtleMove.coord.x + FwHelper[TurtleMove.direction+1].x
- TurtleMove.coord.z = TurtleMove.coord.z + FwHelper[TurtleMove.direction+1].z
- end
- end
- end
- TurtleMove.turnLeft = function(n)
- n = n or 1
- for i=1,n do
- TurtleMove.direction = (TurtleMove.direction - 1) % 4
- turtle.turnLeft()
- end
- end
- TurtleMove.turnRight = function(n)
- n = n or 1
- for i=1,n do
- TurtleMove.direction = (TurtleMove.direction + 1) % 4
- turtle.turnRight()
- end
- end
- TurtleMove.back = function(n)
- n = n or 1
- for i=1,n do
- if turtle.back() then
- TurtleMove.coord.x = TurtleMove.coord.x - FwHelper[TurtleMove.direction+1].x
- TurtleMove.coord.z = TurtleMove.coord.z - FwHelper[TurtleMove.direction+1].z
- end
- end
- end
- TurtleMove.up = function(n)
- n = n or 1
- for i=1,n do
- if turtle.up() then
- TurtleMove.coord.y = TurtleMove.coord.y + 1
- end
- end
- end
- TurtleMove.down = function(n)
- n = n or 1
- for i=1,n do
- if turtle.down() then
- TurtleMove.coord.y = TurtleMove.coord.y - 1
- end
- end
- end
- -- ################################################################
- -- Taskクラス
- Task = {}
- setmetatable(Task, {__index = TurtleMove})
- Task.new = function(name, priority)
- local obj={}
- obj.priority = priority or 0 -- 小さいほど優先度高い
- obj.turn_last_fired = 0 -- AIエンジンにより自動更新
- obj.name = name or tostring(obj)
- -- 必ず、trueかfalseを返すこと
- obj.can_execute = function(this)
- return true
- end
- obj.execute = function(this)
- print(' execute: ',this.name, ' priority=',this.priority)
- -- trueを返すと今ターンはこれで終了、falseを返すともう一度タスクリストから実行
- return true
- end
- return setmetatable(obj, {__index = Task})
- end
- -- ###############################################################
- -- Turtle AIクラス
- local within = function(arg, array)
- for i,v in ipairs(array) do
- if arg == v then return true end
- end
- return false
- end
- TurtleAI = {
- tasks = {}, -- 全タスクのリスト
- executable_tasks = {} -- 現在の状況で実行可能なタスクリスト
- }
- TurtleAI.new = function()
- local obj = {}
- obj.addTask = function(this, task, priority)
- if type(priority)=="number" then task.priority = priority end
- table.insert(this.tasks, task)
- end
- obj.pp_tasks = function(this)
- for i,v in ipairs(this.tasks) do
- print(i,': ',v.name)
- end
- end
- obj.get_executable_tasks = function(this)
- local tmp = {}
- for i,task in ipairs(this.tasks) do
- if task:can_execute() then
- table.insert(tmp, task)
- end
- end
- return tmp
- end
- obj.resolve_conflict = function(this)
- local best_task
- for i,task in ipairs(this.executable_tasks) do
- if not best_task then
- best_task = task
- else
- -- タスクのpriority値で優先度を決める
- -- priority値が同じならば、最近実行したものほど優先度を下げる
- local p = task.priority
- if best_task.priority > p then
- best_task = task
- elseif best_task.priority == p then
- if best_task.turn_last_fired > task.turn_last_fired then
- best_task = task
- end
- end
- end
- end
- return best_task
- end
- obj.iterate = function(this,max_turn)
- max_turn = max_turn or 500
- return function()
- this.executable_tasks = this:get_executable_tasks()
- local best_task = this:resolve_conflict()
- local status = best_task:execute()
- if status then
- if status == "quit" then return nil end
- best_task.turn_last_fired = TurtleMove.turn
- TurtleMove.turn = TurtleMove.turn + 1
- else
- best_task.turn_last_fired = TurtleMove.turn
- end
- if TurtleMove.turn>max_turn then
- return nil
- else
- return best_task, TurtleMove.turn, this
- end
- end
- end
- return setmetatable(obj, {__index = TurtleAI})
- end
- function newAI()
- return TurtleAI.new()
- end
- function newTask(...)
- return Task.new(...)
- end
Advertisement
Add Comment
Please, Sign In to add comment