daily pastebin goal
71%
SHARE
TWEET

ComputerCraft Tutorial: turtle_ai_api_0_2

hevohevo Aug 28th, 2014 704 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top