Advertisement
NickM13

[ComputerCraft] Turtle Maze Solver

Jun 2nd, 2015
297
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.75 KB | None | 0 0
  1. --[[
  2. Do not delete this comment
  3.  
  4. Written by NickM13
  5. Maze Mapper v1.0
  6.  
  7. Map any generated maze, as long as
  8. it does not contain loops or
  9. blocked regions, and saves data
  10. to a file.
  11.  
  12. Place turtle in bottom left corner, facing along the left side,
  13. the turtle will map any maze as long as it is to the
  14. front and right of him.
  15.  
  16. Format of file saved is in bytes,
  17. (0-1)MazeWidth (Left to Right) because who wouldnt want a 65536x65536 maze?
  18. (2-3)MazeHeight (Forward to Back)
  19. (4+)width * height / 8, rounded up
  20. store 8 bits per byte for compression
  21. read using
  22. bit.brshift(BYTE, BitID(0-7)) % 2
  23. right to left
  24.  
  25. Thanks, and happy mazing!
  26.  
  27. Do not delete this comment
  28. ]]
  29.  
  30. tArgs = {...}
  31.  
  32. local debugging = true
  33.  
  34. local startX = 1
  35. local startY = 1
  36. local currX = 1
  37. local currY = 1
  38. local rotation = 0
  39.  
  40. local mazewidth = 0
  41. local mazeheight = 0
  42. local mazedata = {}
  43. local preferredfilename = "Maze"
  44.  
  45. if tArgs[1] and tArgs[1] ~= "" then
  46. preferredfilename = tArgs[1]
  47. end
  48.  
  49. local function dPrint(msg) --debug print
  50. if debugging then
  51. io.write(msg)
  52. end
  53. end
  54.  
  55. local function checkFuel() --if fuel level is 0 or 1, wait
  56. if turtle.getFuelLevel() < 2 then
  57. print("Out of fuel, insert coal")
  58. repeat
  59. for i=1, 16 do
  60. if turtle.getItemCount(i) ~= 0 then
  61. turtle.select(i)
  62. if turtle.refuel() then break end
  63. end
  64. end
  65. if turtle.getFuelLevel() < 2 then
  66. os.pullEvent()
  67. end
  68. until turtle.getFuelLevel() >= 2
  69. print("Fueled: "..turtle.getFuelLevel())
  70. end
  71. end
  72.  
  73. local function setRotation(face) --rotate to face(0-3)
  74. if face == nil or tonumber(face) == nil then return nil end
  75. face = face % 4
  76. direction_ = math.abs(face - rotation)
  77. dPrint("Rotate: "..direction_.." "..rotation.." "..face.."\n")
  78. if direction_ == 0 then return end
  79. if rotation == 0 and face == 3 then
  80. repeat
  81. turtle.turnLeft()
  82. rotation = (rotation - 1)%4
  83. until rotation == face
  84. elseif rotation == 3 and face == 0 then
  85. repeat
  86. turtle.turnRight()
  87. rotation = (rotation + 1)%4
  88. until rotation == face
  89. else
  90. if rotation < face then
  91. repeat
  92. turtle.turnRight()
  93. rotation = (rotation + 1)%4
  94. until rotation == face
  95. else
  96. repeat
  97. turtle.turnLeft()
  98. rotation = (rotation - 1)%4
  99. until rotation == face
  100. end
  101. end
  102. end
  103.  
  104. local function forward() --move turtle one block forward, if block is saved as empty. If saved as empty and is not empty, force empty(dig)
  105. checkFuel()
  106. if rotation == 0 then
  107. if mazedata[currX][currY + 1] == 1 then return false end
  108. currY = currY + 1
  109. elseif rotation == 1 then
  110. if mazedata[currX + 1][currY] == 1 then return false end
  111. currX = currX + 1
  112. elseif rotation == 2 then
  113. if mazedata[currX][currY - 1] == 1 then return false end
  114. currY = currY - 1
  115. elseif rotation == 3 then
  116. if mazedata[currX - 1][currY] == 1 then return false end
  117. currX = currX - 1
  118. end
  119. while not turtle.forward() do
  120. turtle.attack()
  121. turtle.dig()
  122. dPrint("Blocked!\n")
  123. os.sleep(2)
  124. end
  125. return true
  126. end
  127.  
  128. local function extendWidth() --extend width for file compression
  129. mazewidth = mazewidth + 1
  130. table.insert(mazedata, {})
  131. end
  132.  
  133. local function extendHeight() --extend height for file compression
  134. mazeheight = mazeheight + 1
  135.  
  136. end
  137.  
  138. local function getAvailable(x, y) --look for unchecked and empty blocks, then check them
  139. availablearray_ = {}
  140. for i=1, 2 do
  141. if ((i-2) + rotation)%4 == 0 then
  142. if (y >= mazeheight) then
  143. extendHeight()
  144. end
  145. if (mazedata[x][y + 1] == nil) then
  146. setRotation(((i-2) + rotation)%4)
  147. mazedata[x][y + 1] = turtle.detect() and 1 or 0
  148. end
  149. if (mazedata[x][y + 1] == 0) then
  150. table.insert(availablearray_, 0)
  151. end
  152. elseif ((i-2) + rotation)%4 == 1 then
  153. if (x >= mazewidth) then
  154. extendWidth()
  155. end
  156. if (mazedata[x + 1][y] == nil) then
  157. setRotation(((i-2) + rotation)%4)
  158. mazedata[x + 1][y] = turtle.detect() and 1 or 0
  159. end
  160. if (mazedata[x + 1][y] == 0) then
  161. table.insert(availablearray_, 1)
  162. end
  163. elseif ((i-2) + rotation)%4 == 2 then
  164. if (y > 1) then
  165. if (mazedata[x][y - 1] == nil) then
  166. setRotation(((i-2) + rotation)%4)
  167. mazedata[x][y - 1] = turtle.detect() and 1 or 0
  168. end
  169. if (mazedata[x][y - 1] == 0) then
  170. table.insert(availablearray_, 2)
  171. end
  172. end
  173. elseif ((i-2) + rotation)%4 == 3 then
  174. if (x > 1) then
  175. if (mazedata[x - 1][y] == nil) then
  176. setRotation(((i-2) + rotation)%4)
  177. mazedata[x - 1][y] = turtle.detect() and 1 or 0
  178. end
  179. if (mazedata[x - 1][y] == 0) then
  180. table.insert(availablearray_, 3)
  181. end
  182. end
  183. end
  184. end
  185. return availablearray_
  186. end
  187.  
  188. local function findUnvisited(x, y) --check for unvisited cells nearby
  189. if (x > 1) then
  190. if (mazedata[x - 1][y] == nil) then
  191. return true
  192. end
  193. end
  194. if (y > 1) then
  195. if (mazedata[x][y - 1] == nil) then
  196. return true
  197. end
  198. end
  199. if (mazedata[x + 1][y] == nil) then
  200. return true
  201. end
  202. if (mazedata[x][y + 1] == nil) then
  203. return true
  204. end
  205. return false
  206. end
  207.  
  208. local function save(preferred) --saving function, compressed file using all bits in each byte
  209. filename = preferred
  210. i=1
  211. if fs.exists(preferred) then
  212. print("File "..preferred.." already exists.")
  213. end
  214. while fs.exists(filename) do
  215. filename = preferred..tostring(i)
  216. i = i + 1
  217. end
  218. if fs.exists(preferred) then
  219. print("Renamed to "..filename)
  220. end
  221. print("Saving maze to: "..filename)
  222. mfile = fs.open(filename, "wb")
  223. mfile.write(mazewidth%256) mfile.write(bit.brshift(mazewidth, 8))
  224. mfile.write(mazeheight%256) mfile.write(bit.brshift(mazeheight, 8))
  225. compindex = 0
  226. compbyte = 0
  227. for x=1, mazewidth do
  228. for y=1, mazeheight do
  229. if mazedata[x][y] == nil or mazedata[x][y] == 1 then
  230. compbyte = compbyte + bit.blshift(1, compindex)
  231. end
  232. compindex = compindex + 1
  233. if compindex >= 8 then
  234. dPrint("CByte: ") dPrint(compbyte) dPrint("\n")
  235. mfile.write(compbyte)
  236. compindex = 0
  237. compbyte = 0
  238. end
  239. end
  240. end
  241. if compindex > 0 then
  242. mfile.write(compbyte)
  243. end
  244. mfile.flush()
  245. mfile.close()
  246. end
  247.  
  248. newcells = true
  249.  
  250. local function render() --render after mapping for debug purposes
  251. print(mazewidth.." "..mazeheight)
  252. os.sleep(2)
  253. term.clear()
  254. for x=1, mazewidth do
  255. for y=1, mazeheight do
  256. term.setCursorPos(x, mazeheight - y + 1)
  257. if mazedata[x][y] == nil then
  258. term.setBackgroundColor(colors.blue)
  259. elseif mazedata[x][y] == 1 then
  260. term.setBackgroundColor(colors.red)
  261. elseif mazedata[x][y] == 0 then
  262. term.setBackgroundColor(colors.green)
  263. end
  264. io.write(".")
  265. end
  266. end
  267. term.setCursorPos(1, mazeheight + 1)
  268. end
  269.  
  270. local function mapMaze() --map current bounding maze, save to next available mazes/maze+i file (i.e mazes/maze7)
  271. mazewidth = 0
  272. mazeheight = 0
  273. for i=1, #mazedata do
  274. table.remove(mazedata, 1)
  275. end
  276. extendWidth()
  277. extendHeight()
  278. repeat
  279. nearby = getAvailable(currX, currY)
  280. if (#nearby ~= 0) then
  281. for i=1, #nearby do
  282. setRotation(nearby[i])
  283. if forward() then break end
  284. end
  285. else
  286. dPrint("Turn Right\n")
  287. setRotation(rotation+1)
  288. end
  289. if currX == startX and currY == startY then
  290. newcells = findUnvisited(currX, currY)
  291. end
  292. until currX == startX and currY == startY and not newcells
  293. setRotation(0)
  294. save(preferredfilename)
  295. end
  296.  
  297. local function cruise()
  298. repeat
  299. nearby = getAvailable(currX, currY)
  300. if (#nearby ~= 0) then
  301. for i=1, #nearby do
  302. setRotation(nearby[i])
  303. if forward() then break end
  304. end
  305. else
  306. dPrint("Turn Right\n")
  307. setRotation(rotation+1)
  308. end
  309. if currX == startX and currY == startY then
  310. newcells = findUnvisited(currX, currY)
  311. end
  312. until currX == startX and currY == startY and not newcells
  313. end
  314.  
  315. for x=1, currX do
  316. extendWidth()
  317. end
  318.  
  319. for y=1, currY do
  320. extendHeight()
  321. end
  322.  
  323. mapMaze()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement