View difference between Paste ID: ySzmSLqN and BhXBYR0V
SHOW: | | - or go back to the newest paste.
1
-- Author: KROM
2
-- 
3
-- NOTE: This is still buggy, turtle might run off :|
4
--
5
-- v0.1 - first code
6
-- v0.2 - added cave mode, x|y can be set independently
7
-- v0.2a - disabled rednet
8
--
9
-- known bugs:
10
-- * moves one step to far on y, when resuming after abort on 1st floor.
11
-- * x/y dimensions need to be uneven
12
-- * calc. of energy requirement somewhat strange/not exact
13
-- * reserved slots not implemented
14
-- --------------------------------
15
local sBotLabel = "MiningBot 01"
16
-- those are reserved at end of inventory
17
local nReservedSlots = 2 
18
-- where's the fuel?
19
local nBatterySlot = 1
20
-- set this to ID of master computer
21
-- get id by: lua(); os.getComputerID(); exit();
22
local nMasterComputerID = 31
23
-- when should me unloadz?
24
local nEmptySlotsMargin = 1
25
26
-- internal vars
27
local nRuns    = 0
28
local nEnergy  = 0
29
local nEnergySafetyMargin = 30
30
local bNoError = true
31
local bRedNet = false
32
local nRadius   = 0 -- should be obsolete
33
local nMaxDepth = 0
34
local bResume   = false
35
local startX,startY,startZ = 0,0,0
36
local currentX,currentY,currentZ = 0,0,0
37
local nDepth    = 0
38
local nMined    = 0
39
local stopCause = 0
40
local xDir,yDir = 0,-1
41
local nDigDir   = -1 -- -1 = down, 1 = up
42
local nRadiusX, nRadiusY = 0,0
43
local tmpDepth = -1 -- backup, when returning home
44
-- ----------------------------------------------------------
45
function saySingle(str)
46
	write(str)
47
end
48
-- ----------------------------------------------------------
49
local function say(message)
50
	if bRedNet == true then
51
		rednet.send(nMasterComputerID, message)
52
	end
53
	print(message)
54
	-- sleep(0.2)
55
end
56
-- ----------------------------------------------------------
57
local function turnLeft()
58
	turtle.turnLeft()
59
	xDir, yDir = -yDir, xDir
60
end
61
-- ----------------------------------------------------------
62
local function turnRight()
63
	turtle.turnRight()
64
	xDir, yDir = yDir, -xDir
65
end
66
-- ----------------------------------------------------------
67
local function recharge()
68
	say("trying to recharge")
69
	turtle.select(nBatterySlot)
70
	local e = turtle.getFuelLevel()
71
	turtle.refuel()
72
	nEnergy = turtle.getFuelLevel()
73
	say("fuel: "..e.." -> "..nEnergy)
74
	if nEnergy > e then
75
		return true
76
	end
77
	return false
78
end
79
-- ----------------------------------------------------------
80
local function unloadCargo()
81
	local ende = 16 - nReservedSlots
82
    for invloop=1,16 do
83
    	if invloop ~= nBatterySlot then
84
    		-- say("Drop item in Slot "..invloop)
85
    		turtle.select(invloop)
86
    		turtle.drop()
87
    	end
88
    end
89
end
90
-- ----------------------------------------------------------
91
local function getFreeSlots()
92
    local nSpace = 0
93
    for invloop=1,16 do
94
        local items = turtle.getItemCount(invloop)
95
        if items == 0 then
96
            nSpace = nSpace + 1
97
        end
98
    end
99
    return nSpace
100
end
101
-- ----------------------------------------------------------
102
local function collect()
103
	nMined = nMined + 1
104
	if math.fmod(nMined, 25) == 0 then
105
		say( "Mined "..nMined.." blocks." )
106
	end
107
	
108
	if getFreeSlots() > 0 then
109
		return true
110
	end
111
	
112
	say( "No empty slots left." )
113
	return false
114
end
115
-- ----------------------------------------------------------
116
local function attackMode()
117
	local bAttacked = false
118
	while turtle.attack() do
119
		say("Attacking!!1")
120
		bAttacked = true
121
	end
122
    return bAttacked 
123
end
124
-- ----------------------------------------------------------
125
local function tryForwards()
126
127
	local nMaxTries = 10
128
	local nTries = 0
129
130
	stopCause = 0
131
132
	while not turtle.forward() do
133
		if nTries > 0 then
134
			say("Try to move forward, "..nTries.." try.")
135
		end
136
		if turtle.dig() then
137
			if not collect() then
138
				say("abort reason 2")
139
				stopCause = 2
140
				return false
141
			end
142
	    else
143
	    	if attackMode() then
144
	    		-- attacking should not reduce tries
145
	    		nTries = nTries - 1
146
	    		if nTries < 0 then
147
	    			nTries = 0
148
	    		end
149
	    	end
150
	    end
151
152
		-- give sand a chance to fall
153
 		sleep(0.8)
154
 		nTries = nTries + 1
155
 		if nTries >= nMaxTries then
156
 			say("abort reason 2")
157
 			return false
158
 		end
159
	end
160
	--xPos = xPos + xDir
161
	--zPos = zPos + zDir	
162
	return true
163
end
164
-- ----------------------------------------------------------
165
local function tryDown()
166
	stopCause = 0
167
	if currentZ == nMaxDepth then
168
		say("tryDown: already at max depth")
169
		return false
170
	end
171
172
	if not turtle.down() then
173
		if turtle.digDown() then
174
			if not collect() then
175
				stopCause = 2
176
				return false
177
			end
178
		end
179
		if not turtle.down() then
180
			stopCause = 1
181
			return false
182
		end
183
	end
184
	
185
	currentZ = currentZ + 1
186
187
	--if math.fmod( nDepth, 10 ) == 0 then
188
	say( ">>> Descended "..currentZ.." metres. <<<" )
189
190
	return true
191
end
192
-- ----------------------------------------------------------
193
local function tryUp()
194
	stopCause = 0
195
	if currentZ == nMaxDepth then
196
		say("tryDown: already at max depth")
197
		return false
198
	end
199
200
	if not turtle.up() then
201
		if turtle.digUp() then
202
			if not collect() then
203
				stopCause = 2
204
				return false
205
			end
206
		end
207
		if not turtle.up() then
208
			stopCause = 1
209
			return false
210
		end
211
	end
212
	
213
	currentZ = currentZ + 1
214
215
	--if math.fmod( nDepth, 10 ) == 0 then
216
	say( ">>> Ascended "..currentZ.." metres. <<<" )
217
218
	return true
219
end
220
-- ----------------------------------------------------------
221
222
-- ----------------------------------------------------------
223
-- S T A R T
224
-- ----------------------------------------------------------
225
226
say("Mining Bot v0.1 - Welcome!")
227
say("Turtle "..sBotLabel.." ready for action.")
228
say("")
229
saySingle("Radius Y (forward, uneven): ")
230
nRadiusY = read()
231
saySingle("Radius X (to the right, uneven, Y default): ")
232
nRadiusX = read()
233
saySingle("Radius Z (up/down): ")
234
nMaxDepth = read()
235
saySingle("Dig (d)own or (u)p? (default down) ")
236
nDigDir = read()
237
saySingle("Is this a resume? (y/n): ")
238
bResume = read()
239
240
-- todo: verify input. for now just convert
241
-- nRadius = tonumber( nRadius )
242
nMaxDepth = tonumber( nMaxDepth )
243
if bResume == "y" then
244
	bResume = true
245
else 
246
	bResume = false
247
end
248
if nMaxDepth < 1 then
249
	say("Depth provided too shallow" )
250
	return
