Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- ###################################################################
- -- Turtle AI programing API version 0.2
- -- (c) 2014 hevohevo. MIT-Style license
- -- http://hevohevo.hatenablog.com/
- -- Twitter: @hevohevo
- -- ##################################################################
- -- 使い方
- --[[
- os.loadAPI("turtleAI")
- -- まずはAIオブジェクトを作る
- local ai = turtleAI.newAI()
- -- #################################################
- -- [fwd-task追加] AIオブジェクトにタスクを追加する
- -- ai:addTask(タスク名,優先度) 値が小さいほど優先度は高い
- -- 優先度を省略するとデフォルト0
- local fwd = ai:addTask('fwd',0)
- -- task_obj:canRun(info) タスクが現在の状況で実行可能かどうかを返すメソッドを追加
- -- なお省略も可能。デフォルトでは常にtrueを返す。function task_obj:canRun(info) return true end
- function fwd:canRun(info)
- if info.getFuelLevel() > 0 then
- return true -- 実行可能ならtrue
- else
- return false -- 実行不可ならfalse
- end
- end
- -- タスクが実際に行う内容を書く
- function fwd:run(ctrl)
- ctrl:forward()
- return true -- trueを返すとこのタスク実行後にターンが進む。falseなら進まない。
- end
- -- #################################################
- -- [fin-task追加] AIオブジェクトにタスクを追加する
- -- ai:addTask(タスク名,優先度) 値が小さいほど優先度は高い
- local fin = ai:addTask('fin',-1)
- -- タスクが現在の状況で実行可能かどうかを返すメソッドを追加
- function fin:canRun(info)
- -- true を返すと実行可能であることを示す。falseなら実行不可
- return info.getBurnOutFuelLevel() >= 5 -- 燃料を5以上使ったら実行可能
- end
- -- タスクが実際に行う内容を書く
- function fin:run(ctrl)
- return "quit" -- quitを返すことでルールベースエンジン終了
- end
- -- #################################################
- -- AIエンジンの実行
- -- for文でぐるぐる回す。ai:iterate(50)で50ターンまで回して終了
- for task, turn in ai:generate(10) do
- print("Turn: ",turn) -- 現在のターン
- print(ai:tasksToString(ai.runable_tasks)) -- 実行可能なタスク一覧
- print(" ran-task: ",task.name) -- 実際に実行したタスク
- print(ai.info:toString()) -- 位置や燃料情報など
- end
- print("Quit")
- --]]
- -- ##################################################################
- -- Turtle Infoクラス
- TurtleInfo = {}
- TurtleInfo.new = function()
- local obj = {}
- -- インスタンス変数
- obj.turn = 1
- obj.coord = {x=0,y=0,z=0} -- y:depth, x:width, z:height
- obj.direction = 0 -- 0,1,2,3, 時計周り
- obj.initial_fuel = turtle.getFuelLevel()
- obj.memory = {}
- -- インスタンスメソッド
- obj.incTurn = function() obj.turn = obj.turn + 1; return obj.turn end
- obj.toString = function() -- プログラムスタート時を基準として、現在の位置と方角を表示する
- return (string.format(" x/y/z=%d/%d/%d, dir=%d, fuel=%d/%d", obj.coord.x, obj.coord.y, obj.coord.z, obj.direction, turtle.getFuelLevel(), obj.initial_fuel))
- end
- obj.getFuelLevel = function(this) return turtle.getFuelLevel() end
- obj.getBurnOutFuelLevel = function(this) return obj.initial_fuel - turtle.getFuelLevel() end
- return obj
- end
- TurtleCtrl = {}
- local FwHelper = {{ x = 0, z = 1 }, { x = 1, z = 0 }, { x = 0, z = -1 }, { x = -1, z = 0 } }
- TurtleCtrl.new = function(info)
- local obj = {}
- -- インスタンス変数
- obj.info = info or TurtleInfo.new()
- -- インスタンスメソッド
- obj.store = function(this,key,value)
- this.info.memory[key] = value
- return this.info.memory
- end
- obj.forward = function(this, n)
- n = n or 1
- for i=1,n do
- if turtle.forward() then
- this.info.coord.x = this.info.coord.x + FwHelper[this.info.direction+1].x
- this.info.coord.z = this.info.coord.z + FwHelper[this.info.direction+1].z
- end
- end
- end
- obj.turnLeft = function(this, n)
- n = n or 1
- for i=1,n do
- this.info.direction = (this.info.direction - 1) % 4
- turtle.turnLeft()
- end
- end
- obj.turnRight = function(this, n)
- n = n or 1
- for i=1,n do
- this.info.direction = (this.info.direction + 1) % 4
- turtle.turnRight()
- end
- end
- obj.back = function(this, n)
- n = n or 1
- for i=1,n do
- if turtle.back() then
- this.info.coord.x = this.info.coord.x - FwHelper[this.info.direction+1].x
- this.info.coord.z = this.info.coord.z - FwHelper[this.info.direction+1].z
- end
- end
- end
- obj.up = function(this, n)
- n = n or 1
- for i=1,n do
- if turtle.up() then
- this.info.coord.y = this.info.coord.y + 1
- end
- end
- end
- obj.down = function(this, n)
- n = n or 1
- for i=1,n do
- if turtle.down() then
- this.info.coord.y = this.info.coord.y - 1
- end
- end
- end
- return obj
- end
- -- ################################################################
- -- Taskクラス
- Task = {}
- 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.canRun = function(this, info)
- return true
- end
- obj.run = function(this, ctrl)
- 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 = {
- tasksToString = function(this, tasks)
- if type(tasks)=="table" and tasks[1].name then
- local tmp = " runable:"
- for i,v in ipairs(tasks) do
- tmp = tmp.." "..v.name.."("..v.priority..")"
- end
- return tmp
- else
- return " runable: none"
- end
- end
- }
- TurtleAI.new = function()
- local obj = {}
- -- インスタンス変数
- obj.tasks = {}
- obj.runable_tasks = {}
- -- インスタンスメソッド
- obj.info = TurtleInfo.new()
- obj.ctrl = TurtleCtrl.new(obj.info)
- obj.addTask = function(this, name, priority)
- local task = Task.new(name, priority)
- table.insert(this.tasks, task)
- return task
- end
- obj.printTasks = function(this)
- for i,v in ipairs(this.tasks) do
- print(i,': ',v.name)
- end
- end
- obj.getRunableTasks = function(this)
- local tmp = {}
- for i,t in ipairs(this.tasks) do
- if t:canRun(this.info) then
- table.insert(tmp, t)
- end
- end
- return tmp
- end
- obj.resolveConflict = function(this)
- local best_task
- for i,task in ipairs(this.runable_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.generate = function(this,max_turn)
- max_turn = max_turn or 500
- return function()
- this.runable_tasks = this:getRunableTasks()
- local best_task = this:resolveConflict()
- local status = best_task:run(this.ctrl)
- if status then
- if status == "quit" then return nil end
- best_task.turn_last_fired = this.info.turn
- this.info.incTurn()
- else
- best_task.turn_last_fired = this.info.turn
- end
- if this.info.turn>max_turn then
- return nil
- else
- return best_task, this.info.turn
- 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
Advertisement