This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Axim's profile picture

Need help fixing my turtle quarry script

Started by Axim, 21 December 2015 - 05:09 PM
Axim #1
Posted 21 December 2015 - 06:09 PM
Hey guys, I'm currently working on a turtle quarry script, one that mines 3 blocks per move to be specific.
I had it close to working perfectly at one point, but I guess I messed up majorly on a recent change and now I can't find where the problem is.

Here's my code so far

The problem I'm having is that sometimes when unloading, it won't properly return to the spot it was mining, and will start going off in different directions. You can provoke this by putting an item in slot 16 while the turtle is mining. I'm guessing the bug is probably somewhere in my goTo funtion, but I swear I've checked and double-checked it all and I can't find it. I hope getting a second set of eyes in on this issue will help get it resolved.
Edited on 21 December 2015 - 05:33 PM
Bomb Bloke #2
Posted 22 December 2015 - 12:34 AM
Just at a quick-ish look, you've got lines 173 and 183:

    forward(xX - xx)
    forward(zZ - zz)

It looks like xx / zz have the potential to be higher than xX / zZ, in which case you'll be calling forward() with a negative value (which'll cause it to do nothing).

A note on function calling, at the moment you're doing this sort of thing:

function goTo(pos)
    local xX, yY, zZ, xXDir, zZDir = pos[1], pos[2], pos[3], pos[4], pos[5]
    -- etc
end

goto( {0, 0, 0, 0, -1} )

pos = {xx, yy, zz, xDir, zDir}

goTo( pos )

You have the option of doing it this way:

function goTo(xX, yY, zZ, xXDir, zZDir)
    -- etc
end

goto( 0, 0, 0, 0, -1 )

pos = {xx, yy, zz, xDir, zDir}

goTo( unpack( pos ) )
Axim #3
Posted 22 December 2015 - 04:00 PM
Just at a quick-ish look, you've got lines 173 and 183:

	forward(xX - xx)
	forward(zZ - zz)

It looks like xx / zz have the potential to be higher than xX / zZ, in which case you'll be calling forward() with a negative value (which'll cause it to do nothing).

That wouldn't be an issue, since my movement functions will get the absolute value of the argument supplied before doing anything.
But I can see why that would be counterintuitive and confusing, so I moved that bit of code into my goTo function just now.

A note on function calling, at the moment you're doing this sort of thing:

function goTo(pos)
	local xX, yY, zZ, xXDir, zZDir = pos[1], pos[2], pos[3], pos[4], pos[5]
	-- etc
end

goto( {0, 0, 0, 0, -1} )

pos = {xx, yy, zz, xDir, zDir}

goTo( pos )

You have the option of doing it this way:

function goTo(xX, yY, zZ, xXDir, zZDir)
	-- etc
end

goto( 0, 0, 0, 0, -1 )

pos = {xx, yy, zz, xDir, zDir}

goTo( unpack( pos ) )

You're right, that is indeed a much nicer way of doing it, thanks.

Anyway, here's the new version of my script (still bugging out)
For comparison, here's the older one from before I messed up (works as intended)
And just for good measure, here's the difference between the two
Edited on 22 December 2015 - 03:08 PM
Bomb Bloke #4
Posted 23 December 2015 - 12:21 PM
Just got around to taking another look at this, but even on downloading the script and testing it out directly, I can't see the issue - it's working here. Did you make further changes?

Edit:

Actually, now it's gone and done something weird: I was bullying it with creeper eggs, and it suddenly decided to detour off and dig out a new shape. Thing is this didn't involve dropping off loot, and if I move stuff to slot 16, it still correctly goes back to the chest and then returns to where it left off.

Edit 2:

Well, I see some issues; I'm not sure they're causing your symptoms, but you may as well patch them up and see what difference they make.

Down the bottom of your script is this:

		for jj = 1, iLength-1 do
			if done then break end
			done = not mineFwd()
		end
		if ii < iWidth then
			if math.fmod(ii + alternate, 2) == 0 then
				iLeft()
				done = not mineFwd()
				iLeft()
			else
				iRight()
				done = not mineFwd()
				iRight()
			end
		end

If the row fails to mine, but the turtle still manages to turn around, then "done" ends up being false again. Around bedrock, the problem will soon correct itself (because it won't be able to continue much further anyway), but…

mineFwd() and forward() both have a potential loophole: they each check if there's a block in front of them using turtle.detect(), and then try to mine it with turtle.dig().

If the latter's not possible (say because a creeper blew the block up in the fraction of a second it took between the two checks (which is about 0.3s); turtle strikes do set them off), then the functions return false. So your loop down the bottom may take that as an excuse to end the row early, but since there's no real obstructions around, the turtle will continue with the next row from there anyway (as "done"'ll get set to false as soon as the turtle turns around).

The turtle still knows exactly where it is - hence why it can still get to the chest and back again - but this leads to it making a rather haphazard trail downwards.

The fix is to invert the call order; if you can't dig, then detect, and if you can detect, then you've hit something you truly can't get past.

		while not turtle.forward() do
			if turtle.dig() then
				iBlock()
			elseif turtle.detect() then
				return false
			end
			turtle.attack()
			turtle.suck()
		end

You may also consider bundling that bottom main "while" loop off into a function. That way, it can return the moment "done" turns true, preventing the messiness you may otherwise see around bedrock level.
Edited on 23 December 2015 - 01:04 PM
Axim #5
Posted 23 December 2015 - 06:27 PM
Thanks a lot for your help, I think I got it all figured out now. Thanks especially for testing how it works when mobs get in the way, I hadn't even considered that yet. Well, I considered it just enough to put a couple turtle.attack calls across my code, but I never bothered to test it.
I guess I inadvertently fixed my original bug in the last version, when I changed the dropLoot function to select slot 1 before calling goTo(pos) instead of after. I'm still kinda weirded out because v0.7 also had it in that order and that one works reasonably well. Anyway I'm pretty sure I got the bug fixed for good now and can go back to adding more features (and thus, bugs).

Here's the latest version of the script
Feel free to keep messing around with it and please let me know if you find anymore bugs or weird/inefficient behaviors.
Edited on 23 December 2015 - 05:29 PM
Bomb Bloke #6
Posted 23 December 2015 - 11:10 PM
Dunno about bugs, but here's a couple of tips you might find useful.

Using the technique discussed here, you can reduce this sort of thing:

    local pos = {0, 0, 0, 0, 1}
    if not done then pos = {xx, yy, zz, xDir, zDir} end

… down to this:

    local pos = done and {0, 0, 0, 0, 1} or {xx, yy, zz, xDir, zDir}

When you define a function, you're initialising a variable and setting it to hold a pointer to the function code. That variable can and should be localised, same as any other:

local function iBlock()

However, you'll notice that doing this triggers some errors within your script: if you define a function which attempts to call functions that haven't been defined yet, then the former will always attempt to find the latter within the global scope. If you only later define the latter functions in the local scope, then the former functions won't find them there and will crash out with "attempts to call nil". The solution is to either ensure that you never try to reference a function before it's defined, or to use forward declarations (first declare the variables for your functions as local, then later assign the actual functions to them - all references in the meantime will then lead to the local versions). See this guide on scope for more info.