Advertisement
joebodo

TL2.lua

May 15th, 2014
631
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 25.04 KB | None | 0 0
  1. if not turtle then
  2.   return
  3. end
  4.  
  5. Point = { }
  6. function Point.copy(pt)
  7.   return { x = pt.x, y = pt.y, z = pt.z }
  8. end
  9.  
  10. function Point.subtract(a, b)
  11.   a.x = a.x - b.x
  12.   a.y = a.y - b.y
  13.   a.z = a.z - b.z
  14. end
  15.  
  16. -- real distance
  17. function Point.pythagoreanDistance(a, b)
  18.   return math.sqrt(
  19.            math.pow(a.x - b.x, 2) +
  20.            math.pow(a.y - b.y, 2) +
  21.            math.pow(a.z - b.z, 2))
  22. end
  23.  
  24. -- turtle distance
  25. function Point.turtleDistance(a, b)
  26.   if b.z then
  27.     return math.max(a.x, b.x) - math.min(a.x, b.x) +
  28.            math.max(a.y, b.y) - math.min(a.y, b.y) +
  29.            math.max(a.z, b.z) - math.min(a.z, b.z)
  30.   else
  31.     return math.max(a.x, b.x) - math.min(a.x, b.x) +
  32.            math.max(a.y, b.y) - math.min(a.y, b.y)
  33.   end
  34. end
  35.  
  36. function Point.calculateTurns(ih, oh)
  37.   if ih == oh then
  38.     return 0
  39.   end
  40.   if (ih % 2) == (oh % 2) then
  41.     return 2
  42.   end
  43.   return 1
  44. end
  45.  
  46. -- Calculate distance to location including turns
  47. -- also returns the resulting heading
  48. function Point.calculateMoves(pta, ptb, distance)
  49.   local heading = pta.heading
  50.   local moves = distance or Point.turtleDistance(pta, ptb)
  51.   if (pta.heading % 2) == 0 and pta.y ~= ptb.y then
  52.     moves = moves + 1
  53.     if ptb.heading and (ptb.heading % 2 == 1) then
  54.       heading = ptb.heading
  55.     elseif ptb.y > pta.y then
  56.       heading = 1
  57.     else
  58.       heading = 3
  59.     end
  60.   elseif (pta.heading % 2) == 1 and pta.x ~= ptb.x then
  61.     moves = moves + 1
  62.     if ptb.heading and (ptb.heading % 2 == 0) then
  63.       heading = ptb.heading
  64.     elseif ptb.x > pta.x then
  65.       heading = 0
  66.     else
  67.       heading = 2
  68.     end
  69.   end
  70.  
  71.   if ptb.heading then
  72.     if heading ~= ptb.heading then
  73.       moves = moves + Point.calculateTurns(heading, ptb.heading)
  74.       heading = ptb.heading
  75.     end
  76.   end
  77.  
  78.   return moves, heading
  79. end
  80.  
  81. function Point.toBox(pt, width, length, height)
  82.   return { ax = pt.x,
  83.            ay = pt.y,
  84.            az = pt.z,
  85.            bx = pt.x + width - 1,
  86.            by = pt.y + length - 1,
  87.            bz = pt.z + height - 1
  88.          }
  89. end
  90.  
  91. function Point.inBox(pt, box)
  92.   return pt.x >= box.ax and
  93.          pt.y >= box.ay and
  94.          pt.x <= box.bx and
  95.          pt.y <= box.by
  96. end
  97.  
  98. Box = { }
  99.  
  100. function Box.contain(boundingBox, containedBox)
  101.  
  102.   local shiftX = boundingBox.ax - containedBox.ax
  103.   if shiftX > 0 then
  104.     containedBox.ax = containedBox.ax + shiftX
  105.     containedBox.bx = containedBox.bx + shiftX
  106.   end
  107.   local shiftY = boundingBox.ay - containedBox.ay
  108.   if shiftY > 0 then
  109.     containedBox.ay = containedBox.ay + shiftY
  110.     containedBox.by = containedBox.by + shiftY
  111.   end
  112.  
  113.   shiftX = boundingBox.bx - containedBox.bx
  114.   if shiftX < 0 then
  115.     containedBox.ax = containedBox.ax + shiftX
  116.     containedBox.bx = containedBox.bx + shiftX
  117.   end
  118.   shiftY = boundingBox.by - containedBox.by
  119.   if shiftY < 0 then
  120.     containedBox.ay = containedBox.ay + shiftY
  121.     containedBox.by = containedBox.by + shiftY
  122.   end
  123. end
  124.  
  125. TL2 = { }
  126.  
  127. local function noop() end
  128.  
  129. if not _G.turtleApi then
  130.   _G.turtleApi = Util.shallowCopy(turtle)
  131. end
  132.  
  133. function TL2.replaceApi()
  134.   for k,m in pairs(TL2) do
  135.     turtle[k] = TL2[k]
  136.   end
  137. end
  138.  
  139. local state = {
  140.   pt = { x = 0, y = 0, z = 0, heading = 0 },
  141.   slot = 1,
  142.   moveAttack = noop,
  143.   moveDig = noop,
  144.   moveCallback = noop,
  145.   locations = {},
  146. }
  147.  
  148. function TL2.getState()
  149.   return state
  150. end
  151.  
  152. function TL2.setPoint(pt)
  153.   state.pt.x = pt.x
  154.   state.pt.y = pt.y
  155.   state.pt.z = pt.z
  156.   if pt.heading then
  157.     state.pt.heading = pt.heading
  158.   end
  159. end
  160.  
  161. TL2.actions = {
  162.   up = {
  163.     detect = turtleApi.detectUp,
  164.     dig = turtleApi.digUp,
  165.     move = turtleApi.up,
  166.     attack = turtleApi.attackUp,
  167.     place = turtleApi.placeUp,
  168.     drop = turtleApi.dropUp,
  169.     suck = turtleApi.suckUp,
  170.     compare = turtleApi.compareUp,
  171.     side = 'top'
  172.   },
  173.   down = {
  174.     detect = turtleApi.detectDown,
  175.     dig = turtleApi.digDown,
  176.     move = turtleApi.down,
  177.     attack = turtleApi.attackDown,
  178.     place = turtleApi.placeDown,
  179.     drop = turtleApi.dropDown,
  180.     suck = turtleApi.suckDown,
  181.     compare = turtleApi.compareDown,
  182.     side = 'bottom'
  183.   },
  184.   forward = {
  185.     detect = turtleApi.detect,
  186.     dig = turtleApi.dig,
  187.     move = turtleApi.forward,
  188.     attack = turtleApi.attack,
  189.     place = turtleApi.place,
  190.     drop = turtleApi.drop,
  191.     suck = turtleApi.suck,
  192.     compare = turtleApi.compare,
  193.     side = 'front'
  194.   },
  195.   back = {
  196.     detect = noop,
  197.     dig = noop,
  198.     move = turtleApi.back,
  199.     attack = noop,
  200.     place = noop,
  201.     suck = noop,
  202.     compare = noop,
  203.     side = 'back'
  204.   },
  205. }
  206.  
  207. TL2.headings = {
  208.   [ 0 ] = { xd =  1, yd =  0, zd =  0, heading = 0, direction = 'east' },
  209.   [ 1 ] = { xd =  0, yd =  1, zd =  0, heading = 1, direction = 'south' },
  210.   [ 2 ] = { xd = -1, yd =  0, zd =  0, heading = 2, direction = 'west' },
  211.   [ 3 ] = { xd =  0, yd = -1, zd =  0, heading = 3, direction = 'north' },
  212.   [ 4 ] = { xd =  0, yd =  0, zd =  1, heading = 4, direction = 'up' },
  213.   [ 5 ] = { xd =  0, yd =  0, zd = -1, heading = 5, direction = 'down' }
  214. }
  215.  
  216. TL2.namedHeadings = {
  217.   east  = TL2.headings[0],
  218.   south = TL2.headings[1],
  219.   west  = TL2.headings[2],
  220.   north = TL2.headings[3],
  221.   up    = TL2.headings[4],
  222.   down  = TL2.headings[5]
  223. }
  224.  
  225. -- [[ Basic turtle actions ]] --
  226. local function _attack(action)
  227.   if action.attack() then
  228.     repeat until not action.attack()
  229.     return true
  230.   end
  231.   return false
  232. end
  233.  
  234. function TL2.attack()        return _attack(TL2.actions.forward) end
  235. function TL2.attackUp()      return _attack(TL2.actions.up)      end
  236. function TL2.attackDown()    return _attack(TL2.actions.down)    end
  237.  
  238. local function _place(action, slot)
  239.  
  240.   if slot and turtleApi.getItemCount(slot) == 0 then
  241.     return false, 'No items to place'
  242.   end
  243.  
  244.   return Util.tryTimes(3, function()
  245.     if slot then
  246.       TL2.select(slot)
  247.     end
  248.     local result = { action.place() }
  249.     if result[1] then
  250.       return true
  251.     end
  252.     if not state.moveDig(action) then
  253.       state.moveAttack(action)
  254.     end
  255.     return unpack(result)
  256.   end)
  257. end
  258.  
  259. function TL2.place(slot)     return _place(TL2.actions.forward, slot) end
  260. function TL2.placeUp(slot)   return _place(TL2.actions.up, slot)      end
  261. function TL2.placeDown(slot) return _place(TL2.actions.down, slot)    end
  262.  
  263. local function _drop(action, count, slot)
  264.   if slot then
  265.     if turtleApi.getItemCount(slot) == 0 then
  266.       return false, 'No items to drop'
  267.     end
  268.     TL2.select(slot)
  269.   end
  270.   return action.drop(count)
  271. end
  272.  
  273. function TL2.drop(count, slot)     return _drop(actions.forward, count, slot) end
  274. function TL2.dropUp(count, slot)   return _drop(actions.up, count, slot)      end
  275. function TL2.dropDown(count, slot) return _drop(actions.down, count, slot)    end
  276.  
  277. --[[
  278. function TL2.dig()           return state.dig(TL2.actions.forward) end
  279. function TL2.digUp()         return state.dig(TL2.actions.up)      end
  280. function TL2.digDown()       return state.dig(TL2.actions.down)    end
  281. --]]
  282.  
  283. function TL2.isTurtleAt(side)
  284.   local sideType = peripheral.getType(side)
  285.   return sideType and sideType == 'turtle'
  286. end
  287.  
  288. TL2.attackPolicy = {
  289.   none = noop,
  290.  
  291.   attack = function(action)
  292.     return _attack(action)
  293.   end,
  294. }
  295.  
  296. TL2.digPolicy = {
  297.   none = noop,
  298.  
  299.   dig = function(action)
  300.     return action.dig()
  301.   end,
  302.  
  303.   turtleSafe = function(action)
  304.     if not TL2.isTurtleAt(action.side) then
  305.       return action.dig()
  306.     end
  307.     os.sleep(.5)
  308.     return not action.detect()
  309.   end,
  310.  
  311.   digAndDrop = function(action)
  312.     if action.detect() then
  313.       local slots = TL2.getSlots()
  314.       if action.dig() then
  315.         TL2.reconcileSlots(slots)
  316.         return true
  317.       end
  318.     end
  319.     return false
  320.   end
  321. }
  322.  
  323. TL2.policies = {
  324.   none       = { dig = TL2.digPolicy.none, attack = TL2.attackPolicy.none },
  325.   digOnly    = { dig = TL2.digPolicy.dig,  attack = TL2.attackPolicy.none },
  326.   attackOnly = { dig = TL2.digPolicy.none, attack = TL2.attackPolicy.attack },
  327.   digAttack  = { dig = TL2.digPolicy.dig,  attack = TL2.attackPolicy.attack },
  328. }
  329.  
  330. function TL2.setPolicy(policy)
  331.   state.moveDig = policy.dig
  332.   state.moveAttack = policy.attack
  333. end
  334.  
  335. function TL2.setDigPolicy(policy)
  336.   state.moveDig = policy
  337. end
  338.  
  339. function TL2.setAttackPolicy(policy)
  340.   state.moveAttack = policy
  341. end
  342.  
  343. function TL2.setMoveCallback(cb)
  344.   state.moveCallback = cb
  345. end
  346.  
  347. function TL2.clearMoveCallback()
  348.   state.moveCallback = noop
  349. end
  350.  
  351. local function infoMoveCallback()
  352.   local pt = TL2.getState().pt
  353.   print(string.format('x:%d y:%d z:%d heading:%d', pt.x, pt.y, pt.z, pt.heading))
  354. end
  355. -- TESTING
  356. --TL2.setMoveCallback(infoMoveCallback)
  357.  
  358. -- [[ Locations ]] --
  359. function TL2.getLocation(name)
  360.   return state.locations[name]
  361. end
  362.  
  363. function TL2.saveLocation(name, pt)
  364.   pt = pt or state.pt
  365.   state.locations[name] = Point.copy(pt)
  366. end
  367.  
  368. function TL2.gotoLocation(name)
  369.   local pt = TL2.getLocation(name)
  370.   if pt then
  371.     return TL2.goto(pt.x, pt.y, pt.z, pt.heading)
  372.   end
  373. end
  374.  
  375. function TL2.storeLocation(name, pt)
  376.   pt = pt or state.pt
  377.   Util.writeTable(name .. '.pt', pt)
  378. end
  379.  
  380. function TL2.loadLocation(name)
  381.   return Util.readTable(name .. '.pt')
  382. end
  383.  
  384. function TL2.gotoStoredLocation(name)
  385.   local pt = TL2.loadLocation(name)
  386.   if pt then
  387.     return TL2.gotoPoint(pt)
  388.   end
  389. end
  390.  
  391. -- [[ Heading ]] --
  392. function TL2.getHeading()
  393.   return state.pt.heading
  394. end
  395.  
  396. function TL2.turnRight()
  397.   TL2.setHeading(state.pt.heading + 1)
  398.   return state.pt
  399. end
  400.  
  401. function TL2.turnLeft()
  402.   TL2.setHeading(state.pt.heading - 1)
  403.   return state.pt
  404. end
  405.  
  406. function TL2.turnAround()
  407.   TL2.setHeading(state.pt.heading + 2)
  408.   return state.pt
  409. end
  410.  
  411. function TL2.getHeadingInfo(heading)
  412.   if heading and type(heading) == 'string' then
  413.     return TL2.namedHeadings[heading]
  414.   end
  415.   heading = heading or state.pt.heading
  416.   return TL2.headings[heading]
  417. end
  418.  
  419. function TL2.setNamedHeading(headingName)
  420.   local headingInfo = TL2.namedHeadings[headingName]
  421.   if headingInfo then
  422.     TL2.setHeading(headingInfo.heading)
  423.   end
  424.   return false, 'Invalid heading'
  425. end
  426.  
  427. function TL2.setHeading(heading)
  428.   if not heading then
  429.     return
  430.   end
  431.  
  432.   heading = heading % 4
  433.   if heading ~= state.pt.heading then
  434.     while heading < state.pt.heading do
  435.       heading = heading + 4
  436.     end
  437.     if heading - state.pt.heading == 3 then
  438.       turtleApi.turnLeft()
  439.       state.pt.heading = state.pt.heading - 1
  440.     else
  441.       turns = heading - state.pt.heading
  442.       while turns > 0 do
  443.         turns = turns - 1
  444.         state.pt.heading = state.pt.heading + 1
  445.         turtleApi.turnRight()
  446.       end
  447.     end
  448.  
  449.     state.pt.heading = state.pt.heading % 4
  450.     state.moveCallback('turn', state.pt)
  451.   end
  452. end
  453.  
  454. function TL2.headTowardsX(dx)
  455.   if state.pt.x ~= dx then
  456.     if state.pt.x > dx then
  457.       TL2.setHeading(2)
  458.     else
  459.       TL2.setHeading(0)
  460.     end
  461.   end
  462. end
  463.  
  464. function TL2.headTowardsY(dy)
  465.   if state.pt.y ~= dy then
  466.     if state.pt.y > dy then
  467.       TL2.setHeading(3)
  468.     else
  469.       TL2.setHeading(1)
  470.     end
  471.   end
  472. end
  473.  
  474. function TL2.headTowards(pt)
  475.   if state.pt.x ~= pt.x then
  476.     TL2.headTowardsX(pt.x)
  477.   else
  478.     TL2.headTowardsY(pt.y)
  479.   end
  480. end
  481.  
  482. -- [[ move ]] --
  483. local function _move(action)
  484.   while not action.move() do
  485.     if not state.moveDig(action) and not state.moveAttack(action) then
  486.       return false
  487.     end
  488.   end
  489.   return true
  490. end
  491.  
  492. function TL2.up()
  493.   if _move(TL2.actions.up) then
  494.     state.pt.z = state.pt.z + 1
  495.     state.moveCallback('up', state.pt)
  496.     return true, state.pt
  497.   end
  498. end
  499.  
  500. function TL2.down()
  501.   if _move(TL2.actions.down) then
  502.     state.pt.z = state.pt.z - 1
  503.     state.moveCallback('down', state.pt)
  504.     return true, state.pt
  505.   end
  506. end
  507.  
  508. function TL2.forward()
  509.   if _move(TL2.actions.forward) then
  510.     state.pt.x = state.pt.x + TL2.headings[state.pt.heading].xd
  511.     state.pt.y = state.pt.y + TL2.headings[state.pt.heading].yd
  512.     state.moveCallback('forward', state.pt)
  513.  
  514.     return true, state.pt
  515.   end
  516. end
  517.  
  518. function TL2.back()
  519.   if _move(TL2.actions.back) then
  520.     state.pt.x = state.pt.x - TL2.headings[state.pt.heading].xd
  521.     state.pt.y = state.pt.y - TL2.headings[state.pt.heading].yd
  522.     state.moveCallback('back', state.pt)
  523.     return true, state.pt
  524.   end
  525. end
  526.  
  527. function TL2.moveTowardsX(dx)
  528.  
  529.   local direction = dx - state.pt.x
  530.   local move
  531.   if direction > 0 and state.pt.heading == 0 or
  532.      direction < 0 and state.pt.heading == 2 then
  533.     move = TL2.forward
  534.   else
  535.     move = TL2.back
  536.   end
  537.  
  538.   repeat
  539.     if not move() then
  540.       return false
  541.     end
  542.   until state.pt.x == dx
  543.   return true
  544. end
  545.  
  546. function TL2.moveTowardsY(dy)
  547.  
  548.   local direction = dy - state.pt.y
  549.   local move
  550.   if direction > 0 and state.pt.heading == 1 or
  551.      direction < 0 and state.pt.heading == 3 then
  552.     move = TL2.forward
  553.   else
  554.     move = TL2.back
  555.   end
  556.  
  557.   repeat
  558.     if not move() then
  559.       return false
  560.     end
  561.   until state.pt.y == dy
  562.   return true
  563. end
  564.  
  565. -- [[ go ]] --
  566. function TL2.gotoPoint(pt)
  567.   return TL2.goto(pt.x, pt.y, pt.z, pt.heading)
  568. end
  569.  
  570. -- go backwards - turning around if necessary to fight mobs / break blocks
  571. function TL2.goback()
  572.   local hi = TL2.headings[state.pt.heading]
  573.   return TL2.goto(state.pt.x - hi.xd, state.pt.y - hi.yd, state.pt.z, state.pt.heading)
  574. end
  575.  
  576. function TL2.gotoZlast(pt)
  577.   if TL2.goto(pt.x, pt.y, nil, pt.heading) then
  578.     if TL2.gotoZ(pt.z) then
  579.       TL2.setHeading(pt.heading)
  580.     end
  581.   end
  582. end
  583.  
  584. function TL2.goto(dx, dy, dz, dh)
  585.   if not TL2.gotoSingleTurn(dx, dy, dz, dh) then
  586.     if not TL2.gotoMultiTurn(dx, dy, dz) then
  587.       return false
  588.     end
  589.   end
  590.   TL2.setHeading(dh)
  591.   return true
  592. end
  593.  
  594. -- 1 turn goto (going backwards if possible)
  595. function TL2.gotoSingleTurn(dx, dy, dz, dh)
  596.  
  597.   dz = dz or state.pt.z
  598.  
  599.   local function gx()
  600.     if state.pt.x ~= dx then
  601.       TL2.moveTowardsX(dx)
  602.     end
  603.     if state.pt.y ~= dy then
  604.       if dh and dh % 2 == 1 then
  605.         TL2.setHeading(dh)
  606.       else
  607.         TL2.headTowardsY(dy)
  608.       end
  609.     end
  610.   end
  611.  
  612.   local function gy()
  613.     if state.pt.y ~= dy then
  614.       TL2.moveTowardsY(dy)
  615.     end
  616.     if state.pt.x ~= dx then
  617.       if dh and dh % 2 == 0 then
  618.         TL2.setHeading(dh)
  619.       else
  620.         TL2.headTowardsX(dx)
  621.       end
  622.     end
  623.   end
  624.  
  625.   repeat
  626.     local x, y
  627.     local z = state.pt.z
  628.  
  629.     repeat
  630.       x, y = state.pt.x, state.pt.y
  631.  
  632.       if state.pt.heading % 2 == 0 then
  633.         gx()
  634.         gy()
  635.       else
  636.         gy()
  637.         gx()
  638.       end
  639.     until x == state.pt.x and y == state.pt.y
  640.  
  641.     if state.pt.z ~= dz then
  642.       TL2.gotoZ(dz)
  643.     end
  644.  
  645.     if state.pt.x == dx and state.pt.y == dy and state.pt.z == dz then
  646.       return true
  647.     end
  648.  
  649.   until x == state.pt.x and y == state.pt.y and z == state.pt.z
  650.  
  651.   return false
  652. end
  653.  
  654. -- fallback goto - will turn around if was previously moving backwards
  655. function TL2.gotoMultiTurn(dx, dy, dz)
  656.  
  657.   if TL2.gotoEx(dx, dy, dz) then
  658.     return true
  659.   end
  660.  
  661.   local moved
  662.   repeat
  663.     local x, y, z = state.pt.x, state.pt.y, state.pt.z
  664.  
  665.     -- try going the other way
  666.     if (state.pt.heading % 2) == 1 then
  667.       TL2.headTowardsX(dx)
  668.     else
  669.       TL2.headTowardsY(dy)
  670.     end
  671.  
  672.     if TL2.gotoEx(dx, dy, dz) then
  673.       return true
  674.     end
  675.  
  676.     if dz then
  677.       TL2.gotoZ(dz)
  678.     end
  679.  
  680.     moved = x ~= state.pt.x or y ~= state.pt.y or z ~= state.pt.z
  681.   until not moved
  682.  
  683.   return false
  684. end
  685.  
  686. function TL2.gotoEx(dx, dy, dz)
  687.  
  688.   -- determine the heading to ensure the least amount of turns
  689.   -- first check is 1 turn needed - remaining require 2 turns
  690.   if state.pt.heading == 0 and state.pt.x <= dx or
  691.      state.pt.heading == 2 and state.pt.x >= dx or
  692.      state.pt.heading == 1 and state.pt.y <= dy or
  693.      state.pt.heading == 3 and state.pt.y >= dy then
  694.     -- maintain current heading
  695.     -- nop
  696.   elseif dy > state.pt.y and state.pt.heading == 0 or
  697.          dy < state.pt.y and state.pt.heading == 2 or
  698.          dx < state.pt.x and state.pt.heading == 1 or
  699.          dx > state.pt.x and state.pt.heading == 3 then
  700.     TL2.turnRight()
  701.   else
  702.     TL2.turnLeft()
  703.   end
  704.  
  705.   if (state.pt.heading % 2) == 1 then
  706.     if not TL2.gotoY(dy) then return false end
  707.     if not TL2.gotoX(dx) then return false end
  708.   else
  709.     if not TL2.gotoX(dx) then return false end
  710.     if not TL2.gotoY(dy) then return false end
  711.   end
  712.  
  713.   if dz then
  714.     if not TL2.gotoZ(dz) then return false end
  715.   end
  716.  
  717.   return true
  718. end
  719.  
  720. function TL2.gotoX(dx)
  721.   TL2.headTowardsX(dx)
  722.  
  723.   while state.pt.x ~= dx do
  724.     if not TL2.forward() then
  725.       return false
  726.     end
  727.   end
  728.   return true
  729. end
  730.  
  731. function TL2.gotoY(dy)
  732.   TL2.headTowardsY(dy)
  733.  
  734.   while state.pt.y ~= dy do
  735.     if not TL2.forward() then
  736.       return false
  737.     end
  738.   end
  739.   return true
  740. end
  741.  
  742. function TL2.gotoZ(dz)
  743.   while state.pt.z > dz do
  744.     if not TL2.down() then
  745.       return false
  746.     end
  747.   end
  748.  
  749.   while state.pt.z < dz do
  750.     if not TL2.up() then
  751.       return false
  752.     end
  753.   end
  754.   return true
  755. end
  756.  
  757. -- [[ Slot management ]] --
  758. function TL2.select(slot)
  759.   state.slot = slot
  760.   turtleApi.select(slot)
  761. end
  762.  
  763. function TL2.getInventory(slots)
  764.   slots = slots or { }
  765.   for i = 1, 16 do
  766.     slots[i] = {
  767.       qty = turtleApi.getItemCount(i),
  768.       index = i
  769.     }
  770.   end
  771.   return slots
  772. end
  773.  
  774. function TL2.emptyInventory(dropAction)
  775.   dropAction = dropAction or turtleApi.drop
  776.   for i = 1, 16 do
  777.     TL2.emptySlot(i, dropAction)
  778.   end
  779. end
  780.  
  781. function TL2.emptySlot(slot, dropAction)
  782.   dropAction = dropAction or turtleApi.drop
  783.   local count = turtleApi.getItemCount(slot)
  784.   if count > 0 then
  785.     TL2.select(slot)
  786.     return dropAction(count)
  787.   end
  788.   return false, 'No items to drop'
  789. end
  790.  
  791. function TL2.getFilledSlots(startSlot)
  792.   startSlot = startSlot or 1
  793.  
  794.   local slots = { }
  795.   for i = startSlot, 16 do
  796.     local count = turtleApi.getItemCount(i)
  797.     if count > 0 then
  798.       slots[i] = {
  799.         qty    = turtleApi.getItemCount(i),
  800.         index = i
  801.       }
  802.     end
  803.   end
  804.   return slots
  805. end
  806.  
  807. function TL2.reconcileInventory(slots, dropAction)
  808.   dropAction = dropAction or turtleApi.drop
  809.   for _,s in pairs(slots) do
  810.     local qty = turtleApi.getItemCount(s.index)
  811.     if qty > s.qty then
  812.       TL2.select(s.index)
  813.       dropAction(qty-s.qty, s)
  814.     end
  815.   end
  816. end
  817.  
  818. function TL2.selectSlotWithItems(startSlot)
  819.   startSlot = startSlot or 1
  820.   for i = startSlot, 16 do
  821.     if turtleApi.getItemCount(i) > 0 then
  822.       TL2.select(i)
  823.       return i
  824.     end
  825.   end
  826. end
  827.  
  828. function TL2.selectOpenSlot(startSlot)
  829.   return TL2.selectSlotWithQuantity(0, startSlot)
  830. end
  831.  
  832. function TL2.selectSlotWithQuantity(qty, startSlot)
  833.   startSlot = startSlot or 1
  834.  
  835.   for i = startSlot, 16 do
  836.     if turtleApi.getItemCount(i) == qty then
  837.       TL2.select(i)
  838.       return i
  839.     end
  840.   end
  841. end
  842.  
  843. GPS = { }
  844. function GPS.locate()
  845.   local pt = { }
  846.   pt.x, pt.z, pt.y = gps.locate(10)
  847.   if pt.x then
  848.     return pt
  849.   end
  850. end
  851.  
  852. function GPS.isAvailable()
  853.   return Util.hasDevice("modem") and GPS.locate()
  854. end
  855.  
  856. function GPS.getPoint()
  857.   local pt = Point.copy(state.pt)
  858.  
  859.   local apt = GPS.locate()
  860.   if not apt then
  861.     print("GPS.getPoint: GPS not available")
  862.     return
  863.   end
  864.  
  865.   while not TL2.forward() do
  866.     TL2.turnRight()
  867.     if TL2.getHeading() == pt.heading then
  868.       print('GPS.getPoint: Unable to move forward')
  869.       return
  870.     end
  871.   end
  872.  
  873.   local bpt = GPS.locate()
  874.   if not apt then
  875.     print("No GPS")
  876.     return
  877.   end
  878.  
  879.   if not TL2.back() then
  880.     print("GPS.getPoint: Unable to move back")
  881. --    return
  882.   end
  883.  
  884.   if apt.x < bpt.x then
  885.     apt.heading = 0
  886.   elseif apt.y < bpt.y then
  887.     apt.heading = 1
  888.   elseif apt.x > bpt.x then
  889.     apt.heading = 2
  890.   else
  891.     apt.heading = 3
  892.   end
  893.  
  894.   return apt
  895. end
  896.  
  897. --[[
  898.   All pathfinding related follows
  899.  
  900.   b = block
  901.   a = adjacent block
  902.   bb = bounding box
  903.   c = coordinates
  904. --]]
  905. local function addAdjacentBlock(blocks, b, dir, bb, a)
  906.   local key = a.x .. ':' .. a.y .. ':' .. a.z
  907.  
  908.   if b.adj[dir] then
  909.     a = b.adj[dir]
  910.   else
  911.     local _a = blocks[key]
  912.     if _a then
  913.       a = _a
  914.     else
  915.       blocks[key] = a
  916.     end
  917.   end
  918.   local revDir = { 2, 3, 0, 1, 5, 4 }
  919.   b.adj[dir] = a
  920.   a.adj[revDir[dir+1]] = b
  921. --[[
  922.   -- too much time...
  923.   if dir == 4 and turtle.detectUp() then
  924.     a.blocked = true
  925.   elseif dir == 5 and turtle.detectDown() then
  926.     a.blocked = true
  927.   elseif dir == state.pt.heading and turtle.detect() then
  928.     a.blocked = true
  929. --]]
  930.   if a.x < bb.ax or a.x > bb.bx or
  931.          a.y < bb.ay or a.y > bb.by or
  932.          a.z < bb.az or a.z > bb.bz then
  933.     a.blocked = true
  934.   end
  935. end
  936.  
  937. local function addAdjacentBlocks(blocks, b, bb)
  938.   if not b.setAdj then
  939.     addAdjacentBlock(blocks, b, 0, bb,
  940.       { x = state.pt.x+1, y = state.pt.y  , z = state.pt.z    , adj = {} })
  941.     addAdjacentBlock(blocks, b, 1, bb,
  942.       { x = state.pt.x  , y = state.pt.y+1, z = state.pt.z    , adj = {} })
  943.     addAdjacentBlock(blocks, b, 2, bb,
  944.       { x = state.pt.x-1, y = state.pt.y  , z = state.pt.z    , adj = {} })
  945.     addAdjacentBlock(blocks, b, 3, bb,
  946.       { x = state.pt.x  , y = state.pt.y-1, z = state.pt.z    , adj = {} })
  947.     addAdjacentBlock(blocks, b, 4, bb,
  948.       { x = state.pt.x  , y = state.pt.y  , z = state.pt.z + 1, adj = {} })
  949.     addAdjacentBlock(blocks, b, 5, bb,
  950.       { x = state.pt.x  , y = state.pt.y  , z = state.pt.z - 1, adj = {} })
  951.   end
  952.   b.setAdj = true
  953. end
  954.  
  955. local function calculateAdjacentBlockDistances(b, dest)
  956.   --local pt = state.pt
  957.   for k,a in pairs(b.adj) do
  958.     if not a.blocked then
  959.       --a.distance, a.heading = Point.calculateMoves(pt, a)
  960.       --a.distance = a.distance + Point.calculateMoves(a, dest)
  961.       a.distance = Point.pythagoreanDistance(a, dest)
  962.     else
  963.       a.distance = 9000
  964.     end
  965. --print(string.format('%d: %f %d,%d,%d, %s', k, a.distance, a.x, a.y, a.z, tostring(a.blocked)))
  966.   end
  967. --read()
  968. end
  969.  
  970. local function blockedIn(b)
  971.   for _,a in pairs(b.adj) do
  972.     if not a.blocked then
  973.       return false
  974.     end
  975.   end
  976.   return true
  977. end
  978.  
  979. local function pathfindMove(b)
  980.   for _,a in Util.spairs(b.adj, function(a, b) return a.distance < b.distance end) do
  981.  
  982.     --print('shortest: ' .. pc(a) .. ' distance: ' .. a.distance)
  983.     if not a.blocked then
  984.       local success = TL2.gotoSingleTurn(a.x, a.y, a.z)
  985.       if success then
  986.         return a
  987.       end
  988.       a.blocked = true
  989.     end
  990.   end
  991. end
  992.  
  993. local function rpath(blocks, block, dest, boundingBox)
  994.  
  995.   addAdjacentBlocks(blocks, block, boundingBox)
  996.   calculateAdjacentBlockDistances(block, dest)
  997.  
  998.   block.blocked = true
  999.   repeat
  1000.     local newBlock = pathfindMove(block)
  1001.     if newBlock then
  1002.       if state.pt.x == dest.x and state.pt.y == dest.y and state.pt.z == dest.z then
  1003.         block.blocked = false
  1004.         return true
  1005.       end
  1006.       --[[
  1007.       if goto then return true end
  1008.       block = getCurrentBlock() (gets or creates block)
  1009.       but this might - will - move us into a block we marked as blockedin
  1010.       if block.blocked then
  1011.         goto newBlock
  1012.         block = getCurrentBlock() (gets or creates block)
  1013.       end
  1014.       maybe check if we have a clear line of sight to the destination
  1015.       ie. keep traveling towards destination building up blocked blocks
  1016.       as we encounter them (instead of adding all blocks on the path)
  1017.       --]]
  1018.       if rpath(blocks, newBlock, dest, boundingBox) then
  1019.         block.blocked = false
  1020.         return true
  1021.       end
  1022.       if not TL2.gotoSingleTurn(block.x, block.y, block.z) then
  1023.         return false
  1024.       end
  1025.     end
  1026.   until blockedIn(block)
  1027.   return false
  1028. end
  1029.  
  1030. --[[
  1031.   goto will traverse towards the destination until it is blocked
  1032.   by something on the x, y, or z coordinate of the destination
  1033.  
  1034.   pathfinding will attempt to find a way around the blockage
  1035.  
  1036.   goto example:
  1037.   . . >-X B D stuck behind block
  1038.   . . | . B .
  1039.   . . | . . .
  1040.   S >-^B. . .
  1041.  
  1042.   pathfind example:
  1043.   . . >-v B D when goto fails, pathfinding kicks in
  1044.   . . | |-B-|
  1045.   . . | >---^
  1046.   S >-^B. . .
  1047.  
  1048. --]]
  1049. function TL2.pathtofreely(dx, dy, dz, dh)
  1050.   local boundingBox = {
  1051.       ax = -9000,
  1052.       ay = -9000,
  1053.       az = -9000,
  1054.       bx = 9000,
  1055.       by = 9000,
  1056.       bz = 9000
  1057.     }
  1058.   return TL2.pathto(dx, dy, dz, dh, boundingBox)
  1059. end
  1060.  
  1061. local function pathfind(dx, dy, dz, dh, boundingBox)
  1062.  
  1063.   local blocks = { } -- memory.blocks
  1064.   local dest = { x = dx, y = dy, z = dz }
  1065.   local block = { x = state.pt.x, y = state.pt.y, z = state.pt.z, adj = {} }
  1066.   local key = block.x .. ':' .. block.y .. ':' .. block.z
  1067.  
  1068.   blocks[key] = block
  1069.  
  1070.   if rpath(blocks, block, dest, boundingBox) then
  1071.     TL2.setHeading(dh)
  1072.     return true
  1073.   end
  1074.  
  1075.   return false
  1076. end
  1077.  
  1078. function TL2.pathto(dx, dy, dz, dh, boundingBox)
  1079.   local start = { x = state.pt.x, y = state.pt.y, z = state.pt.z }
  1080.   if TL2.goto(dx, dy, dz, dh) then
  1081.     return true
  1082.   end
  1083.  
  1084.   if not dz then
  1085.     dz = state.pt.z
  1086.   end
  1087.  
  1088.   if not boundingBox then
  1089.     boundingBox = {
  1090.       ax = math.min(dx, start.x),
  1091.       ay = math.min(dy, start.y),
  1092.       az = math.min(dz, start.z),
  1093.       bx = math.max(dx, start.x),
  1094.       by = math.max(dy, start.y),
  1095.       bz = math.max(dz, start.z),
  1096.     }
  1097.   end
  1098.   return pathfind(dx, dy, dz, dh, boundingBox)
  1099. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement