View difference between Paste ID: Z1kzT3Cj and EQkKrChQ
SHOW: | | - or go back to the newest paste.
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()