Whitemambaa

Maze AI

Jul 6th, 2013
200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.26 KB | None | 0 0
  1. --By xXxMoNkEyMaNxXx (Whitemambaa)
  2. --annoying autocomplete fixers: doz
  3.  
  4. --[[
  5.     ********************************************
  6.     **BUILD A MAZE AND PLACE THE TURTLE INSIDE**
  7.     ********************************************
  8.  
  9.     The finish should be marked by a block in
  10.     the floor that is different from the rest of
  11.     the maze, and that same block type should be
  12.     placed in slot 1.  You can put fuel in any
  13.     other slots.  The turtle will explore the
  14.     maze completely, then go back to the start
  15.     to do a SPEED RUN!  It will then wander to
  16.     random nodes.
  17.  
  18.     *************
  19.     **HAVE FUN!**
  20.     *************
  21. --]]
  22.  
  23. ---[[
  24. if not turtle then
  25.     math.randomseed(os.time())
  26.     math.random()
  27.  
  28.     local fuel=0
  29.     turtle={
  30.         getFuelLevel=function() return math.random()*1000 end,
  31.         compareDown=function() return math.random()<0.001 end,
  32.         detect=function() return math.random()<0.51 end,
  33.         up=function() fuel=fuel-1 return true end,
  34.         down=function() fuel=fuel-1 return true end,
  35.         forward=function() fuel=fuel-1 return true end,
  36.         back=function() fuel=fuel-1 return true end,
  37.         turnLeft=function() return true end,
  38.         turnRight=function() return true end,
  39.         refuel=function(n) fuel=fuel+n return true end,
  40.         select=function() return true end,
  41.         getItemCount=function(s) return 64 end,
  42.     }
  43.  
  44.     sleep=function() end
  45. end
  46. --]]
  47.  
  48. local tick=os.clock
  49.  
  50. local next=next
  51. local abs=math.abs
  52. local max=math.max
  53. local min=math.min
  54.  
  55. local insert=table.insert
  56. local remove=table.remove
  57.  
  58. --Stolen from my vec.lua--
  59. local vec={}
  60. function vec.add(a,b)
  61.     local new={}
  62.     for d=1,max(#a,#b) do
  63.         new[d]=(a[d] or 0)+(b[d] or 0)
  64.     end
  65.     return new
  66. end
  67. function vec.sub(a,b)
  68.     local new={}
  69.     for d=1,max(#a,#b) do
  70.         new[d]=(a[d] or 0)-(b[d] or 0)
  71.     end
  72.     return new
  73. end
  74. function vec.tostring(a)
  75.     local new=tostring(a[1])
  76.     for d=2,#a do
  77.         new=new..", "..tostring(a[d])
  78.     end
  79.     return new
  80. end
  81. --------------------------
  82. local function distance(v3a,v3b)
  83.     local dx,dy,dz=v3b[1]-v3a[1],v3b[2]-v3a[2],v3b[3]-v3a[3]
  84.     return abs(dx*dx)+abs(dy*dy)+abs(dz*dz)
  85. end
  86.  
  87. local start=1
  88. local finish
  89.  
  90. local nodes={{0,0,0}}
  91. local links={{}}--Adjacent nodes indexed by direction
  92. local state={}--Exploring state of the node
  93. local known=0--Number of nodes that have no unexplored adjacent nodes
  94.  
  95. local pos=1
  96. local dir=1
  97.  
  98. local units={{0,0,1},{-1,0,0},{0,0,-1},{1,0,0}}
  99. local unitNames={"N","W","S","E"}
  100.  
  101. local function getDir(a,b)
  102.     local d=vec.sub(b,a)
  103.     if d[1]==1 then
  104.         return 4
  105.     elseif d[3]==1 then
  106.         return 1
  107.     elseif d[1]==-1 then
  108.         return 2
  109.     elseif d[3]==-1 then
  110.         return 3
  111.     end
  112. end
  113.  
  114. local function getRealFuel()
  115.     local f=turtle.getFuelLevel()
  116.     return type(f)=="number" and f or math.huge
  117. end
  118.  
  119. local function refuel(req)
  120.     while getRealFuel()<req do
  121.         for s=2,16 do
  122.             if turtle.getItemCount(s)>0 then
  123.                 turtle.select(s)
  124.                 turtle.refuel(1)
  125.             end
  126.         end
  127.         sleep(1)
  128.     end
  129.     turtle.select(1)
  130. end
  131.  
  132. local function update(jumps,nodeId)
  133.     local dis=jumps[nodeId]+1
  134.     local addToQueue={}
  135.     for _,i in next,links[nodeId] do
  136.         if not jumps[i] or jumps[i]>dis then
  137.             jumps[i]=dis
  138.             addToQueue[#addToQueue+1]=i
  139.         end
  140.     end
  141.     return addToQueue
  142. end
  143.  
  144. local function jumpMap(pos,nodeId)--Non-recursive pathfinding ;)
  145.     local point=nodes[pos]
  146.     local jumps={[nodeId]=0}
  147.     local queue={nodeId}
  148.     local best=math.huge
  149.     repeat
  150.         local b,q=math.huge
  151.         for i=1,#queue do
  152.             local j=queue[i]
  153.             local dis=distance(nodes[j],point)+jumps[j]
  154.             if jumps[pos] then
  155.                 if dis<best then
  156.                     best,q=dis,i
  157.                 end
  158.             elseif dis<b then
  159.                 b,q=dis,i
  160.                 if b<best then
  161.                     best=b
  162.                 end
  163.             end
  164.         end
  165.         if q then
  166.             local addToQueue=update(jumps,remove(queue,q))
  167.             for i=1,#addToQueue do
  168.                 queue[#queue+1]=addToQueue[i]
  169.             end
  170.         else
  171.             break
  172.         end
  173.     until #queue==0
  174.     return jumps
  175. end
  176.  
  177. local function register(node,parent)
  178.     local p=nodes[parent]
  179.     for i=1,#nodes do
  180.         local n=nodes[i]
  181.         if n[1]==node[1] and n[2]==node[2] and n[3]==node[3] then
  182.             links[i][getDir(n,p)]=parent
  183.             links[parent][getDir(p,n)]=i
  184.             return not state[i]
  185.         end
  186.     end
  187.     local i=#nodes+1
  188.     nodes[i]=node
  189.     links[i]={}
  190.     links[i][getDir(node,p)]=parent
  191.     links[parent][getDir(p,node)]=i
  192.     return true
  193. end
  194.  
  195. local function turn(turns)-- + is Left
  196.     while turns>0 do
  197.         if turtle.turnLeft() then
  198.             turns=turns-1
  199.             dir=dir%4+1
  200.         end
  201.     end
  202.     while turns<0 do
  203.         if turtle.turnRight() then
  204.             turns=turns+1
  205.             dir=(dir-2)%4+1
  206.         end
  207.     end
  208. end
  209.  
  210. local function f(d)
  211.     turn((d-dir+2)%4-2)
  212.     repeat refuel(1) until turtle.forward()
  213.     pos=links[pos][(d-1)%4+1]
  214. end
  215.  
  216. local function b(d)
  217.     turn((d-dir+2)%4-2)
  218.     repeat refuel(1) until turtle.back()
  219.     pos=links[pos][(d+1)%4+1]
  220. end
  221.  
  222. print'There is a finish... right?'
  223.  
  224. print"I'll start exploring. Brb"
  225. do
  226.     local t0=tick()
  227.     while known<#nodes do--Even though known will not be filled in in ascending order, this will only be true when the whole maze has been explored.
  228.         if not state[pos] then
  229.             turn(1)
  230.             state[pos]=-1
  231.             if not turtle.detect() and register(vec.add(nodes[pos],units[dir]),pos) then--Could be logically simpler, but the program would register walls.
  232.                 f(dir)
  233.             end
  234.         elseif state[pos]==-1 then
  235.             turn(-1)
  236.             state[pos]=0
  237.             if not turtle.detect() and register(vec.add(nodes[pos],units[dir]),pos) then
  238.                 f(dir)
  239.             end
  240.         elseif state[pos]==0 then
  241.             turn(-1)
  242.             state[pos]=1
  243.             if not turtle.detect() and register(vec.add(nodes[pos],units[dir]),pos) then
  244.                 f(dir)
  245.             end
  246.         elseif state[pos]==1 then
  247.             if turtle.compareDown() then
  248.                 if finish then
  249.                     print'I found the... other finish'
  250.                 else
  251.                     finish=pos
  252.                     print'I found the finish!'
  253.                 end
  254.             end
  255.             turn(1)
  256.             state[pos]=true
  257.             known=known+1
  258.             if pos~=start then
  259.                 b(dir)
  260.             end
  261.         else
  262.             print'Uh, what am I doing here?'
  263.             print"Whatever, I'll throw some crazy error."
  264.             error"[SEVERE] YO MAMA's SO FAT THAT SHE ACQUIRED PRIORITY OVER ALL OTHER PROCESSES."
  265.         end
  266.     end
  267.     local dt=tick()-t0
  268.     if finish then
  269.         print("Exploring took "..dt.." second"..(dt==1 and "" or "s")..".")
  270.     else
  271.         print"There's no finish you bastard!"
  272.         error'No finish'
  273.     end
  274. end
  275.  
  276. sleep(2)
  277. print'Time for a speed-run!'
  278. sleep(1.5)
  279. for i=3,1,-1 do
  280.     print(i)
  281.     sleep(1)
  282. end
  283. print'Go!'
  284.  
  285. do
  286.     local t0=tick()
  287.     print'Calculating...'
  288.     local jumps=jumpMap(pos,finish)
  289.     local t1=tick()
  290.     if jumps[pos] then
  291.         print("Optimal path found. ("..t1-t0.."s)  Lol, umad?")
  292.         while pos~=finish do
  293.             local best,v
  294.             for d,i in next,links[pos] do
  295.                 if jumps[i] and (not best or jumps[i]<best) then
  296.                     best,v=jumps[i],d
  297.                 end
  298.             end
  299.             f(v)-- :D
  300.         end
  301.         local dt=tick()-t1
  302.         print("WINNER!  "..dt.." SECOND"..(dt==1 and "" or "S")..", A NEW RECORD!  THE CROWD GOES WIIIIILD!")
  303.     else
  304.         print("No path found... ummm, this shouldn't happen.")
  305.     end
  306. end
  307.  
  308. turtle.up()
  309. turtle.up()
  310. turtle.turnLeft()
  311. turtle.turnRight()
  312. turtle.up()
  313. turtle.down()
  314. turtle.turnRight()
  315. turtle.turnLeft()
  316. sleep(10)
  317. turtle.down()
  318. turtle.down()
  319.  
  320. print'Wandering.'
  321.  
  322. repeat
  323.     local target=math.random(#nodes)
  324.     print("Moving to node "..target..".")
  325.     local jumps=jumpMap(pos,target)
  326.     if jumps[pos] and pos~=target then
  327.         repeat
  328.             local best,v
  329.             for d,i in next,links[pos] do
  330.                 if jumps[i] and (not best or jumps[i]<best) then
  331.                     best,v=jumps[i],d
  332.                 end
  333.             end
  334.             f(v)-- :D
  335.         until pos==target
  336.     end
  337. until nil
Advertisement
Add Comment
Please, Sign In to add comment