251
end
252
253
nRadiusX = tonumber( nRadiusX )
254
if nRadiusX == 0 then
255
	nRadiusX = nRadiusY
256
end
257
258
if nDigDir ~= nil then
259
    if nDigDir == "u" then
260
        nDigDir = 1
261
    else
262
        nDigDir = -1
263
    end
264
else
265
    nDigDir = -1
266
end
267
268
269
-- Repeat what we understood
270
say("I should mine in a radius of "..nRadiusX..","..nRadiusY.."to a nDepth of "..nMaxDepth)
271
if bResume == true then
272
	say("This is a resume operation")
273
else 
274
	say("This is not a resume operation")
275
end
276
277
-- ----------------------------------------------------------
278
279-
bRedNet = rednet.open("right")
279+
280
-- init wireless
281
----------------------------
282
-- bRedNet = rednet.open("right")
283-
bRedNet = true
283+
284
--	bRedNet = rednet.open("left")
285
-- end
286
bRedNet = false
287
if bRedNet == true then
288
	say("Rednet enabled")
289
	rednet.send(nMasterComputerID, sBotLabel.." reporting in.")
290
else 
291
	say("no rednet available")
292
end
293
294
295
-- ----------------------------------------------------------
296
local function isOperational()
297
298
	-- get energy
299
	local nEnergyLevel = turtle.getFuelLevel()
300
	-- get needed energy for way back home
301
	local nSteps = currentX + currentY + currentZ
302
	local required = 0
303
	
304
	if nEnergyLevel < nSteps then
305
		say("ALERT: Not enough energy to return home.")
306
		say("Current Energy: "..nEnergyLevel.."E")
307
		say("Needed :"..nSteps.."E")
308
		say("We will do what we can... :-/")
309
		return false
310
	end
311
	--   y*(x + 2) for movement
312
	required = required + (nRadiusX * (nRadiusY+2))
313
	-- + (x*y) for dig
314
	required = required + (nRadiusX * nRadiusY)
315
	-- + energy for way back home
316
	required = required + nSteps
317
	-- + safety margin
318
	required = required + nEnergySafetyMargin
319
	-- = energy requirement
320
	say("Energy: "..required.."E req. "..nEnergyLevel.."E avail.")
321
322
	if nEnergyLevel <= required then
323
		say("Not enough energy for a full cycle.")
324
		-- Try to recharge
325
		if recharge() == true then
326
			-- recheck energy
327
			if nEnergyLevel <= required then
328
				say("Still not enough energy for a full cycle.")
329
				return false
330
			end
331
		else
332
			-- failed to recharge, abort.
333
			say("Could not recharge.")
334
			return false
335
		end
336
	end
337
338
	-- check inventory
339
	local emptySlots = getFreeSlots()	
340
	if emptySlots < nEmptySlotsMargin then
341
		say(emptySlots.." Slots left. Need "..nEmptySlotsMargin)
342
		return false
343
	end
344
345
	-- all cool
346
	return true
347
end
348
-- ----------------------------------------------------------
349
local function saveStatus()
350
	-- save which depth we have been on
351
	-- for sake of simplicity, we will restart on that layer
352
	-- when resuming, not returning to exact last position.
353
	tmpDepth = currentZ
354
end
355
-- ----------------------------------------------------------
356
local function waitForEnergy()  
357
	local count = 0
358
	local hasEnergy = false
359
	say("Waiting for energy in Slot "..nBatterySlot)
360
361
	while not hasEnergy do
362
		if recharge() == true then
363
			hasEnergy = true
364
			return true
365
		else
366
			sleep(5)
367
			count = count + 1
368
			if count == 5 then
369
				say("Waiting for energy in Slot "..nBatterySlot)
370
				count = 0
371
			end
372
		end
373
	end
374
	return true
375
end
376
-- ----------------------------------------------------------
377
local function goHome(vDir, bResume)
378
	say("Going Home :)")
379
380
	say("Dir: "..xDir..","..yDir)
381
382
	-- needs to face left
383
	if yDir == -1 then
384
		if xDir == 1 then
385
			turnRight()
386
		elseif xDir == -1 then
387
			turnLeft()
388
		else
389
			turnLeft()
390
			turnLeft()
391
		end
392
	elseif yDir == 0 then
393
		if xDir > 0 then 
394
			turnLeft()
395
		else
396
			turnRight()
397
		end
398
	elseif xDir > 0 or xDir < 0 then
399
		if xDir > 0 then
400
			turnRight()
401
		else
402
			turnLeft()
403
		end
404
	end
405
406
	-- if energy too low, go to a wait-for-recharge loop
407
	nEnergy = turtle.getFuelLevel()
408
	if nEnergy < 5 then
409
		waitForEnergy()
410
	end
411
412
	say("I am at "..currentX..","..currentY..","..currentZ)
413
414
	if nDigDir == 1 then
415
		while currentZ > 0 do
416
			if not turtle.down() then
417
				say("ALERT: Failed to move down while returning")
418
				return false
419
			end
420
			currentZ = currentZ - 1
421
		end	
422
	else
423
		while currentZ > 0 do
424
			if not turtle.up() then
425
				say("ALERT: Failed to move up while returning")
426
				return false
427
			end
428
			currentZ = currentZ - 1
429
		end	
430
	end
431
432
	if currentX > 0 then
433
		turnRight()
434
		while currentX > 0 do
435
			if not tryForwards() then
436
				say("ALERT: Failed to move forward(X) while returning")
437
				return false
438
			end
439
			currentX = currentX - 1
440
		end
441
		turnLeft()
442
	end
443
444
	while currentY > 0 do
445
		if not tryForwards() then
446
			say("ALERT: Failed to move forward(Y) while returning")
447
			return false
448
		end
449
		currentY = currentY - 1
450
	end
451
452
	say("Should be at home. hopefully. :)")
453
	return true
454
end
455
-- ----------------------------------------------------------
456
local function waitForInput()
457
	local id,message,distance = rednet.receive(0.05)
458
	if id ~= nil then
459
		if message == "terminate" then
460
			say("Message: Terminate")
461
			exit()
462
		elseif message == "home" then
463
			say("Message: Go home")
464
			goHome()
465
			exit()
466
		end
467
	end
468
end
469
-- ----------------------------------------------------------
470
-- 0 = normal, like 1st layer
471
-- 1 = reverse direction, every 2nd layer
472
layerdirection = 1
473
startX,startY,startZ = 0,0,0
474
local v
475
476
local function work(nHowDeep, nSizeX, nSizeY, nDir) 
477
	local depth,x,y
478
 	local startZ = currentZ
479
say("StartZ: "..startZ)
480
481
	local bFirstLoop = false
482
483
	for depth=startZ,nHowDeep do
484
485
		-- full check each layer
486
		if not isOperational() then
487
			say("Depth-Check: returning home")
488
			saveStatus()
489
			goHome(v, true)
490
			return true
491
		end
492
493
		for x=0,(nSizeX-1) do
494
495
			-- waitForInput()
496
497
			-- first row has no turn move
498
			-- which needs to be offset
499
			local startY = 1
500
501
			if x == 0 and startZ == 0 and depth == 0 then
502
				startY = 0
503
			elseif bFirstLoop == true then
504
				startY = 0
505
			end
506
507
			if x == 0 then
508
				say("SY: "..startY)
509
			end
510
511
			for y=startY,(nSizeY-1) do
512
513
				local start = currentX..","..currentY..","..currentZ
514
				
515
				v = math.fmod(x,2)
516
				-- v == 0 = facing away. like start
517
				-- v == 1 = facing to start
518
				-- say("V: "..v.." LD: "..layerdirection.." SY: "..startY.." xyz: "..x..","..y..","..depth)
519
520
521
				-- checks
522
				-- simple inventory check here
523
				local emptySlots = getFreeSlots()
524
				if emptySlots < nEmptySlotsMargin then
525
					say(emptySlots.." Slots left. Need "..nEmptySlotsMargin)
526
					saveStatus()
527
					goHome(v, true)
528
					return true
529
				end
530
531
				if not tryForwards() then
532
					if stopCause == 2 then
533
						-- inventory full?!
534
						say("Failed to move forward. Inv. full?!")
535
						saveStatus()
536
						goHome(v, true)
537
						return true
538
					else 
539
						say("Failed to move forward.")
540
						saveStatus()
541
						goHome(v, false)
542
						return false
543
					end
544
				end
545
546
				if layerdirection == 1 then
547
					if v == 0 then
548
						currentY = currentY + 1
549
					else
550
						currentY = currentY - 1
551
					end
552
				else
553
					if v == 0 then
554
						currentY = currentY - 1
555
					else
556
						currentY = currentY + 1
557
					end
558
				end
559
560
				-- say("P: "..start.." -> "..currentX..","..currentY..","..currentZ)
561
				-- say("Dir: "..xDir..","..yDir)
562
			-- end y loop
563
			end	
564
565
			bFirstLoop = false;
566
567
			say("completed one line")
568
569
			-- if not on last line
570
			if  x < nSizeX-1 then
571
				-- move to next line (turn, move, turn)
572
				if v == 0 then
573
574
					say("Moving to next row (1)")
575
					turnRight()
576
					-- to be on the safe side:
577
					if not isOperational() then
578
						saveStatus()
579
						goHome(v, true)
580
						return true
581
					end
582
583
					if not tryForwards() then
584
585
						if stopCause == 2 then
586
							-- inventory full?!
587
							say("Failed to move forward. Inv. full?!")
588
							saveStatus()
589
							goHome(v, true)
590
							return true
591
						else 
592
							saveStatus()
593
							goHome(v, false)
594
							return false
595
						end						
596
					end
597
598
					turnRight()
599
				else 
600
					say("Moving to next row (2)")
601
					turnLeft()
602
603
					-- to be on the safe side:
604
					if not isOperational() then
605
						saveStatus()
606
						goHome(v, true)
607
						return true
608
					end
609
610
					if not tryForwards() then
611
						if stopCause == 2 then
612
							-- inventory full?!
613
							say("Failed to move forward. Inv. full?!")
614
							saveStatus()
615
							goHome(v, true)
616
							return true
617
						else 
618
							saveStatus()
619
							goHome(v, false)
620
							return false
621
						end
622
					end
623
624
					turnLeft()
625
				end
626
627
				if layerdirection == 1 then
628
					currentX = currentX + 1
629
				else
630
					currentX = currentX - 1
631
				end
632
			end
633
634
635
		-- end x loop
636
		end
637
638
		say("completed one layer")
639
640
		-- checks if depth reached
641
		if depth < nHowDeep then
642
643
			if nDir == 1 then
644
				if not tryUp() then
645
					-- unable to move down?
646
					-- assume we hit bedrock
647
					goHome(v, false)
648
					return true
649
				end
650
			else
651
				if not tryDown() then
652
					-- unable to move down?
653
					-- assume we hit bedrock
654
					goHome(v, false)
655
					return true
656
				end
657
			end
658
659
			if layerdirection == 1 then
660
				layerdirection = 0
661
			else
662
				layerdirection = 1
663
			end
664
665
			turnLeft()
666
			turnLeft()
667
		else
668
			say("finished all layer")
669
			-- finished
670
			saveStatus()
671
			goHome(v, false)
672
			return true
673
		end
674
		-- end z loop
675
	end
676
	say("should not hit this code line")
677
end
678
-- ----------------------------------------------------------
679
local function resume()
680
	local depthcounter = 0
681
682
	-- move away from start
