Advertisement
princejoogie

solver.lua

Apr 25th, 2025 (edited)
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.40 KB | Source Code | 0 0
  1. -- my test maze:
  2. --
  3. -- ++++++++
  4. -- +     X+
  5. -- +++ ++ +
  6. -- +    + +
  7. -- + ++ + +
  8. -- +O+    +
  9. -- ++++++++
  10. --
  11. -- moving forward from the start will "move up" the maze
  12. -- === Utility ===
  13. local function key(pos)
  14.     return pos.x .. "," .. pos.y
  15. end
  16.  
  17. local function heuristic(a, b)
  18.     return math.abs(a.x - b.x) + math.abs(a.y - b.y)
  19. end
  20.  
  21. -- === Direction State ===
  22. local pos = { x = 0, y = 0 }
  23. local dir = 0 -- 0=north, 1=east, 2=south, 3=west
  24.  
  25. local directions = {
  26.     [0] = { x = 0, y = -1 },
  27.     [1] = { x = 1, y = 0 },
  28.     [2] = { x = 0, y = 1 },
  29.     [3] = { x = -1, y = 0 },
  30. }
  31.  
  32. local function turnTo(newDir)
  33.     local diff = (newDir - dir) % 4
  34.     if diff == 1 then
  35.         turtle.turnRight()
  36.     elseif diff == 2 then
  37.         turtle.turnRight()
  38.         turtle.turnRight()
  39.     elseif diff == 3 then
  40.         turtle.turnLeft()
  41.     end
  42.     dir = newDir
  43. end
  44.  
  45. local function moveForward()
  46.     if turtle.forward() then
  47.         pos.x = pos.x + directions[dir].x
  48.         pos.y = pos.y + directions[dir].y
  49.         return true
  50.     end
  51.     return false
  52. end
  53.  
  54. -- === World Map ===
  55. local known = {} -- key(pos) -> "open" | "blocked"
  56.  
  57. local function isKnownBlocked(x, y)
  58.     return known[key { x = x, y = y }] == "blocked"
  59. end
  60.  
  61. local function canMoveTo(x, y)
  62.     local k = key { x = x, y = y }
  63.     if known[k] == "blocked" then
  64.         return false
  65.     elseif known[k] == "open" then
  66.         return true
  67.     end
  68.  
  69.     -- Face toward position to test
  70.     for d = 0, 3 do
  71.         local dx, dy = directions[d].x, directions[d].y
  72.         if pos.x + dx == x and pos.y + dy == y then
  73.             turnTo(d)
  74.             if turtle.detect() then
  75.                 known[k] = "blocked"
  76.                 return false
  77.             else
  78.                 known[k] = "open"
  79.                 return true
  80.             end
  81.         end
  82.     end
  83.  
  84.     return false -- unknown and unreachable from current pos
  85. end
  86.  
  87. -- === A* ===
  88. local function popLowestF(openSet, fScore)
  89.     local lowestIndex = 1
  90.     for i = 2, #openSet do
  91.         if fScore[openSet[i]] < fScore[openSet[lowestIndex]] then
  92.             lowestIndex = i
  93.         end
  94.     end
  95.     local node = openSet[lowestIndex]
  96.     table.remove(openSet, lowestIndex)
  97.     return node
  98. end
  99.  
  100. local function neighbors(pos)
  101.     return {
  102.         { x = pos.x, y = pos.y - 1, dir = 0 },
  103.         { x = pos.x + 1, y = pos.y, dir = 1 },
  104.         { x = pos.x, y = pos.y + 1, dir = 2 },
  105.         { x = pos.x - 1, y = pos.y, dir = 3 },
  106.     }
  107. end
  108.  
  109. local function aStar(start, goal)
  110.     local openSet = { key(start) }
  111.     local cameFrom = {}
  112.     local gScore = { [key(start)] = 0 }
  113.     local fScore = { [key(start)] = heuristic(start, goal) }
  114.     local posMap = { [key(start)] = start }
  115.  
  116.     while #openSet > 0 do
  117.         local currentKey = popLowestF(openSet, fScore)
  118.         local current = posMap[currentKey]
  119.  
  120.         if current.x == goal.x and current.y == goal.y then
  121.             local totalPath = { current }
  122.             while cameFrom[currentKey] do
  123.                 currentKey = cameFrom[currentKey]
  124.                 table.insert(totalPath, 1, posMap[currentKey])
  125.             end
  126.             return totalPath
  127.         end
  128.  
  129.         for _, neighbor in ipairs(neighbors(current)) do
  130.             local nk = key(neighbor)
  131.             posMap[nk] = neighbor
  132.  
  133.             if canMoveTo(neighbor.x, neighbor.y) then
  134.                 local tentativeG = gScore[currentKey] + 1
  135.                 if gScore[nk] == nil or tentativeG < gScore[nk] then
  136.                     cameFrom[nk] = currentKey
  137.                     gScore[nk] = tentativeG
  138.                     fScore[nk] = tentativeG + heuristic(neighbor, goal)
  139.  
  140.                     local inOpenSet = false
  141.                     for _, k in ipairs(openSet) do
  142.                         if k == nk then
  143.                             inOpenSet = true
  144.                             break
  145.                         end
  146.                     end
  147.                     if not inOpenSet then
  148.                         table.insert(openSet, nk)
  149.                     end
  150.                 end
  151.             end
  152.         end
  153.     end
  154.  
  155.     return nil -- no path
  156. end
  157.  
  158. -- === Path Executor ===
  159. local function followPath(path)
  160.     for i = 2, #path do
  161.         local curr = path[i - 1]
  162.         local next = path[i]
  163.         for d = 0, 3 do
  164.             if curr.x + directions[d].x == next.x and curr.y + directions[d].y == next.y then
  165.                 turnTo(d)
  166.                 if not moveForward() then
  167.                     print("Failed to move to", next.x, next.y)
  168.                     return false
  169.                 end
  170.                 break
  171.             end
  172.         end
  173.     end
  174.     return true
  175. end
  176.  
  177. -- === Refuel ===
  178. if turtle.getFuelLevel() == 0 then
  179.     turtle.select(1)
  180.     turtle.refuel()
  181. end
  182.  
  183. -- === MAIN ===
  184. local GOAL = { x = 5, y = -4 } -- 'X' relative to 'O' at {0,0}
  185.  
  186. -- Probe adjacent blocks so A* has at least some data
  187. for d = 0, 3 do
  188.     local checkX = pos.x + directions[d].x
  189.     local checkY = pos.y + directions[d].y
  190.     canMoveTo(checkX, checkY)
  191. end
  192.  
  193. print("Starting A* pathfinding...")
  194. local path = aStar(pos, GOAL)
  195.  
  196. if path then
  197.     print("Path found. Following...")
  198.     followPath(path)
  199.     print("Arrived at destination.")
  200. else
  201.     print("No path found!")
  202. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement