I'm sorta guessing, but I reckon your issue has something to do with this here "for" loop:
for j = 1, distance do
toGo = height - math.abs(yCoord)
if toGo > 3 then
distance = 3
inc = 3
else
distance = 1
inc = 1
end
print("Height: "..height)
print("HeightOpp: "..heightOpp)
print("To Go: "..toGo)
print("Distance: "..distance)
print("Increment: "..inc)
down()
end
Lua's "for" loops operate a bit differently from other languages I've dealt with.
For starters, the conditions you set on that first line are "set in stone", so to speak. Say "distance" is set to 1 and the Lua interpretor hits the line that reads:
for j = 1, distance do
It'll start a "loop" that only runs once. Even though that one instance of the "loop" it runs may change the value of "distance", it'll still only run once, because the value of "distance" was 1 when the loop was defined.
The other oddity is that you don't have much wriggle room for playing with "j", either. Say you defined a loop like this:
for j=1,10 do
j = j - 1
end
Under other languages, this'd be an infinite loop. Under Lua it'll undo your changes to "j" with each iteration.
Another thing worth bearing in mind (which isn't Lua-specific) is that impossible loops are skipped. For eg:
for j=1,0 do
print("Hello")
end
You're asking it to count upwards from 1 to 0 - can't be done. The interpretor spots that 1) it's supposed to count up, and 2) its starting value exceeds its target value, and so it simply skips the entire loop on the basis that it's technically already completed.
Which means once you set "distance" to 0 the loop'll never run again.
Generally, having a function call itself is a bad idea.
I feel I must stress this.
When you call a function, Lua dumps it into a list of active functions - the stack. With every function call you make the amount of functions in the stack increases. When a function finishes, it decreases. A function that calls another function will typically not be able to complete until the second function completes. A function that calls itself (a recursive call) may, if improperly coded, lead to an infinite loop of function calls.
Obviously there is a limit to how many function calls you can have active at once. Exceed that, and the resulting stack overflow will crash your script.
For example, let's take a look at your beginMine() function:
function beginMine()
if turtle.detect() == true then
turtle.dig()
end
if turtle.forward() == true then
xCoord = 0
yCoord = 0
zCoord = 1
distance = 0
else
beginMine()
end
turnRight()
end
If a block is in front of the turtle, it'll attempt to dig it out. Successful or otherwise, it then attempts to move forwards. If that movement attempt failed - say some gravel fell in front of it, or a mob just happened to be standing there - then the same function gets called again.
In the event that after a couple of hundred calls the turtle still hasn't succeeded in moving (let's say there was some bedrock there, or a mob with nothing better to do), it'll crash out. Worse still, however, is that in this particular case if the turtle
does eventually get to move (say three bits of gravel fell down) - the instance of beginMine() that first succeeds in moving will go forward, turn right, and then finish. It'll then give control back to the instance of beginMine() that called it, which'll turn right and then finish. Control then goes to the instance of beginMine() that called
that, which'll turn right again…
If you want something to repeat until it succeeds, don't use recursive function calls. Use either a
"while" or a "repeat" loop.
Eg:
function beginMine()
if turtle.detect() then -- "if" statements already check to see if something is true. Checking if "turtle.detect() == true" is a redundant extra step.
if not turtle.dig() then
return -- Exit the function if we can't go forward (eg hit bedrock). You might print errors or something too, perhaps.
end
end
while not turtle.forward() do -- So long as attempts to move forward fail...
turtle.dig() -- ... try to dig (in case gravel fell)...
turtle.attack() -- ... and try to attack (in case there's a mob there).
end
-- The loop ends once the attempt to move forward succeeds.
xCoord = 0
yCoord = 0
zCoord = 1
distance = 0
turnRight()
end
To be clear, yes, I'm saying that much of the script really needs similar treatment.
What is the best way to teach yourself to think in programming so that I can program much better and see these stupid mistakes I make before I make them?
Practise, quite frankly.
That is to say, don't worry too much about making mistakes - code what you think should work, don't be too afraid to fill the gaps in your knowledge with assumptions, just code something - and then run it. Watch what it does, learn from that, you'll be able to make less assumptions next time. Really all you need is motivation to write something.
If you don't
know what your code just did, then make it obvious. For example, add print statements - if I write a complex bit of code that's buggy (but not buggy enough to cause a crash with a helpful error message), I'll place in unique print statements throughout along the lines of "debug1", "debug2", etc. By watching the order in which these fire off (or even
if certain ones get to fire at all) it makes it very easy to see what the flow of a program looks like, and thus to pinpoint where to look for the mistake.