683
	tryForwards()
684
	currentY = currentY + 1
685
686
	-- if tmpZ isgiven, go down to that Z
687
	if tmpDepth == -1 then
688
		if nDigDir == 1 then
689
			while turtle.up() == true do
690
				depthcounter = depthcounter + 1
691
			end
692
			say("Resume: We hit ceiling at "..depthcounter)
693
		else
694
			while turtle.down() == true do
695
				depthcounter = depthcounter + 1
696
			end
697
			say("Resume: We hit ground at "..depthcounter)
698
		end
699
		-- find ground
700
		currentZ = depthcounter
701
	else
702
		-- resuming last position
703
		while depthcounter < tmpDepth do
704
705
			if nDigDir == 1 then
706
				if turtle.up() == true then
707
					depthcounter = depthcounter + 1
708
				else
709
					-- we hit something.
710
					say("We hit something while going up.")
711
					say("Starting a new, full cycle at this position.")
712
					currentZ = depthcounter
713
					return
714
				end
715
			else
716
				if turtle.down() == true then
717
						depthcounter = depthcounter + 1
718
				else
719
					-- we hit something.
720
					say("We hit something while going down.")
721
					say("Starting a new, full cycle at this position.")
722
					currentZ = depthcounter
723
					return
724
				end
725
			end
726
		end
727
		currentZ = depthcounter
728
	end
729
end
730
731
-- ----------------------------------------------------------
732
-- END MAIN LOOP FUNCTION
733
-- ----------------------------------------------------------
734
735
736
local done = false
737
738
while not done do
739
740
	sleep(5)
741
742
	-- determine min. energy for next cycle
743
	local required = 0
744
	-- z for going back down
745
	required = required + tmpDepth
746
	-- + enough for at least two full layers
747
	required = required + (2 * (nRadiusX * (nRadiusY+2)))
748
	required = required + (2 * (nRadiusX * nRadiusY))
749
	-- + energy for way back home
750
	required = required + (nRadiusX + nRadiusY + nMaxDepth)
751
	-- + safety margin
752
	required = required + nEnergySafetyMargin
753
	nEnergy = turtle.getFuelLevel()
754
	say("Need about "..required.."E for resuming. Have: "..nEnergy.."E")
755
756
	-- recharge if needed. 
757
	while nEnergy < required do
758
		if not recharge() then 
759
			waitForEnergy()
760
		end
761
	end
762
763
	-- first run, still in original position
764
	-- fill face other direction when returning
765
	if tmpDepth == -1 then
766
		turnLeft()
767
		turnLeft()
768
	end
769
	
770
	-- unload cargo
771
	say("Unloading Cargo")
772
	unloadCargo()
773
774
	turnLeft()
775
	turnLeft()
776
777
	-- reset vars
778
	layerdirection = 1
779
	startX,startY,startZ = 0,0,0
780
781
	-- if resuming by prompt or resuming running operation
782
	if bResume == true or tmpDepth > -1 then
783
		resume()
784
	end
785
786
	-- start normal operation
787
	local status = work(nMaxDepth, nRadiusX, nRadiusY, nDigDir)
788
789
	if not status then
790
		-- either something went wrong, or we have finished
791
		done = true
792
793
		if tmpDepth == nMaxDepth then
794
			say("**** Successfully finished ****")
795
		else
796
			say("Something went wrong")
797
		end
798
	else
799
		-- we assume a successful cycle.
800
		say("Finished a successful cycle")		
801
		if tmpDepth == nMaxDepth then
802
			done = true
803
			say("**** Successfully finished ****")
804
			say("Unloading Cargo")
805
			unloadCargo()
806
			turnLeft()
807
			turnLeft()
808
		else
809
			-- resume
810
			say("Resuming")
811
		end
812
	end
813
	nRuns = nRuns + 1
814
end
815
816
say( "Mined "..nMined.." blocks total in "..nRuns.." runs." )