Advertisement
jackmott

ComputerCraft 3D Maze Turtle Program

Oct 2nd, 2015
1,406
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.89 KB | None | 0 0
  1. --TODO - distribute torches more intelligently?
  2. --TODO - more efficient ladder placement? turtle makes many unecessary moves to place them
  3. --TODO - better ladder placement? ladders sometimes switch sides of the maze
  4.  
  5.  
  6. --USAGE
  7. --for large mazes, set up 3 chests in a row, each with one block of space between them:
  8. --Put blocks in chest 1, to the right in chest 2 put torches, and in chest 3 ladders
  9. --put the turtle on top of chest 1
  10. --fuel up your turtle
  11. --fill inventory slot 1 with torches, 2 with ladders, the rest with blocks you want the maze to be built of
  12. --set the maze dimension by editing w/h/d, values must be odd
  13. --run the program - turtle will build forward and to the right, and up!
  14.  
  15. --When the turtle is done you will need to manually poke in any entrance/exit points you want to use.
  16. --Any two spots will work, all points of the maze can reach all other points. Some choices will be harder than others.
  17.  
  18.  
  19. --To pull in API stub for offline development
  20. if require then
  21. require "minecraft"
  22. end
  23.  
  24. --width and height of maze, must be odd
  25. w = 15
  26. h = 9
  27. d = 15
  28.  
  29.  
  30. --To keep track of current position within the maze
  31. --Z is height
  32. curX = 0
  33. curY = 0
  34. curZ = 0 -- maze relative z
  35. worldZ = 0 --world relative z
  36.  
  37.  
  38. --These are maze relative N/S/E/W
  39. --Wherever you turtle is pointing when you start the maze is "north"
  40. --Turtle will start in the 'Southwest' corner of the maze
  41. -- 0=N 1=E 2=S 3=W
  42. curRotation = 0;
  43.  
  44.  
  45.  
  46. math.randomseed(os.time())
  47. --math.randomseed(5)
  48.  
  49.  
  50. --The light field below is only for debugging purposes
  51. --You can remove it for performance reasons
  52. cells = {}
  53. --initialize cells
  54. for i = 0,w-1 do
  55. cells[i] = {}
  56. for j = 0,d-1 do
  57. cells[i][j] = {}
  58. for k = 0,h-1 do
  59. cell = {visited = false,x=i,y=j,z=k,light=false}
  60. cells[i][j][k] = cell
  61. end
  62. end
  63. end
  64.  
  65. --neighbors are two and only two cells away in cardinal directions
  66. --this leaves the perimeter maze walls solid
  67. --we tag each neighbor as vertical or not so we can go vertical less often
  68. --for a more pleasant to navigate maze
  69. function getNeighbors(cell)
  70. neighbors = {}
  71. count = 0
  72. x = cell.x
  73. y = cell.y
  74. z = cell.z
  75. if x+2 < w-1 then
  76. neighbor = {cell = cells[x+2][y][z], vertical = false }
  77. neighbors[count] = neighbor
  78. count = count + 1
  79. end
  80. if x-2 >= 1 then
  81. neighbor = {cell = cells[x-2][y][z], vertical = false }
  82. neighbors[count] = neighbor
  83. count = count + 1
  84. end
  85. if y+2 < d-1 then
  86. neighbor = {cell = cells[x][y+2][z], vertical = false }
  87. neighbors[count] = neighbor
  88. count = count + 1
  89. end
  90. if y-2 >= 1 then
  91. neighbor = {cell = cells[x][y-2][z], vertical = false }
  92. neighbors[count] = neighbor
  93. count = count + 1
  94. end
  95. if z+2 < h-1 then
  96. neighbor = {cell = cells[x][y][z+2], vertical = true }
  97. neighbors[count] = neighbor
  98. count = count+1
  99. end
  100. if z-2 >= 1 then
  101. neighbor = {cell = cells[x][y][z-2], vertical = true}
  102. neighbors[count] = neighbor
  103. count = count+1
  104. end
  105.  
  106. return neighbors
  107. end
  108.  
  109. --get a random neighbor cell that is unvisited
  110. function getRandomUnvisitedNeighbor(cell)
  111. neighbors = getNeighbors(cell)
  112. unvisitedNeighbors = {}
  113. count = 0
  114.  
  115. for k,v in pairs(neighbors) do
  116. if v.cell.visited == false then
  117. unvisitedNeighbors[count] = v
  118. count = count + 1
  119. end
  120. end
  121.  
  122. --This holds off on vertical path choices until the last minute
  123. --So there are less up and down movements which are tiresome
  124. --for the player to navigate
  125. --you can just toss this if you prefer not to do this
  126. if count > 2 then
  127. for i = count-1,0,-1 do
  128. neighbor = unvisitedNeighbors[i]
  129. if neighbor.vertical == true then
  130. table.remove(unvisitedNeighbors,i)
  131. count = count - 1
  132. end
  133. end
  134. end
  135.  
  136.  
  137. if count == 0 then
  138. return nil
  139. end
  140.  
  141. --get a random neihgbor
  142. r = math.random(count)-1;
  143. return unvisitedNeighbors[r].cell
  144.  
  145. end
  146.  
  147. --given two neighboring cells, get the cell between them
  148. function cellBetween(cell1,cell2)
  149. if cell1.x > cell2.x then
  150. return cells[cell1.x-1][cell1.y][cell1.z]
  151. end
  152.  
  153. if cell1.x < cell2.x then
  154. return cells[cell1.x+1][cell1.y][cell1.z]
  155. end
  156.  
  157. if cell1.y > cell2.y then
  158. return cells[cell1.x][cell1.y-1][cell1.z]
  159. end
  160.  
  161. if cell1.y < cell2.y then
  162. return cells[cell1.x][cell1.y+1][cell1.z]
  163. end
  164.  
  165. if cell1.z > cell2.z then
  166. return cells[cell1.x][cell1.y][cell1.z-1]
  167. end
  168.  
  169. if cell1.z < cell2.z then
  170. return cells[cell1.x][cell1.y][cell1.z+1]
  171. end
  172.  
  173. end
  174.  
  175. --the main recursive function to traverse the maze
  176. function recur(curCell)
  177.  
  178. --mark current cell as visited
  179. curCell.visited = true
  180.  
  181. --check each neighbor cell
  182. for i = 1,6 do
  183. nCell = getRandomUnvisitedNeighbor(curCell)
  184. if nCell ~= nil then
  185. -- clear the cell between the neighbors
  186. bCell = cellBetween(curCell,nCell)
  187. bCell.visited = true
  188. --push current cell onto the stack and move on the neighbor cell
  189. recur(nCell)
  190. end
  191. end
  192.  
  193. end
  194.  
  195.  
  196. --start point needs to be inside the perimeter
  197. --and odd
  198. recur(cells[1][1][1])
  199.  
  200. --Now we are done with the maze algorithm, and have a maze complete
  201. --in memory in the cells table
  202. --We must being building it with our turtle
  203.  
  204. lightSlot = 1 --inventory slot for lights
  205. ladderSlot = 2 --inventory slot for ladders
  206. lightCount = 0 --how many blocks since we last placed a light?
  207. lightThreshold = 4 --how often to place lights
  208.  
  209.  
  210. --For debugging
  211. function printWorldLocation()
  212. print("World: (" .. curX .. "," .. curY .. "," .. worldZ .. ")")
  213. end
  214.  
  215. function printMazeLocation()
  216. print("Maze: (" .. curX .. "," .. curY .. "," .. curZ ..")")
  217. end
  218.  
  219.  
  220.  
  221. --find a slot with building material in it
  222. function selectBlock()
  223. for i = 3, 16 do
  224. if turtle.getItemCount(i) > 0 then
  225. turtle.select(i)
  226. return true
  227. end
  228. end
  229. return false
  230. end
  231.  
  232. --Place a block, first checking inventory
  233. function blockDown()
  234. checkInventory()
  235. turtle.select(3)
  236. if turtle.getItemCount() == 0 then
  237. selectBlock()
  238. end
  239. turtle.placeDown()
  240. end
  241.  
  242. --light can be anything that will place down on the floors
  243. function placeLight()
  244. if lightCount > lightThreshold then
  245. if curZ +1 < h then
  246. --we have to much sure this current block has no vertical passage
  247. --above or below it as torch will interfere with ladder
  248. if cells[curX][curY][curZ+1].visited == false then
  249. if cells[curX][curY][curZ-1].visited == false then
  250. turtle.select(lightSlot)
  251. turtle.placeDown()
  252.  
  253. --below is for debugging only
  254. cells[curX][curY][curZ].light = true
  255.  
  256. lightCount = 0
  257. end
  258. end
  259. end
  260. else
  261. lightCount = lightCount + 1
  262. end
  263. end
  264.  
  265. --We always use these to turn to keep track of rotation
  266. function turnRight()
  267. turtle.turnRight()
  268. curRotation = (curRotation +1) % 4
  269. end
  270.  
  271. function turnLeft()
  272. turtle.turnLeft()
  273. curRotation = (curRotation-1) % 4
  274. end
  275.  
  276. --Will orient to the direction specified
  277. function orient(direction)
  278. while curRotation ~= direction do
  279. turnRight()
  280. end
  281. end
  282.  
  283. --We use this to go forward to keep track of our x/y position
  284. function forward()
  285. turtle.forward()
  286. if curRotation == 0 then
  287. curY = curY + 1
  288. elseif curRotation == 2 then
  289. curY = curY - 1
  290. elseif curRotation == 1 then
  291. curX = curX + 1
  292. elseif curRotation == 3 then
  293. curX = curX - 1
  294. end
  295. end
  296.  
  297.  
  298. --And we use these to go up and down to keep track of our Z position
  299. function up()
  300. worldZ = worldZ + 1
  301. turtle.up()
  302. end
  303.  
  304. function down()
  305. worldZ = worldZ - 1
  306. turtle.down()
  307. end
  308.  
  309.  
  310. function turnAroundOut()
  311. --if pointing "north" turn right
  312. if curRotation == 0 then
  313. turnRight()
  314. forward()
  315. turnRight()
  316. else
  317. turnLeft()
  318. forward()
  319. turnLeft()
  320. end
  321. end
  322.  
  323. --when going back the other way
  324. function turnAroundIn()
  325. if curRotation == 2 then
  326. turnRight()
  327. forward()
  328. turnRight()
  329. else
  330. turnLeft()
  331. forward()
  332. turnLeft()
  333. end
  334. end
  335.  
  336. --Descends into vertical passages
  337. --places ladders as it comes back up
  338. function placeLadder()
  339. checkInventory()
  340. turtle.select(ladderSlot)
  341. down()
  342. down()
  343. turtle.placeDown()
  344. up()
  345. turtle.placeDown()
  346. up()
  347. turtle.placeDown()
  348. end
  349.  
  350.  
  351. function placeFloorLayerOut()
  352. print("FloorLayerOut")
  353.  
  354. if curZ ~= 0 then
  355. up()
  356. turnRight()
  357. turnRight()
  358. end
  359. for x = 0, w-1 do
  360. for y = 0, d-1 do
  361. if cells[curX][curY][curZ].visited == false then
  362. blockDown()
  363. end
  364. if y < d-1 then
  365. forward()
  366. end
  367.  
  368. end
  369. if x < w-1 then
  370. turnAroundOut()
  371. end
  372. end
  373.  
  374. end
  375.  
  376. function placeFloorLayerIn()
  377. print("FloorLayerIn");
  378. up()
  379. if curZ ~= 0 then
  380. turnRight()
  381. turnRight()
  382. end
  383. for x = w-1, 0,-1 do
  384. for y = d-1,0,-1 do
  385. if cells[curX][curY][curZ].visited == false then
  386. blockDown()
  387. end
  388. if y > 0 then
  389. forward()
  390. end
  391.  
  392. end
  393. if x > 0 then
  394. turnAroundIn()
  395. end
  396. end
  397. end
  398.  
  399.  
  400. function placeWallLayer1In()
  401. print("wallLayer1In")
  402. up()
  403. turnRight()
  404. turnRight()
  405. for x = w-1,0,-1 do
  406. for y = d-1,0,-1 do
  407. if cells[curX][curY][curZ].visited then
  408. placeLight()
  409. else
  410. blockDown()
  411. end
  412. if y > 0 then
  413. forward()
  414. end
  415. end
  416. if x > 0 then
  417. turnAroundIn()
  418. end
  419. end
  420. end
  421.  
  422.  
  423.  
  424. function placeWallLayer2Out()
  425. print("wallLayer2Out")
  426. up()
  427. turnRight()
  428. turnRight()
  429. for x = 0,w-1 do
  430. for y = 0,d-1 do
  431. if cells[curX][curY][curZ].visited == false then
  432. blockDown()
  433. end
  434. if y < d-1 then
  435. forward()
  436. end
  437. end
  438. if x < w-1 then
  439. turnAroundOut()
  440. end
  441. end
  442. end
  443.  
  444. --This could be made more efficient
  445. --Turtle could go directly to each vertical passage
  446. function placeLaddersOut()
  447. print("placeLaddersOut")
  448. if curZ == 0 then
  449. return
  450. end
  451. turnRight()
  452. turnRight()
  453. for x = 0,w-1 do
  454. for y = 0,d-1 do
  455. if cells[curX][curY][curZ].visited then
  456. placeLadder()
  457. end
  458. if y < d-1 then
  459. forward()
  460. end
  461. end
  462. if x < w-1 then
  463. turnAroundOut()
  464. end
  465. end
  466. end
  467.  
  468.  
  469. --checks if we are running low on blocks, torches, or ladders
  470. function checkInventory()
  471.  
  472. --check building blocks
  473. totalBlocks = 0
  474. for i=3,16 do
  475. totalBlocks = totalBlocks + turtle.getItemCount(i)
  476. end
  477.  
  478. --check torches
  479. torchCount = turtle.getItemCount(1)
  480.  
  481. --check ladders
  482. ladderCount = turtle.getItemCount(2)
  483.  
  484. if totalBlocks < 5 or torchCount < 5 or ladderCount < 5 then
  485. returnToOrigin()
  486. getMoreBlocks()
  487. resumeBuild()
  488. end
  489.  
  490. end
  491.  
  492. --resume coordinates
  493. resX = 0
  494. resY = 0
  495. resZ = 0
  496. resRotation = 0
  497.  
  498. --returns to starting chest
  499. function returnToOrigin()
  500. resX = curX
  501. resY = curY
  502. resZ = worldZ
  503. resRotation = curRotation
  504.  
  505. --point south then go past the edge of the maze
  506. orient(2)
  507. for i = 0,resY do
  508. forward()
  509. end
  510.  
  511. --point west then go to point above chest
  512. orient(3)
  513. for i = 0, resX-1 do
  514. forward()
  515. end
  516.  
  517. --drop down to above the chest
  518. for i = 0, resZ-1 do
  519. down()
  520. end
  521.  
  522.  
  523. end
  524.  
  525. --fill up on all 3 resources
  526. function getMoreBlocks()
  527.  
  528. --get building blocks from 1st chest
  529. while turtle.suckDown(64) do
  530. end
  531.  
  532. --get torches from 2nd chest which is assumed to be 2 blocks east
  533. --point east
  534. orient(1)
  535. forward()
  536. forward()
  537. turtle.select(1)
  538. turtle.suckDown(64-turtle.getItemCount()) --just enough to fill upt he stack
  539.  
  540. --get ladders from 3rd chest assumed to be 2 more blocks east
  541. forward()
  542. forward()
  543. turtle.select(2)
  544. turtle.suckDown(64-turtle.getItemCount()) --just enough
  545.  
  546. --point west and go back to above the start chest
  547. orient(3)
  548. forward()
  549. forward()
  550. forward()
  551. forward()
  552.  
  553. end
  554.  
  555. --return to the position we left off
  556. function resumeBuild()
  557.  
  558. --back up
  559. for i = 0, resZ -1 do
  560. up()
  561. end
  562.  
  563. --point east
  564. orient(1)
  565. for i = 0, resX-1 do
  566. forward()
  567. end
  568.  
  569. orient(0)
  570. for i = 0, resY do
  571. forward()
  572. end
  573. --resume original rotation
  574. orient(resRotation)
  575. end
  576.  
  577.  
  578. --prints ton of text representing maze state
  579. function fullDebug()
  580. for z = 0,h-1 do
  581. for y = 0,d-1 do
  582. for x = 0,w-1 do
  583.  
  584. if cells[x][y][z].light == true and cells[x][y][z].visited == false then
  585. io.write("("..x..","..y..","..z.."):FF") --if you see this something went wrong
  586. elseif cells[x][y][z].light then
  587. io.write("("..x..","..y..","..z.."):**")
  588. elseif cells[x][y][z].visited == false then
  589. io.write("("..x..","..y..","..z.."):XX")
  590. else
  591. io.write("("..x..","..y..","..z.."): ")
  592. end
  593.  
  594. end
  595. io.write("\n")
  596. end
  597. io.write("\n")
  598. end
  599. end
  600.  
  601. --quick text representation of each layer of the maze
  602. function debug()
  603. for z = 0,h-1 do
  604. for y = 0,d-1 do
  605. for x = 0,w-1 do
  606.  
  607. if (cells[x][y][z].light == true) and (cells[x][y][z].visited == false) then
  608. io.write("FF") --if you see this something went wrong
  609. elseif cells[x][y][z].light == true then
  610. io.write("**")
  611. elseif cells[x][y][z].visited == false then
  612. io.write("XX")
  613. else
  614. io.write(" ")
  615. end
  616.  
  617. end
  618. io.write("\n")
  619. end
  620. io.write("\n")
  621. end
  622. end
  623.  
  624.  
  625.  
  626. hush = true --silences stub api prints, has no effect in game
  627.  
  628. turtle.forward() --move off the chest to starting position of maze
  629. placeFloorLayerOut()
  630. curZ = curZ + 1
  631. placeWallLayer1In()
  632. placeWallLayer2Out()
  633. while true do
  634. print("loopstart")
  635.  
  636. curZ = curZ + 1
  637. placeFloorLayerIn()
  638.  
  639. if curZ == h-1 then
  640. break
  641. end
  642.  
  643. placeLaddersOut()
  644. curZ = curZ + 1
  645.  
  646. placeWallLayer1In()
  647. placeWallLayer2Out()
  648. end
  649.  
  650. returnToOrigin()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement