edig.lua

737 lines · 18.8 KB

Open raw

Advanced tunnel digger with dome shapes and multi-turtle coordination

Usage: edig [command] [args...]

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/eDig/edig.lua
1-- edig.lua - Advanced tunnel digger with dome shapes and multi-turtle coordination
2-- Usage: edig [command] [args...]
3-- Commands: dig, multi, install, client, help
4
5local args = {...}
6
7-- Check if we're on a turtle
8local function hasTurtle()
9 return pcall(function() return turtle.getFuelLevel() end)
10end
11
12-- Movement helpers
13local function df() while turtle.detect() do turtle.dig() end end
14local function du() while turtle.detectUp() do turtle.digUp() end end
15local function dd() while turtle.detectDown() do turtle.digDown() end end
16local function gf()
17 while not turtle.forward() do
18 if turtle.detect() then turtle.dig() end
19 turtle.attack()
20 end
21end
22local function gu()
23 while not turtle.up() do
24 if turtle.detectUp() then turtle.digUp() end
25 turtle.attackUp()
26 end
27end
28local function gd()
29 while not turtle.down() do
30 if turtle.detectDown() then turtle.digDown() end
31 turtle.attackDown()
32 end
33end
34
35-- Resource scanning
36local function scanInventory()
37 local fuel = 0
38 local blocks = 0
39 local fuelSlots = {}
40 local blockSlots = {}
41
42 for i = 1, 16 do
43 local count = turtle.getItemCount(i)
44 if count > 0 then
45 turtle.select(i)
46 local isFuel = turtle.refuel(0)
47 if isFuel then
48 fuel = fuel + count
49 table.insert(fuelSlots, i)
50 else
51 blocks = blocks + count
52 table.insert(blockSlots, i)
53 end
54 end
55 end
56
57 return {
58 fuel = fuel,
59 blocks = blocks,
60 fuelSlots = fuelSlots,
61 blockSlots = blockSlots
62 }
63end
64
65-- Fuel management
66local function refuel(target)
67 if turtle.getFuelLevel() == "unlimited" then return true end
68
69 local current = turtle.getSelectedSlot()
70 for i = 1, 16 do
71 if turtle.getItemCount(i) > 0 then
72 turtle.select(i)
73 while turtle.getItemCount(i) > 0 and turtle.getFuelLevel() < target do
74 if not turtle.refuel(1) then break end
75 end
76 if turtle.getFuelLevel() >= target then break end
77 end
78 end
79 turtle.select(current)
80
81 if turtle.getFuelLevel() < target then
82 print("Need fuel! Current: " .. turtle.getFuelLevel())
83 print("Add coal/charcoal to any slot")
84 while turtle.getFuelLevel() < target do
85 sleep(1)
86 for i = 1, 16 do
87 if turtle.getItemCount(i) > 0 then
88 turtle.select(i)
89 if turtle.refuel(1) then break end
90 end
91 end
92 end
93 end
94 return true
95end
96
97-- Find block slot for placement
98local function findBlockSlot()
99 for i = 1, 16 do
100 local count = turtle.getItemCount(i)
101 if count > 0 then
102 turtle.select(i)
103 local isFuel = turtle.refuel(0)
104 if not isFuel then return i end
105 end
106 end
107 return nil
108end
109
110-- Place floor
111local function placeFloor()
112 if not turtle.detectDown() then
113 local slot = findBlockSlot()
114 if slot then
115 turtle.select(slot)
116 local success = turtle.placeDown()
117 if not success then
118 print("Warning: Could not place floor block (no blocks available)")
119 return false
120 end
121 return true
122 else
123 print("Warning: No blocks available for floor placement")
124 return false
125 end
126 end
127 return true
128end
129
130-- Dome tunnel shapes
131local DOME_SHAPES = {
132 ["size2"] = {
133 width = 7,
134 heights = {3,3,4,4,4,3,3},
135 maxTurtles = 7
136 },
137 ["custom"] = {
138 width = 5,
139 heights = {3,4,4,4,3},
140 maxTurtles = 5
141 }
142}
143
144-- Calculate dome shape heights
145local function getDomeHeights(shape, width, sideHeight, centerHeight, radius)
146 if shape == "size2" then
147 return DOME_SHAPES.size2.heights
148 elseif shape == "custom" then
149 local heights = {}
150 for x = 0, width - 1 do
151 if radius <= 0 then
152 if x == 0 or x == width - 1 then
153 heights[x+1] = sideHeight
154 else
155 heights[x+1] = centerHeight
156 end
157 else
158 local u = 1 - (math.abs(2*x - (width - 1)) / (width - 1))
159 local exponent = 1 / (1 + radius)
160 local u2 = u ^ exponent
161 local f = (1 - math.cos(math.pi * u2)) / 2
162 local h = math.floor(0.5 + (sideHeight + (centerHeight - sideHeight) * f))
163 if h < sideHeight then h = sideHeight end
164 if h > centerHeight then h = centerHeight end
165 heights[x+1] = h
166 end
167 end
168 return heights
169 end
170 return {3,3,3} -- default
171end
172
173-- Check if we have blocks for floor placement
174local function checkBlocksForFloor(shouldPlaceFloor)
175 if shouldPlaceFloor then
176 local slot = findBlockSlot()
177 if not slot then
178 print("No blocks available for floor placement!")
179 print("Options:")
180 print("1. Add blocks to inventory and press Enter")
181 print("2. Type 'skip' to continue without floor placement")
182 print("3. Type 'stop' to abort")
183
184 while true do
185 write("Choice: ")
186 local choice = string.lower(read())
187 if choice == "skip" then
188 return false
189 elseif choice == "stop" then
190 error("Operation aborted by user")
191 elseif choice == "" then
192 slot = findBlockSlot()
193 if slot then
194 print("Blocks found! Continuing...")
195 return true
196 else
197 print("Still no blocks. Please add blocks or type 'skip' or 'stop'")
198 end
199 end
200 end
201 end
202 end
203 return shouldPlaceFloor
204end
205
206-- Straight tunnel digging
207local function digStraightTunnel(height, width, length, shouldPlaceFloor)
208 local slice = 0
209
210 print("Starting straight tunnel dig...")
211 print("Dimensions: " .. length .. "x" .. width .. "x" .. height)
212
213 while slice < length do
214 slice = slice + 1
215
216 -- Refuel check every 8 slices
217 if slice % 8 == 0 then
218 refuel(turtle.getFuelLevel() + 16)
219 end
220
221 -- Dig tunnel slice
222 digTunnelSlice(height, width, shouldPlaceFloor)
223
224 -- Move forward for next slice
225 gf()
226
227 if slice >= 1000 then
228 print("Safety stop at 1000 slices")
229 break
230 end
231 end
232
233 print("Done! Dug " .. slice .. " slices")
234end
235
236-- Dig dome slice
237local function digDomeSlice(heights, width, shouldPlaceFloor)
238 shouldPlaceFloor = checkBlocksForFloor(shouldPlaceFloor)
239
240 -- Enter slice
241 df()
242 gf()
243
244 -- Move to level 2 for dome shape
245 if heights[1] >= 2 then
246 gu()
247 end
248
249 -- Dig left to right
250 for x = 1, width do
251 local h = heights[x] or 0
252
253 -- Adjust height
254 if h >= 1 then turtle.digDown() end
255 if h >= 3 then du() end
256
257 -- Move right if not last column
258 if x < width then
259 turtle.turnLeft()
260 df()
261 gf()
262 turtle.turnRight()
263 end
264 end
265
266 -- Upper pass for height 4 columns
267 local needUpper = false
268 for i = 1, #heights do
269 if heights[i] >= 4 then needUpper = true break end
270 end
271
272 if needUpper then
273 gu() -- Move to level 3
274 for x = 1, width do
275 if (heights[x] or 0) >= 4 then du() end
276 if x < width then
277 turtle.turnLeft()
278 gf()
279 turtle.turnRight()
280 end
281 end
282 gd() -- Return to level 2
283 end
284
285 -- Return to base level
286 gd()
287
288 -- Return to starting position
289 for w = 1, width - 1 do
290 turtle.turnLeft()
291 gf()
292 turtle.turnRight()
293 end
294end
295
296-- Dome tunnel digging
297local function digDomeTunnel(shape, length, shouldPlaceFloor)
298 local heights = getDomeHeights(shape, DOME_SHAPES[shape].width, 3, 4, 0)
299 local width = DOME_SHAPES[shape].width
300 local slice = 0
301
302 print("Starting dome tunnel dig...")
303 print("Shape: " .. shape .. " (" .. width .. " wide)")
304 print("Length: " .. length)
305
306 while slice < length do
307 slice = slice + 1
308
309 -- Refuel check every 8 slices
310 if slice % 8 == 0 then
311 refuel(turtle.getFuelLevel() + 16)
312 end
313
314 -- Dig dome slice
315 digDomeSlice(heights, width, shouldPlaceFloor)
316
317 -- Move forward for next slice
318 gf()
319
320 if slice >= 1000 then
321 print("Safety stop at 1000 slices")
322 break
323 end
324 end
325
326 print("Done! Dug " .. slice .. " dome slices")
327end
328
329-- Dig tunnel slice (straight)
330local function digTunnelSlice(height, width, shouldPlaceFloor)
331 shouldPlaceFloor = checkBlocksForFloor(shouldPlaceFloor)
332
333 -- Dig the slice in front of turtle
334 for h = 1, height - 1 do
335 du()
336 if h < height - 1 then gu() end
337 end
338
339 -- Dig forward
340 df()
341 gf()
342 if shouldPlaceFloor then placeFloor() end
343
344 -- Return to base level
345 for h = 1, height - 1 do gd() end
346
347 -- Dig the width (side to side)
348 for w = 1, width - 1 do
349 turtle.turnLeft()
350 df()
351 gf()
352 if shouldPlaceFloor then placeFloor() end
353
354 -- Dig up for height
355 for h = 1, height - 1 do
356 du()
357 if h < height - 1 then gu() end
358 end
359
360 -- Return to base
361 for h = 1, height - 1 do gd() end
362
363 turtle.turnRight()
364 end
365
366 -- Return to starting position
367 for w = 1, width - 1 do
368 turtle.turnLeft()
369 gf()
370 turtle.turnRight()
371 end
372end
373
374
375-- Dig command
376local function digCommand()
377 if not hasTurtle() then
378 print("Turtle required for digging!")
379 return
380 end
381
382 local height = 3
383 local length = 32
384 local width = 3
385 local autoPlace = false
386 local segment = nil
387 local shape = "straight"
388
389 -- Parse arguments
390 if #args >= 2 then
391 height = math.max(1, tonumber(args[2]) or 3)
392 for i = 3, #args do
393 local arg = string.lower(args[i])
394 local num = tonumber(args[i])
395 if num then
396 if i == 3 then
397 length = math.max(1, num)
398 elseif i == 4 then
399 width = math.max(1, num)
400 elseif i == 5 then
401 segment = num
402 end
403 elseif arg == "place" then
404 autoPlace = true
405 elseif arg == "dome" or arg == "size2" then
406 shape = "size2"
407 elseif arg == "custom" then
408 shape = "custom"
409 end
410 end
411 else
412 -- Interactive prompts
413 term.clear()
414 term.setCursorPos(1, 1)
415 print("eDig - Advanced Tunnel Digger")
416
417 local resources = scanInventory()
418 print("Resources: " .. resources.fuel .. " fuel, " .. resources.blocks .. " blocks")
419
420 write("Tunnel type (straight/dome/size2) [straight]: ")
421 local t = string.lower(read())
422 if t == "dome" or t == "size2" then
423 shape = "size2"
424 elseif t == "custom" then
425 shape = "custom"
426 end
427
428 if shape == "straight" then
429 write("Tunnel height (blocks) [3]: ")
430 local h = read()
431 if h ~= "" then height = math.max(1, tonumber(h) or 3) end
432
433 write("Tunnel length (blocks) [32]: ")
434 local l = read()
435 if l ~= "" then length = math.max(1, tonumber(l) or 32) end
436
437 write("Tunnel width (blocks) [3]: ")
438 local w = read()
439 if w ~= "" then width = math.max(1, tonumber(w) or 3) end
440 else
441 write("Tunnel length (blocks) [32]: ")
442 local l = read()
443 if l ~= "" then length = math.max(1, tonumber(l) or 32) end
444 end
445
446 write("Place floor blocks? (y/n) [n]: ")
447 local place = string.lower(read())
448 autoPlace = (place == "y" or place == "yes")
449
450 write("Segment number (for multi-turtle) [none]: ")
451 local seg = read()
452 if seg ~= "" then segment = tonumber(seg) end
453 end
454
455 -- Resource check and planning
456 local resources = scanInventory()
457 print("Digging " .. shape .. " tunnel")
458
459 if shape == "straight" then
460 print("Dimensions: " .. length .. "x" .. width .. "x" .. height)
461 else
462 print("Shape: " .. shape .. " (" .. DOME_SHAPES[shape].width .. " wide)")
463 print("Length: " .. length)
464 end
465
466 if segment then
467 print("Segment: " .. segment)
468 end
469
470 print("Resources: " .. resources.fuel .. " fuel, " .. resources.blocks .. " blocks")
471
472 -- Initial fuel check
473 local fuelNeeded = length * (width + height) * 2
474 if resources.fuel * 80 < fuelNeeded then
475 print("Warning: May need more fuel")
476 end
477 refuel(math.min(fuelNeeded, turtle.getFuelLevel() + 100))
478
479 print("Starting tunnel dig...")
480 if segment then
481 print("Segment " .. segment .. " starting...")
482 end
483
484 -- Dig based on shape
485 if shape == "straight" then
486 digStraightTunnel(height, width, length, autoPlace)
487 else
488 digDomeTunnel(shape, length, autoPlace)
489 end
490
491 if segment then
492 print("Segment " .. segment .. " complete")
493 end
494end
495
496-- Multi-turtle command
497local function multiCommand()
498 local function findModem()
499 for _, side in pairs(rs.getSides()) do
500 if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then
501 return side
502 end
503 end
504 error("No modem found!")
505 end
506
507 rednet.open(findModem())
508
509 print("Multi-Turtle eDig")
510 write("Tunnel type (straight/dome/size2) [straight]: ")
511 local shape = string.lower(read())
512 if shape ~= "dome" and shape ~= "size2" then
513 shape = "straight"
514 end
515
516 local height, width, length
517 if shape == "straight" then
518 write("Tunnel height (blocks) [3]: ")
519 height = tonumber(read()) or 3
520
521 write("Tunnel width (blocks) [3]: ")
522 width = tonumber(read()) or 3
523 else
524 height = DOME_SHAPES[shape].heights[1]
525 width = DOME_SHAPES[shape].width
526 print("Dome shape: " .. shape .. " (" .. width .. " wide, max " .. DOME_SHAPES[shape].maxTurtles .. " turtles)")
527 end
528
529 write("Tunnel length (blocks) [32]: ")
530 length = tonumber(read()) or 32
531
532 write("Place floor blocks? (y/n) [n]: ")
533 local place = string.lower(read()) == "y" and "place" or ""
534
535 write("Turtle IDs (space-separated): ")
536 local idStr = read()
537 local ids = {}
538 for id in idStr:gmatch("%S+") do
539 local num = tonumber(id)
540 if num then table.insert(ids, num) end
541 end
542
543 if #ids == 0 then
544 print("No valid turtle IDs")
545 return
546 end
547
548 -- Limit turtles based on shape
549 local maxTurtles = shape == "straight" and width or DOME_SHAPES[shape].maxTurtles
550 if #ids > maxTurtles then
551 print("Warning: " .. shape .. " shape supports max " .. maxTurtles .. " turtles")
552 print("Using first " .. maxTurtles .. " turtles")
553 while #ids > maxTurtles do
554 table.remove(ids)
555 end
556 end
557
558 write("Segment mode? (y/n) [n]: ")
559 local segmentMode = string.lower(read()) == "y"
560
561 local segmentLength = 0
562 if segmentMode then
563 write("Segment length (blocks per turtle) [8]: ")
564 segmentLength = tonumber(read()) or 8
565 end
566
567 -- Build command
568 local cmd = tostring(height) .. " " .. tostring(length) .. " " .. tostring(width)
569 if place ~= "" then cmd = cmd .. " " .. place end
570 if shape ~= "straight" then cmd = cmd .. " " .. shape end
571
572 -- Send to turtles with coordination
573 print("Sending coordinated jobs to " .. #ids .. " turtles...")
574 print("All turtles will start simultaneously")
575
576 if segmentMode then
577 local totalLength = length
578 local segments = math.ceil(totalLength / segmentLength)
579
580 for i = 1, #ids do
581 local turtleId = ids[i]
582 local segmentStart = (i - 1) * segmentLength
583 local segmentEnd = math.min(segmentStart + segmentLength, totalLength)
584 local segmentLengthActual = segmentEnd - segmentStart
585
586 if segmentLengthActual > 0 then
587 local segmentCmd = cmd .. " " .. tostring(i)
588 print("Turtle " .. turtleId .. " (Segment " .. i .. "): " .. segmentLengthActual .. " blocks")
589 rednet.send(turtleId, {command = "RUN", args = segmentCmd})
590 end
591 end
592 else
593 -- Simultaneous row-based coordination
594 for i = 1, #ids do
595 local turtleId = ids[i]
596 local rowCmd = cmd .. " " .. tostring(i) .. " " .. tostring(width)
597 print("Turtle " .. turtleId .. " (Row " .. i .. "): " .. width .. " blocks wide")
598 rednet.send(turtleId, {command = "RUN", args = rowCmd})
599 end
600 end
601
602 print("Jobs sent! All turtles starting simultaneously...")
603end
604
605-- Client command
606local function clientCommand()
607 local function findModem()
608 for _, side in pairs(rs.getSides()) do
609 if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then
610 return side
611 end
612 end
613 error("No modem found!")
614 end
615
616 rednet.open(findModem())
617 local id = os.getComputerID()
618
619 print("eDig client ready (ID: " .. id .. ")")
620 print("Waiting for jobs...")
621
622 while true do
623 local sender, msg, protocol = rednet.receive()
624
625 local cmd = ""
626 if type(msg) == "table" and msg.command == "RUN" then
627 cmd = msg.args or ""
628 elseif type(msg) == "string" then
629 cmd = msg
630 end
631
632 if cmd ~= "" then
633 print("Running: edig dig " .. cmd)
634 local ok, err = pcall(function()
635 shell.run("edig dig " .. cmd)
636 end)
637
638 if ok then
639 rednet.send(sender, {status = "done", id = id})
640 print("Job completed")
641 else
642 rednet.send(sender, {status = "error", id = id, error = err})
643 print("Job failed: " .. tostring(err))
644 end
645 end
646 end
647end
648
649-- Install command
650local function installCommand()
651 print("Installing eDig system...")
652
653 local files = {
654 "https://raw.githubusercontent.com/perlytiara/CC-Tweaked-TurtsAndComputers/refs/heads/main/programs/perlytiara/eDig/edig.lua"
655 }
656
657 local function downloadFile(url, filename)
658 print("Downloading " .. filename .. "...")
659 local result = shell.run("wget", url, filename)
660 if result then
661 print("✓ " .. filename)
662 return true
663 else
664 print("✗ Failed to download " .. filename)
665 return false
666 end
667 end
668
669 local success = 0
670
671 if downloadFile(files[1], "edig") then
672 success = success + 1
673 end
674
675 print("Installed " .. success .. " files")
676
677 if turtle then
678 print("Turtle setup complete!")
679 print("Run 'edig client' to start listening for jobs")
680 print("Or run 'edig dig <height> <length> <width> [place] [segment]' directly")
681 else
682 print("Computer setup complete!")
683 print("Run 'edig multi' to send jobs to turtles")
684 end
685end
686
687-- Help command
688local function helpCommand()
689 print("eDig Advanced Tunnel System")
690 print("Usage: edig [command] [args...]")
691 print()
692 print("Commands:")
693 print(" dig [height] [length] [width] [place] [segment] [shape]")
694 print(" - Dig tunnels (straight or dome shapes)")
695 print(" - Shapes: straight, dome, size2")
696 print(" - Interactive mode if no args provided")
697 print()
698 print(" multi")
699 print(" - Send coordinated jobs to multiple turtles")
700 print(" - Supports simultaneous row-based coordination")
701 print(" - Dome shapes: max 7 turtles (size2), max 5 turtles (custom)")
702 print()
703 print(" client")
704 print(" - Start remote listener for jobs")
705 print(" - Use on turtle clients")
706 print()
707 print(" install")
708 print(" - Download and install the system")
709 print()
710 print(" help")
711 print(" - Show this help message")
712 print()
713 print("Examples:")
714 print(" edig dig 3 32 3 -- 3x3x32 straight tunnel")
715 print(" edig dig 4 50 5 place -- 4x5x50 tunnel with floors")
716 print(" edig dig 0 100 0 dome -- 7-wide dome tunnel (size2)")
717 print(" edig multi -- Multi-turtle coordinator")
718 print(" edig client -- Start turtle client")
719end
720
721-- Main command router
722local command = args[1] or "help"
723
724if command == "dig" then
725 digCommand()
726elseif command == "multi" then
727 multiCommand()
728elseif command == "client" then
729 clientCommand()
730elseif command == "install" then
731 installCommand()
732elseif command == "help" then
733 helpCommand()
734else
735 print("Unknown command: " .. command)
736 print("Use 'edig help' for available commands")
737end