SHARE
TWEET

ComputerCraft Tutorial: turtle_ai_api_0_2

hevohevo Aug 28th, 2014 550 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- ###################################################################
  2. -- Turtle AI programing API version 0.2
  3. -- (c) 2014 hevohevo. MIT-Style license
  4. -- http://hevohevo.hatenablog.com/
  5. -- Twitter: @hevohevo
  6.  
  7.  
  8. -- ##################################################################
  9. -- 使い方
  10. --[[
  11. os.loadAPI("turtleAI")
  12.  
  13. -- まずはAIオブジェクトを作る
  14. local ai = turtleAI.newAI()
  15.  
  16. -- #################################################
  17. -- [fwd-task追加] AIオブジェクトにタスクを追加する
  18.  
  19. -- ai:addTask(タスク名,優先度) 値が小さいほど優先度は高い
  20. -- 優先度を省略するとデフォルト0
  21. local fwd = ai:addTask('fwd',0)
  22.  
  23. -- task_obj:canRun(info)  タスクが現在の状況で実行可能かどうかを返すメソッドを追加
  24. -- なお省略も可能。デフォルトでは常にtrueを返す。function task_obj:canRun(info) return true end
  25. function fwd:canRun(info)
  26.   if info.getFuelLevel() > 0 then
  27.     return true -- 実行可能ならtrue
  28.   else
  29.     return false -- 実行不可ならfalse
  30.   end
  31. end
  32.  
  33. -- タスクが実際に行う内容を書く
  34. function fwd:run(ctrl)
  35.   ctrl:forward()
  36.   return true -- trueを返すとこのタスク実行後にターンが進む。falseなら進まない。
  37. end
  38.  
  39.  
  40. -- #################################################
  41. -- [fin-task追加] AIオブジェクトにタスクを追加する
  42.  
  43. -- ai:addTask(タスク名,優先度) 値が小さいほど優先度は高い
  44. local fin = ai:addTask('fin',-1)
  45.  
  46. -- タスクが現在の状況で実行可能かどうかを返すメソッドを追加
  47. function fin:canRun(info)
  48.   -- true を返すと実行可能であることを示す。falseなら実行不可
  49.   return info.getBurnOutFuelLevel() >= 5  -- 燃料を5以上使ったら実行可能
  50. end
  51.  
  52. -- タスクが実際に行う内容を書く
  53. function fin:run(ctrl)
  54.   return "quit" -- quitを返すことでルールベースエンジン終了
  55. end
  56.  
  57.  
  58.  
  59. -- #################################################
  60. -- AIエンジンの実行
  61. -- for文でぐるぐる回す。ai:iterate(50)で50ターンまで回して終了
  62. for task, turn in ai:generate(10) do
  63.   print("Turn: ",turn) -- 現在のターン
  64.   print(ai:tasksToString(ai.runable_tasks)) -- 実行可能なタスク一覧
  65.   print(" ran-task: ",task.name) -- 実際に実行したタスク
  66.   print(ai.info:toString()) -- 位置や燃料情報など
  67. end
  68.  
  69. print("Quit")
  70.  
  71. --]]
  72.  
  73. -- ##################################################################
  74. -- Turtle Infoクラス
  75. TurtleInfo = {}
  76.  
  77. TurtleInfo.new = function()
  78.   local obj = {}
  79.   -- インスタンス変数
  80.   obj.turn = 1
  81.   obj.coord = {x=0,y=0,z=0} -- y:depth, x:width, z:height
  82.   obj.direction = 0 -- 0,1,2,3, 時計周り
  83.   obj.initial_fuel = turtle.getFuelLevel()
  84.   obj.memory = {}
  85.  
  86.   -- インスタンスメソッド
  87.   obj.incTurn = function() obj.turn = obj.turn + 1; return obj.turn end
  88.   obj.toString = function() -- プログラムスタート時を基準として、現在の位置と方角を表示する
  89.     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))
  90.   end
  91.   obj.getFuelLevel = function(this) return turtle.getFuelLevel() end
  92.   obj.getBurnOutFuelLevel = function(this) return obj.initial_fuel - turtle.getFuelLevel() end
  93.   return obj
  94. end
  95.  
  96.  
  97.  
  98. TurtleCtrl = {}
  99. local FwHelper = {{ x = 0, z = 1 }, { x = 1, z = 0 }, { x = 0, z = -1 }, { x = -1, z = 0 } }
  100. TurtleCtrl.new = function(info)
  101.   local obj = {}
  102.   -- インスタンス変数
  103.   obj.info = info or TurtleInfo.new()
  104.  
  105.   -- インスタンスメソッド
  106.   obj.store = function(this,key,value)
  107.     this.info.memory[key] = value
  108.     return this.info.memory
  109.   end
  110.   obj.forward = function(this, n)
  111.     n = n or 1
  112.     for i=1,n do
  113.       if turtle.forward() then
  114.         this.info.coord.x = this.info.coord.x + FwHelper[this.info.direction+1].x
  115.         this.info.coord.z = this.info.coord.z + FwHelper[this.info.direction+1].z
  116.       end
  117.     end
  118.   end
  119.   obj.turnLeft = function(this, n)
  120.     n = n or 1
  121.     for i=1,n do
  122.       this.info.direction = (this.info.direction - 1) % 4
  123.       turtle.turnLeft()
  124.     end
  125.   end
  126.   obj.turnRight = function(this, n)
  127.     n = n or 1
  128.     for i=1,n do
  129.       this.info.direction = (this.info.direction + 1) % 4
  130.       turtle.turnRight()
  131.     end
  132.   end
  133.   obj.back = function(this, n)
  134.     n = n or 1
  135.     for i=1,n do
  136.       if turtle.back() then
  137.         this.info.coord.x = this.info.coord.x - FwHelper[this.info.direction+1].x
  138.         this.info.coord.z = this.info.coord.z - FwHelper[this.info.direction+1].z
  139.       end
  140.     end
  141.   end
  142.   obj.up = function(this, n)
  143.     n = n or 1
  144.     for i=1,n do
  145.       if turtle.up() then
  146.         this.info.coord.y = this.info.coord.y + 1
  147.       end
  148.     end
  149.   end
  150.   obj.down = function(this, n)
  151.     n = n or 1
  152.     for i=1,n do
  153.       if turtle.down() then
  154.         this.info.coord.y = this.info.coord.y - 1
  155.       end
  156.     end
  157.   end
  158.   return obj
  159. end
  160.  
  161. -- ################################################################
  162. -- Taskクラス
  163. Task = {}
  164. Task.new = function(name, priority)
  165.   local obj={}
  166.   obj.priority = priority or 0 -- 小さいほど優先度高い
  167.   obj.turn_last_fired = 0  -- AIエンジンにより自動更新
  168.   obj.name = name or tostring(obj)
  169.  
  170.   -- 必ず、trueかfalseを返すこと
  171.   obj.canRun = function(this, info)
  172.     return true
  173.   end
  174.  
  175.   obj.run = function(this, ctrl)
  176.     print(' execute: ',this.name, ' priority=',this.priority)
  177.     -- trueを返すと次のターンへ、falseを返すともう一度タスクリストから実行
  178.     return true
  179.   end
  180.  
  181.   return setmetatable(obj, {__index = Task})
  182. end
  183.  
  184. -- ###############################################################
  185. -- Turtle AIクラス
  186.  
  187. local within = function(arg, array)
  188.   for i,v in ipairs(array) do
  189.     if arg == v then return true end
  190.   end
  191.   return false
  192. end
  193.  
  194. TurtleAI = {
  195.   tasksToString = function(this, tasks)
  196.     if type(tasks)=="table" and tasks[1].name then
  197.       local tmp = " runable:"
  198.       for i,v in ipairs(tasks) do
  199.         tmp = tmp.." "..v.name.."("..v.priority..")"
  200.       end
  201.       return tmp
  202.     else
  203.       return " runable: none"
  204.     end
  205.   end
  206. }
  207. TurtleAI.new = function()
  208.   local obj = {}
  209.   -- インスタンス変数
  210.   obj.tasks = {}
  211.   obj.runable_tasks = {}
  212.  
  213.   -- インスタンスメソッド
  214.   obj.info = TurtleInfo.new()
  215.   obj.ctrl = TurtleCtrl.new(obj.info)
  216.   obj.addTask = function(this, name, priority)
  217.     local task = Task.new(name, priority)
  218.     table.insert(this.tasks, task)
  219.     return task
  220.   end
  221.  
  222.   obj.printTasks = function(this)
  223.     for i,v in ipairs(this.tasks) do
  224.       print(i,': ',v.name)
  225.     end
  226.   end
  227.  
  228.   obj.getRunableTasks = function(this)
  229.     local tmp = {}
  230.     for i,t in ipairs(this.tasks) do
  231.       if t:canRun(this.info) then
  232.         table.insert(tmp, t)
  233.       end
  234.     end
  235.     return tmp
  236.   end
  237.  
  238.   obj.resolveConflict = function(this)
  239.     local best_task
  240.     for i,task in ipairs(this.runable_tasks) do
  241.       if not best_task then
  242.         best_task = task
  243.       else
  244.         -- タスクのpriority値で優先度を決める
  245.         -- priority値が同じならば、最近実行したものほど優先度を下げる
  246.         local p = task.priority
  247.         if best_task.priority > p then
  248.           best_task = task
  249.         elseif best_task.priority == p then
  250.           if best_task.turn_last_fired > task.turn_last_fired then
  251.             best_task = task
  252.           end
  253.         end
  254.  
  255.       end
  256.     end
  257.     return best_task
  258.   end
  259.  
  260.   obj.generate = function(this,max_turn)
  261.     max_turn = max_turn or 500
  262.     return function()
  263.       this.runable_tasks = this:getRunableTasks()
  264.       local best_task = this:resolveConflict()
  265.       local status = best_task:run(this.ctrl)
  266.       if status then
  267.         if status == "quit" then return nil end
  268.         best_task.turn_last_fired = this.info.turn
  269.         this.info.incTurn()
  270.       else
  271.         best_task.turn_last_fired = this.info.turn
  272.       end
  273.       if this.info.turn>max_turn then
  274.         return nil
  275.       else
  276.         return best_task, this.info.turn
  277.       end
  278.     end
  279.   end
  280.  
  281.   return setmetatable(obj, {__index = TurtleAI})
  282. end
  283.  
  284.  
  285. function newAI()
  286.   return TurtleAI.new()
  287. end
  288.  
  289. function newTask(...)
  290.   return Task.new(...)
  291. end
RAW Paste Data
Top