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

Programming my own Mining Turtle Program - API issues

Started by xBlizzDevious, 10 February 2014 - 01:25 PM
xBlizzDevious #1
Posted 10 February 2014 - 02:25 PM
Hey guys, new to the forum but I've been doing little bits of programming here and there every now and then, whether it be in Minecraft on CC or whether it be college work or just me programming because I enjoy it. I'm certainly not very advanced but I'm getting better.

What I'm trying to do here, is to create an API for my turtle that will have a number of mining related functions and then have a main program that will run the main menu and access the API. I seem to be struggling with this though as I can't figure out how to make it work the way I'm expecting.

I may be missing something simple, but when I try to access my API, my main menu program errors out and tells me that there is a nil value.

Here's the main menu so far. I'm just doing testing to make sure it works at all. Haha!

Spoiler

function mineMenu()
  term.clear()
  term.setCursorPos(1,1)
  print("Please choose the type of")
  print("mine that you would like:")
  print("1. Hole")
  print("2. Tunnel")
  print("3. Branch Mine")
  begin()
end

function begin()
  local userInput = read()
  if userInput == "1" then
	miner.holeMenu()
  elseif userInput == "2" then
	miner.tunnelMenu()
  elseif userInput == "3" then
	miner.branchMenu()
  else
	print("That was an invalid selection")
	sleep(2)
	mineMenu()
  end
end

mineMenu()

And here is the API that I'm trying to access. My code may break the standards and it may use stupid ways of doing things, but it's basically all I know and what I've thought of in my head.

Spoiler

local x = 0
local y = 0
local z = 0
local width = 0
local height = 0
local length = 0
local leftCount = 0
local rightCount = 0
local curDur = "forward"
local userInput = ""

function clearScreen()
  term.clear()
  term.setCursorPos(1,1)
end

function checkOdd()
  if (userInput % 2 == 0) then
	print("That is an even number.")
	print("Please input an ODD number:")
	userInput = read()
	checkOdd()
  else
	return
  end
end

function holeMenu()
  clearScreen()
  print("You have chosen to dig a hole.")

  print("Please enter an odd number for width")
  userInput = read()
  checkOdd()

  print("Please enter a number for the length")
  length = read()

  print("You have chosen to dig a "..width.." by "..length.." hole.")
  print("Is this correct (Y/N):"
  local yesNo = read()
  if yesNo == "y" or yesNo == "Y" then
	hole()
  elseif yesNo == "n" or yesNo == "N" then
	holeMenu()
  else
	print("Invalid input - try again")
	sleep(2)
	holeMenu()
  end
end

function forward()
  if turtle.detect() == true then
  end
end
Grim Reaper #2
Posted 10 February 2014 - 04:13 PM
In your main file, you have to load the API so that you can use it in that scope. When you try to access 'miner', your program looks for a table called 'miner', but, since you haven't loaded it, the identifier 'miner' is of nil value. To load the API, you simply have to type the following at the top of your main file:


os.loadAPI ("/miner")

You can change "/miner" to the correct file path and name. os.loadAPI loads the contents of that file into a table which is the name of the file and adds it to the global table (_G). You can also load it more directly by putting a return statement at the end of your api which returns all of the functions and data you want to have access to in a table, then run that file at the top of your main file and catch whatever it returns in the 'miner' table.

Miner:

-- . . . Miner api here.
return getfenv() -- Returns everything in the "top" scope for the miner file. (Everything that wasn't declared as local).

Main:

local miner = dofile ("/miner")
xBlizzDevious #3
Posted 10 February 2014 - 04:28 PM
In your main file, you have to load the API so that you can use it in that scope. When you try to access 'miner', your program looks for a table called 'miner', but, since you haven't loaded it, the identifier 'miner' is of nil value. To load the API, you simply have to type the following at the top of your main file:


os.loadAPI ("/miner")

You can change "/miner" to the correct file path and name. os.loadAPI loads the contents of that file into a table which is the name of the file and adds it to the global table (_G). You can also load it more directly by putting a return statement at the end of your api which returns all of the functions and data you want to have access to in a table, then run that file at the top of your main file and catch whatever it returns in the 'miner' table.

Miner:

-- . . . Miner api here.
return getfenv() -- Returns everything in the "top" scope for the miner file. (Everything that wasn't declared as local).

Main:

local miner = dofile ("/miner")

Thanks for the quick response. However, I'm a little confused by the second half of your post about returning the table and using the miner = dofile bit. Would you be able to explain it a bit more for me please?


Also, I have added the os.loadAPI("/miner") code and it did not work. I'm getting the exact same error.

In your main file, you have to load the API so that you can use it in that scope. When you try to access 'miner', your program looks for a table called 'miner', but, since you haven't loaded it, the identifier 'miner' is of nil value. To load the API, you simply have to type the following at the top of your main file:


os.loadAPI ("/miner")

You can change "/miner" to the correct file path and name. os.loadAPI loads the contents of that file into a table which is the name of the file and adds it to the global table (_G). You can also load it more directly by putting a return statement at the end of your api which returns all of the functions and data you want to have access to in a table, then run that file at the top of your main file and catch whatever it returns in the 'miner' table.

Miner:

-- . . . Miner api here.
return getfenv() -- Returns everything in the "top" scope for the miner file. (Everything that wasn't declared as local).

Main:

local miner = dofile ("/miner")

*Would edit my last post but I can't until it's been approved

EDIT: I just realised that I'm an idiot. I think I even made the mistake in the post I made. I used a "/" instead of a "\". Doh!
Grim Reaper #4
Posted 10 February 2014 - 10:47 PM
So, if I had this basic API which had some functions which added and subtracted, I could make it an API this way:


function add (firstNumber, secondNumber)
  return firstNumber + secondNumber
end

function subtract (firstNumber, secondNumber)
  return firstNumber - secondNumber
end

return getfenv()

When you create some data which is not initialized with the 'local' keyword, you're adding it to what is called the function's environment. Also, a good thing to note is that when you run programs in lua, they're run as functions, but you're just not aware that it's happening that way. Every function has its own environment as well.

So, getfenv() returns the function you're calling it in's environment, if that makes sense. So, when I create those two functions without localizing them, they're added to the api's environment and I return the environment with those two functions in them.

To get these functions, you have to run that api as a function. I did this using the dofile function which loads the file into an executable function, executes that function, and returns whatever that function returns. Therefore, when I use dofile on that api, I get whatever that api returns which was that api's environment containing those two functions.

Wow. That was quite the ramble. Anyway, I hope you get the point.

The main file would then look like this:

local miner = dofile ("/miner")
Lyqyd #5
Posted 10 February 2014 - 11:44 PM
That's really not best practices. Given two equally useful options, one should stick to suggesting the best practice option first and foremost. APIs should be loaded with os.loadAPI, not dofile, whenever possible.
xBlizzDevious #6
Posted 11 February 2014 - 04:02 AM
That's really not best practices. Given two equally useful options, one should stick to suggesting the best practice option first and foremost. APIs should be loaded with os.loadAPI, not dofile, whenever possible.

Well it seems that my slashes and backslashes being mixed up makes no difference. The program cannot access the API whether I use a slash or a backslash. I've tried re-arranging the folder structure too, but it didn't do anything either.

Anyone know why I'm having an issue? Thanks
Lyqyd #7
Posted 11 February 2014 - 10:17 AM
Folder structure? os.loadAPI requires an absolute path relative to the computer's root folder, so if it isn't at /miner, it won't load it given that path. If you had it in a folder named foo, you'd need to use os.loadAPI("/foo/miner").
xBlizzDevious #8
Posted 11 February 2014 - 10:55 AM
Folder structure? os.loadAPI requires an absolute path relative to the computer's root folder, so if it isn't at /miner, it won't load it given that path. If you had it in a folder named foo, you'd need to use os.loadAPI("/foo/miner").

I was using it in the root folder and it wasn't working, so I moved my program to a folder called programs and my miner API to an apis folder then changed the os.loadAPI line in my program to os.loadAPI("../apis/miner") which also didn't work. If it always works from the root then that could explain that. I shall have to try that again.

One thing I'm not sure about though is which slash to use. In folder structure I've become used to using "\" whereas you're writing a "/".
Lyqyd #9
Posted 11 February 2014 - 12:36 PM
I don't think it matters in ComputerCraft, but it's generally better to stick with the forward slash, as resolved paths always use them. Again, the path to the API should be an absolute path, so "../apis/miner" won't work. In that case, it should be "/apis/miner".
xBlizzDevious #10
Posted 11 February 2014 - 01:36 PM
I don't think it matters in ComputerCraft, but it's generally better to stick with the forward slash, as resolved paths always use them. Again, the path to the API should be an absolute path, so "../apis/miner" won't work. In that case, it should be "/apis/miner".

Hmm. I think I must be doing something terribly obvious, remarkably wrong. I've tried this in every way that could make any sense and nothing works. Unless there's some config file somewhere switched off? I'm using FTB Monster if that could explain it.

Here's an updated version of my code (very mid-development) and the folder structure is:


root>ls
rom programs apis

The "betterMine" program is in programs folder and my "miner" API is in the apis folder.


betterMine:
Spoiler

os.loadAPI("/apis/miner")

function mineMenu()
  term.clear()
  term.setCursorPos(1,1)
  print("Please choose the type of")
  print("mine that you would like:")
  print("1. Hole")
  print("2. Tunnel")
  print("3. Branch Mine")
  print("4. Stairs")
  begin()
end

function begin()
  local userInput = read()
  if userInput == "1" then
	miner.holeMenu()
  elseif userInput == "2" then
	miner.tunnelMenu()
  elseif userInput == "3" then
	miner.branchMenu()
  elseif userInput == "4" then
	miner.stairsMenu()
  else
	print("That was an invalid selection")
	sleep(2)
	mineMenu()
  end
end

mineMenu()


miner:
Spoiler

local x = 0
local y = 0
local z = 0
local width = 0
local height = 0
local length = 0
local leftCount = 0
local rightCount = 0
local curDir = "forward"
local userInput = ""

function clearScreen()
	term.clear()
	term.setCursorPos(1,1)
end

function checkOdd()
	if (userInput % 2 == 0) then
		print("That is an even number.")
		print("Please input an ODD number:")
		userInput = read()
		checkOdd()
	else
		return
	end
end

function forward()
	if turtle.detect() == true then
		turtle.dig()
	end
	
	if turtle.detectUp() == true then
		turtle.digUp()
	end
	
	if turtle.detectDown() == true then
		turtle.digDown()
	end
	
	if turtle.forward() == true then
		addPath()
	else
		forward()
	end
end

function up()
	print("I'm not able to do that yet")
end

function down()
	print("I'm not able to do that yet")
end

function addPath()
	if curDir == "forward" then
		z = z + 1
	end
	
	if curDir == "back" then
		z = z - 1
	end
	
	if curDir == "right" then
		x = x + 1
	end
	
	if curDir == "left" then
		x = x - 1
	end
end

function holeMenu()
	clearScreen()
	print("You have chosen to dig a hole.")
	
	print("Please enter an odd number for width")
	userInput = read()
	checkOdd()
	width = userInput
	
	print("Please enter a number for the length")
	length = read()
	
	print("You have chosen to dig a "..width.." by "..length.." hole.")
	print("Is this correct (Y/N): ")
	local yesNo = read()
	if yesNo == "y" or yesNo == "Y" then
		hole()
	elseif yesNo == "n" or yesNo == "N" then
		holeMenu()
	else
		print("Invalid input - try again")
		sleep(2)
		holeMenu()
	end
end

function hole()
	print("Still constructing software...")
	break
end

function tunnelMenu()
	print("Tunnel menu still in construction")
	break
end

function tunnel()
	print("Still constructing software...")
	break
end

function branchMenu()
	print("Branch menu still in construction")
	break
end

function branch()
	print("Still constructing software...")
	break
end



When I run "betterMine from my programs folder, my menu appears and I can choose things correctly. If I choose "1" as it's the only thing that is at all implemented now, it will throw the following error:
"betterMine:18: attempt to index ? (a nil value)"

Which is the line that runs "miner.holeMenu()". I have no idea what's going on and would really like to figure it out. Thanks!
Edited on 11 February 2014 - 12:38 PM
CometWolf #11
Posted 11 February 2014 - 02:09 PM
Give this a try, and post what it prints

os.loadAPI"/apis/miner"
local amount = 0
for k,v in pairs(miner) do
  if type(v) == "function" then
    print(k)
    amount = amount+1
  end
end
print("Total functions: "..amount)
This should give you the name of all the functions in the miner api, provided it was loaded properly.
xBlizzDevious #12
Posted 11 February 2014 - 03:18 PM
Give this a try, and post what it prints

os.loadAPI"/apis/miner"
local amount = 0
for k,v in pairs(miner) do
  if type(v) == "function" then
	print(k)
	amount = amount+1
  end
end
print("Total functions: "..amount)
This should give you the name of all the functions in the miner api, provided it was loaded properly.

Well this is terribly odd…

I created a blank file called "apiTest" and then saved it and closed it. I opened the real file on my server and pasted in your code (I added in the brackets around the os.loadAPI bit) and then ran the function on my turtle. The following is what it showed:


programs> apiTest
API miner is already being loaded
apiTest:3: bad argument: table
expected, got nil

a) How on earth could it already be loading a custom made API?
B)/> How can it fail to get the functions of said API when it knows it's already there and loaded?
CometWolf #13
Posted 11 February 2014 - 03:29 PM
This is usually the result of a failed api load. Reboot the comp and or check your startup file. Also, the brackets aren't nessecary when passing a single string as the argument.
If that dosen't work, try just running the api from the shell.
xBlizzDevious #14
Posted 11 February 2014 - 04:00 PM
This is usually the result of a failed api load. Reboot the comp and or check your startup file. Also, the brackets aren't nessecary when passing a single string as the argument.
If that dosen't work, try just running the api from the shell.

I tried running my betterMine program again after restarting the computer and got the same error. I checked the startup program and it looks normal, nothing to do with my miner in there, just the normal APIs.

I then ran your program again and this time got a different error:


bios:339: [string "miner"]:103: no loop to break
apiTest:4: bad argument: table
expected, got nil

I'm assuming that the error in the second half is because the first bit is erroring out. The first one will be beacuse something of mine is not working, right? Something to do with a loop. I shall try removing my "break"s to see if it works with that!


EDIT: WHOOOOOOOP!!!!! I removed the "break"s I'd put into my temporary functions and ran your apiTest program and it works! Thank you, thank you, thank you!
Edited on 11 February 2014 - 03:04 PM
CometWolf #15
Posted 11 February 2014 - 04:29 PM
i did think those breaks were somewhat pointless, but i didn't think they'd cause an error so i didn't say anything. Great job figuring it out on your own :D/>
xBlizzDevious #16
Posted 11 February 2014 - 04:33 PM
i did think those breaks were somewhat pointless, but i didn't think they'd cause an error so i didn't say anything. Great job figuring it out on your own :D/>

Thanks! I'm now going to attempt to program the first mine which is a simple hole… This could turn into a disaster. But we shall see. I shall come back to this topic should I require more assistance.


EDIT: I have another quick question: what is the best way to detect when a turtle is full? Is it just to run a scan of how many items in the selected slot through a for loop for 16 once every so often or something? If so, how often would be most suitable?

If it would be best a different way, how would I go about that?

EDIT 2: Also, the same question as the last one basically, but substitute the inventory being full for refueling. When is best to refuel and what is the best way to check fuel usage and such?
Edited on 11 February 2014 - 05:41 PM
Bomb Bloke #17
Posted 11 February 2014 - 08:28 PM
EDIT: I have another quick question: what is the best way to detect when a turtle is full? Is it just to run a scan of how many items in the selected slot through a for loop for 16 once every so often or something? If so, how often would be most suitable?
That's pretty much it, yes. Make a basic function like so:

local function inventoryIsFull()  -- Returns true if the all slots in the turtle's inventory contain items.
	for i=1,16 do
		if turtle.getItemCount(i) == 0 then
			return false
		end
	end
	
	return true
end

As for "how often" to call it? Well, the frequency should be equal to how often you wish to know… Choose a time in the turtle's routine where it'd be convenient to break out and dump stuff, and check then.

if inventoryIsFull() then
	-- Code to go empty the turtle's inventory goes here.
end

EDIT 2: Also, the same question as the last one basically, but substitute the inventory being full for refueling. When is best to refuel and what is the best way to check fuel usage and such?
Again, choose a time that suits you. For example, if I made a turtle that dug layers of stuff downwards until it hit bedrock, I might have it check once every row it digs, or every layer it digs, or maybe just once before it started the whole project. Work out how much fuel it'll consume between each check, and if on any given check it has less then that amount, refuel.
Edited on 11 February 2014 - 07:28 PM
xBlizzDevious #18
Posted 11 February 2014 - 10:01 PM
EDIT: I have another quick question: what is the best way to detect when a turtle is full? Is it just to run a scan of how many items in the selected slot through a for loop for 16 once every so often or something? If so, how often would be most suitable?
That's pretty much it, yes. Make a basic function like so:

local function inventoryIsFull()  -- Returns true if the all slots in the turtle's inventory contain items.
	for i=1,16 do
		if turtle.getItemCount(i) == 0 then
			return false
		end
	end
	
	return true
end

As for "how often" to call it? Well, the frequency should be equal to how often you wish to know… Choose a time in the turtle's routine where it'd be convenient to break out and dump stuff, and check then.

if inventoryIsFull() then
	-- Code to go empty the turtle's inventory goes here.
end

EDIT 2: Also, the same question as the last one basically, but substitute the inventory being full for refueling. When is best to refuel and what is the best way to check fuel usage and such?
Again, choose a time that suits you. For example, if I made a turtle that dug layers of stuff downwards until it hit bedrock, I might have it check once every row it digs, or every layer it digs, or maybe just once before it started the whole project. Work out how much fuel it'll consume between each check, and if on any given check it has less then that amount, refuel.

Ok, thanks!

Next question…. I've come across a major bug and I really need to get to sleep so I'm posting this before I head to bed. When my turtle finishes a layer, it is supposed to work out the distance to the end of its path and then go down a certain number of layers, respectively. So, for example, if I tell the miner to dig a 5x3 hole 10 deep, it should check the distance between it's current "yCoord" and its intended height and then travel either 3 blocks down or one block down depending on whether the "toGo" distance is above 3 or not. I've told the miner to print the "toGo" variable and the "distance" variable just before it starts to dig down and they are both correct - 10 and 3 respectively - but for some reason, my miner just digs down as far as he can go.


Here's the latest version of each program:

betterMine:
Spoiler

os.loadAPI("/apis/miner")

function mineMenu()
  term.clear()
  term.setCursorPos(1,1)
  print("Please choose the type of")
  print("mine that you would like:")
  print("1. Hole")
  print("2. Tunnel")
  print("3. Branch Mine")
  print("4. Stairs")
  begin()
end

function begin()
  local userInput = read()
  if userInput == "1" then
	miner.holeMenu()
  elseif userInput == "2" then
	miner.tunnelMenu()
  elseif userInput == "3" then
	miner.branchMenu()
  elseif userInput == "4" then
	miner.stairsMenu()
  else
	print("That was an invalid selection")
	sleep(2)
	mineMenu()
  end
end

mineMenu()

miner:
Spoiler

local xCoord = 0
local yCoord = 0
local zCoord = 0
local distance = 0
local firstWidth = 0
local width = 0
local height = 0
local length = 0
local curDir = "forward"
local userInput = ""

function clearScreen()
	term.clear()
	term.setCursorPos(1,1)
end

function checkOdd()
	if (userInput % 2 == 0) then
		print("That is an even number.")
		print("Please input an ODD number:")
		userInput = read()
		checkOdd()
	else
		return
	end
end

function forward()
	if turtle.detect() == true then
		turtle.dig()
	end
	
	if turtle.detectUp() == true then
		turtle.digUp()
	end
	
	if turtle.detectDown() == true then
		turtle.digDown()
	end
	
	if turtle.forward() == true then
		addPath()
	else
		forward()
	end
end

function up()
	for i = 1, distance, 1 do
		if turtle.detectUp() == false then
			turtle.up()
			yCoord = yCoord + 1
		else
			turtle.digUp()
			up()
		end
	end
end

function down()
	for i = 1, distance, 1 do
		if turtle.detectDown() == false then
			turtle.down()
			yCoord = yCoord - 1
		else
			turtle.digDown()
			down()
		end
	end
	
end

function beginMine()
	if turtle.detect() == true then
		turtle.dig()
	end
	turtle.forward()
	turtle.turnLeft()
	curDir = "left"
end

function turnLeft()
	if turtle.turnLeft() == true then
		if curDir == "forward" then
			curDir = "left"
		elseif curDir == "left" then
			curDir = "back"
		elseif curDir == "back" then
			curDir = "right"
		elseif curDir == "right" then
			curDir = "forward"
		end
	end
end

function turnRight()
	if turtle.turnRight() == true then
		if curDir == "forward" then
			curDir = "right"
		elseif curDir == "left" then
			curDir = "forward"
		elseif curDir == "back" then
			curDir = "left"
		elseif curDir == "right" then
			curDir = "back"
		end
	end
end

function faceRight()
	if curDir == "forward" then
		turnRight()
		print("Facing right")
	elseif curDir == "right" then
		print("Facing right")
	elseif curDir == "back" then
		turnLeft()
		print("Facing right")
	elseif curDir == "left" then
		turnRight()
		turnRight()
		print("Facing right")
	end
end

function faceLeft()
	if curDir == "forward" then
		turnLeft()
		print("Facing left")
	elseif curDir == "right" then
		turnLeft()
		turnLeft()
		print("Facing left")
	elseif curDir == "back" then
		turnRight()
		print("Facing left")
	elseif curDir == "left" then
		print("Facing left")
	end
end

function faceForward()
	if curDir == "forward" then
		print("Facing forward")
	elseif curDir == "right" then
		turnLeft()
		print("Facing forward")
	elseif curDir == "back" then
		turnRight()
		turnRight()
		print("Facing forward")
	elseif curDir == "left" then
		turnRight()
		print("Facing forward")
	end
end

function faceBack()
	if curDir == "forward" then
		turnRight()
		turnRight()
		print("Facing back")
	elseif curDir == "right" then
		turnLeft()
		print("Facing back")
	elseif curDir == "back" then
		print("Facing back")
	elseif curDir == "left" then
		turnLeft()
		print("Facing left")
	end
end

function addPath()
	if curDir == "forward" then
		zCoord = zCoord + 1
	end
	
	if curDir == "back" then
		zCoord = zCoord - 1
	end
	
	if curDir == "right" then
		xCoord = xCoord + 1
	end
	
	if curDir == "left" then
		xCoord = xCoord - 1
	end
end

function returnPath()
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	if xCoord < 0 then
		faceRight()
		for i = 0, xCoord, -1 do
			forward()
		end
	elseif xCoord > 0 then
		faceLeft()
		for i = 0, xCoord, 1 do
			forward()
		end
	end
	
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	faceBack()
	if yCoord < 0 then
		for i = 0, yCoord, -1 do
			up()
		end
	elseif yCoord > 0 then
		for i = 0, yCoord, 1 do
			down()
		end
	end
end

function getFirstWidth()
	firstWidth = math.floor((width/2))
	print("The first width is: "..firstWidth)
end

function holeMenu()
	clearScreen()
	print("You have chosen to dig a hole.")
	
	print("Please enter an odd number for width:")
	userInput = read()
	checkOdd()
	width = userInput
	
	print("Please enter an odd number for length:")
	userInput = read()
	checkOdd()
	length = userInput
	
	print("Please enter how far down to go:")
	height = read()
	
	print("You have chosen to dig a "..width.." by "..length.." and")
	print(height.." deep hole. Is this correct (Y/N): ")
	local yesNo = read()
	if yesNo == "y" or yesNo == "Y" then
		hole()
	elseif yesNo == "n" or yesNo == "N" then
		holeMenu()
	else
		print("Invalid input - try again")
		sleep(2)
		holeMenu()
	end
end

function hole()
	beginMine()
	getFirstWidth()
	for i = 1, firstWidth, 1 do
		forward()
	end
	for i = 1, height, 1 do
		for j = 3, length, 2 do
			turnRight()
			forward()
			turnRight()
			for k = 2, width, 1 do
				forward()
			end
			turnLeft()
			forward()
			turnLeft()
			for k = 2, width, 1 do
				forward()
			end
		end
		local toGo = height - yCoord
		if toGo > 3 then
			distance = 3
		else
			distance = 1
		end
		print(toGo)
		print(distance)
		sleep(5)
		down()
	end
end

function tunnelMenu()
	print("Tunnel menu still in construction")
end

function tunnel()
	print("Still constructing software...")
end

function branchMenu()
	print("Branch menu still in construction")
end

function branch()
	print("Still constructing software...")
end
Edited on 11 February 2014 - 09:03 PM
Bomb Bloke #19
Posted 11 February 2014 - 10:13 PM
function down()
    for i = 1, distance, 1 do
        if turtle.detectDown() == false then
            turtle.down()
            yCoord = yCoord - 1
        else
            turtle.digDown()
            down()
        end
    end

end

When calling this function, it starts a loop. On each iteration, it'll check to see if a block is below the turtle, and if so, dig it out and then call the same function again.

This results in a new loop starting, and so on. Generally, having a function call itself is a bad idea.

Consider using something like this:

function down()
	for i = 1, distance do  -- If the "step" value isn't specified, it defaults to 1.
		if turtle.detectDown() then
			if not turtle.digDown() then  -- Equivalent to "if turtle.digDown() == false then".
				return  -- Turtle tried to dig something it couldn't; may've hit bedrock?
			end
		end

		while not turtle.down() do   -- Every call to "turtle.down()" not only attempts to move, but returns the result of that attempt.
			turtle.attackDown()  -- If an attempt failed, we may still be blocked by a mob...
			turtle.digDown()     -- ... or a natural cobble generator.
		end

		yCoord = yCoord - 1  -- This line can only be reached if the turtle succeeded in going down.
	end
end
xBlizzDevious #20
Posted 12 February 2014 - 07:00 AM
function down()
	for i = 1, distance, 1 do
		if turtle.detectDown() == false then
			turtle.down()
			yCoord = yCoord - 1
		else
			turtle.digDown()
			down()
		end
	end

end

When calling this function, it starts a loop. On each iteration, it'll check to see if a block is below the turtle, and if so, dig it out and then call the same function again.

This results in a new loop starting, and so on. Generally, having a function call itself is a bad idea.

Consider using something like this:

function down()
	for i = 1, distance do  -- If the "step" value isn't specified, it defaults to 1.
		if turtle.detectDown() then
			if not turtle.digDown() then  -- Equivalent to "if turtle.digDown() == false then".
				return  -- Turtle tried to dig something it couldn't; may've hit bedrock?
			end
		end

		while not turtle.down() do   -- Every call to "turtle.down()" not only attempts to move, but returns the result of that attempt.
			turtle.attackDown()  -- If an attempt failed, we may still be blocked by a mob...
			turtle.digDown()	 -- ... or a natural cobble generator.
		end

		yCoord = yCoord - 1  -- This line can only be reached if the turtle succeeded in going down.
	end
end

Ah of course! I should've realised. I've been copy and pasting too many functions that do the same thing in different directions. Then again, re-reading some of these functions, I feel I should've gone to bed a little earlier. Haha!

I was really struggling to think of an anti-bedrock system, but this just makes so much sense. Right, got that bit going well. Now to fix all the other bugs in this system. The main one being one that I realised it'd do and that was that it digs its layer and then heads forwards instead of back around on itself.





EDIT: Having some issues getting my miner to work properly. I totally re-programmed the way in which it mines to in theory make what I'm trying to do possible (the way it was, I don't think it would ever work right) but all I seem to have done now is turned my variables that are supposed to be numbers, into strings. I get the following error when I run the code. I'll comment where in the code.


miner:318: attempt to compare string
with number expected, got string

Spoiler

local xCoord = 0
local yCoord = 0
local zCoord = 0
local distance = 0
local firstWidth = 0
local width = 0
local height = 0
local length = 0
local curDir = "forward"
local userInput = ""

function clearScreen()
	term.clear()
	term.setCursorPos(1,1)
end

function checkOdd()
	if (userInput % 2 == 0) then
		print("That is an even number.")
		print("Please input an ODD number:")
		userInput = read()
		checkOdd()
	else
		return
	end
end

function forward()
	if turtle.detect() == true then
		turtle.dig()
	end
	
	if turtle.detectUp() == true then
		turtle.digUp()
	end
	
	if turtle.detectDown() == true then
		turtle.digDown()
	end
	
	if turtle.forward() == true then
		addPath()
	else
		forward()
	end
	clearScreen()
	print("X Difference: "..xCoord)
	print("Y Difference: "..yCoord)
	print("Z Difference: "..zCoord)
	print("Current fuel: "..turtle.getFuelLevel())
end

function up()
	for i = 1, distance do
		if turtle.detectUp() then
			if not turtle.digUp() then
			return
			end
		end
		while not turtle.up() do
			turtle.attackUp()
			turtle.digUp()
		end
	end
	yCoord = yCoord + 1
end

function down()
	for i = 1, distance do
		if turtle.detectDown() then
			if not turtle.digDown() then
				return
			end
		end
		while not turtle.down() do
			turtle.attackDown()
			turtle.digDown()
		end
	yCoord = yCoord - 1
	end
end

function beginMine()
	if turtle.detect() == true then
		turtle.dig()
	end
	turtle.forward()
	turnRight()
end

function turnLeft()
	if turtle.turnLeft() == true then
		if curDir == "forward" then
			curDir = "left"
		elseif curDir == "left" then
			curDir = "back"
		elseif curDir == "back" then
			curDir = "right"
		elseif curDir == "right" then
			curDir = "forward"
		end
	end
end

function turnRight()
	if turtle.turnRight() == true then
		if curDir == "forward" then
			curDir = "right"
		elseif curDir == "left" then
			curDir = "forward"
		elseif curDir == "back" then
			curDir = "left"
		elseif curDir == "right" then
			curDir = "back"
		end
	end
end

function faceRight()
	if curDir == "forward" then
		turnRight()
		print("Facing right")
	elseif curDir == "right" then
		print("Facing right")
	elseif curDir == "back" then
		turnLeft()
		print("Facing right")
	elseif curDir == "left" then
		turnRight()
		turnRight()
		print("Facing right")
	end
end

function faceLeft()
	if curDir == "forward" then
		turnLeft()
		print("Facing left")
	elseif curDir == "right" then
		turnLeft()
		turnLeft()
		print("Facing left")
	elseif curDir == "back" then
		turnRight()
		print("Facing left")
	elseif curDir == "left" then
		print("Facing left")
	end
end

function faceForward()
	if curDir == "forward" then
		print("Facing forward")
	elseif curDir == "right" then
		turnLeft()
		print("Facing forward")
	elseif curDir == "back" then
		turnRight()
		turnRight()
		print("Facing forward")
	elseif curDir == "left" then
		turnRight()
		print("Facing forward")
	end
end

function faceBack()
	if curDir == "forward" then
		turnRight()
		turnRight()
		print("Facing back")
	elseif curDir == "right" then
		turnLeft()
		print("Facing back")
	elseif curDir == "back" then
		print("Facing back")
	elseif curDir == "left" then
		turnLeft()
		print("Facing left")
	end
end

function addPath()
	if curDir == "forward" then
		zCoord = zCoord + 1
	end
	
	if curDir == "back" then
		zCoord = zCoord - 1
	end
	
	if curDir == "right" then
		xCoord = xCoord + 1
	end
	
	if curDir == "left" then
		xCoord = xCoord - 1
	end
end

function returnPath()
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	if xCoord < 0 then
		faceRight()
		for i = 0, xCoord, -1 do
			forward()
		end
	elseif xCoord > 0 then
		faceLeft()
		for i = 0, xCoord, 1 do
			forward()
		end
	end
	
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	faceBack()
	if yCoord < 0 then
		for i = 0, yCoord, -1 do
			up()
		end
	elseif yCoord > 0 then
		for i = 0, yCoord, 1 do
			down()
		end
	end
end

function getFirstWidth()
	firstWidth = math.floor((width/2))
	print("The first width is: "..firstWidth)
end

function holeMenu()
	clearScreen()
	print("You have chosen to dig a hole.")
	
	print("Please enter an odd number for width:")
	userInput = read()
	checkOdd()
	width = userInput
	
	print("Please enter an odd number for length:")
	userInput = read()
	checkOdd()
	length = userInput
	
	print("Please enter how far down to go:")
	height = read()
	
	print("You have chosen to dig a "..width.." by "..length.." and")
	print(height.." deep hole. Is this correct (Y/N): ")
	local yesNo = read()
	if yesNo == "y" or yesNo == "Y" then
		hole()
	elseif yesNo == "n" or yesNo == "N" then
		holeMenu()
	else
		print("Invalid input - try again")
		sleep(2)
		holeMenu()
	end
end

function turnMineRight()
	turnRight()
	forward()
	turnRight()
end

function turnMineLeft()
	turnLeft()
	forward()
	turnLeft()
end

function hole()
	beginMine()
	getFirstWidth()
	for i = 1, firstWidth do
		forward()
	end
	turnLeft()
	turnLeft()
	for i = 2, width do
		forward()
	end
	local toGo = height - yCoord
	if toGo > 3 then
		distance = 3
		inc = 3
	else
		distance = 1
		inc = 1
	end
	for i = 1, height, inc do
		while yCoord < length do		 -- This line is line 318 and both yCoord and length should be integers. At this point with length as 3 and yCoord should be 0
			if xCoord < 0 then
				turnMineRight()
			elseif xCoord > 0 then
				turnMineLeft()
			end
			for i = 2, width do
				forward()
			end
		end
		down()
		turnRight()
		turnRight()
	end
end

function tunnelMenu()
	print("Tunnel menu still in construction")
end

function tunnel()
	print("Still constructing software...")
end

function branchMenu()
	print("Branch menu still in construction")
end

function branch()
	print("Still constructing software...")
end




EDIT2: I ran the following code just before the error occurs and got the following results (after telling the program to mine a 5 x 3, 5 deep):


	print("Height: "..height) --5
	print("Width: "..width) --5
	print("Length: "..length) --3
	print("Distance: "..distance) --3
	print("Increment: "..inc) --3
	print("To Go: "..toGo) --5

Which is all correct and clearly all are integers. I'm confused!
Edited on 12 February 2014 - 04:00 PM
Bomb Bloke #21
Posted 12 February 2014 - 05:32 PM
Even if a string contains characters representing numerals, doesn't mean it's not a string!

You can actually query type directly - type(length) for eg will outright tell you if "length" is a number or a string or something else entirely.

In holeMenu, among similar chunks of code we have:

        print("Please enter an odd number for length:")
        userInput = read()
        checkOdd()
        length = userInput

"read()" always returns strings. Hence you may want something along these lines:

        print("Please enter an odd number for length:")
        userInput = tonumber(read())
        checkOdd()
        length = userInput

… or better yet:

        repeat
        	print("Please enter an odd number for length:")
        	length = tonumber(read())
        until length and (length % 2 == 1)

Just to throw you off, Lua will sometimes allow mathematical operations to be performed on strings which contain numeric values.

tonumber() returns nil if the value you pass it can't be represented as a number. For the purposes of conditional statements, variables set to nil count as false (or if set to any other value, they count as true).
Edited on 12 February 2014 - 04:33 PM
xBlizzDevious #22
Posted 12 February 2014 - 06:08 PM
Even if a string contains characters representing numerals, doesn't mean it's not a string!

You can actually query type directly - type(length) for eg will outright tell you if "length" is a number or a string or something else entirely.

In holeMenu, among similar chunks of code we have:

		print("Please enter an odd number for length:")
		userInput = read()
		checkOdd()
		length = userInput

"read()" always returns strings. Hence you may want something along these lines:

		print("Please enter an odd number for length:")
		userInput = tonumber(read())
		checkOdd()
		length = userInput

… or better yet:

		repeat
			print("Please enter an odd number for length:")
			length = tonumber(read())
		until length and (length % 2 == 1)

Just to throw you off, Lua will sometimes allow mathematical operations to be performed on strings which contain numeric values.

tonumber() returns nil if the value you pass it can't be represented as a number. For the purposes of conditional statements, variables set to nil count as false (or if set to any other value, they count as true).

Ah, that makes a lot more sense. I remember last year when I was writing my college project program, I had to use the function: toString() a lot. I think that was in either Java or C#.

Anyways, I'm using tonumber(read()) as the other way which is definitely better, will cause me to have to change the way other things work in the program and every time I do that, I break things. Haha. I'll maybe convert it sometime later though.

Now I've got to rethink my logic around how things should be mined as I've done something wrong in my mining bit which means that it just digs forward. I'm thinking it's something to do with my yCoord and the ordering of the functions I have. Don't be surprised if I come back here shortly when I can't figure it out.

Thanks for the help so far!


EDIT: Well what did I say… Hahaha! I changed some code and made it dig the first layer correctly, then move down correctly, then it turns round and digs down again. Which is completely wrong. I don't know what I'm doing wrong, but I've changed almost all of the mining code to work in a slightly different way and it has done the exact same thing every single time. Which means I'm other looking at the wrong bit, or I'm doing the same thing wrong 5 different ways. Here's the latest version of my miner API:

Spoiler

local xCoord = 0
local yCoord = 0
local zCoord = 0
local distance = 0
local firstWidth = 0
local width = 0
local height = 0
local length = 0
local heightOpp = 0
local curDir = "forward"
local userInput = ""

function clearScreen()
	term.clear()
	term.setCursorPos(1,1)
end

function printVariables()
	clearScreen()
	print("Currently digging a "..width.." by "..length.." hole")
	print("Mining down "..heightOpp.." blocks")
	print("X Difference: "..xCoord)
	print("Y Difference: "..yCoord)
	print("Z Difference: "..zCoord)
	print("Current fuel: "..turtle.getFuelLevel())
end

function checkOdd()
	if (userInput % 2 == 0) then
		print("That is an even number.")
		print("Please input an ODD number:")
		userInput = tonumber(read())
		checkOdd()
	else
		return
	end
end

function forward()
	if turtle.detect() == true then
		turtle.dig()
	end
	
	if turtle.detectUp() == true then
		turtle.digUp()
	end
	
	if turtle.detectDown() == true then
		turtle.digDown()
	end
	
	if turtle.forward() == true then
		addPath()
	else
		forward()
	end
	printVariables()
end

function up()
	if turtle.detectUp() then
		if not turtle.digUp() then
			return
		end
	end
	while not turtle.up() do
		turtle.attackUp()
		turtle.digUp()
	end
	yCoord = yCoord + 1
end

function down()
	if turtle.detectDown() then
		if not turtle.digDown() then
			return
		end
	end
	while not turtle.down() do
		turtle.attackDown()
		turtle.digDown()
	end
	yCoord = yCoord - 1
end

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

function turnLeft()
	if turtle.turnLeft() == true then
		if curDir == "forward" then
			curDir = "left"
		elseif curDir == "left" then
			curDir = "back"
		elseif curDir == "back" then
			curDir = "right"
		elseif curDir == "right" then
			curDir = "forward"
		end
	end
end

function turnRight()
	if turtle.turnRight() == true then
		if curDir == "forward" then
			curDir = "right"
		elseif curDir == "left" then
			curDir = "forward"
		elseif curDir == "back" then
			curDir = "left"
		elseif curDir == "right" then
			curDir = "back"
		end
	end
end

function faceRight()
	if curDir == "forward" then
		turnRight()
		print("Facing right")
	elseif curDir == "right" then
		print("Facing right")
	elseif curDir == "back" then
		turnLeft()
		print("Facing right")
	elseif curDir == "left" then
		turnRight()
		turnRight()
		print("Facing right")
	end
end

function faceLeft()
	if curDir == "forward" then
		turnLeft()
		print("Facing left")
	elseif curDir == "right" then
		turnLeft()
		turnLeft()
		print("Facing left")
	elseif curDir == "back" then
		turnRight()
		print("Facing left")
	elseif curDir == "left" then
		print("Facing left")
	end
end

function faceForward()
	if curDir == "forward" then
		print("Facing forward")
	elseif curDir == "right" then
		turnLeft()
		print("Facing forward")
	elseif curDir == "back" then
		turnRight()
		turnRight()
		print("Facing forward")
	elseif curDir == "left" then
		turnRight()
		print("Facing forward")
	end
end

function faceBack()
	if curDir == "forward" then
		turnRight()
		turnRight()
		print("Facing back")
	elseif curDir == "right" then
		turnLeft()
		print("Facing back")
	elseif curDir == "back" then
		print("Facing back")
	elseif curDir == "left" then
		turnLeft()
		print("Facing left")
	end
end

function addPath()
	if curDir == "forward" then
		zCoord = zCoord + 1
	end
	
	if curDir == "back" then
		zCoord = zCoord - 1
	end
	
	if curDir == "right" then
		xCoord = xCoord + 1
	end
	
	if curDir == "left" then
		xCoord = xCoord - 1
	end
end

function returnPath()
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	if xCoord < 0 then
		faceRight()
		for i = 0, xCoord, -1 do
			forward()
		end
	elseif xCoord > 0 then
		faceLeft()
		for i = 0, xCoord, 1 do
			forward()
		end
	end
	
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	faceBack()
	if yCoord < 0 then
		for i = 0, yCoord, -1 do
			up()
		end
	elseif yCoord > 0 then
		for i = 0, yCoord, 1 do
			down()
		end
	end
end

function getFirstWidth()
	firstWidth = math.floor((width/2))
	print("The first width is: "..firstWidth)
end

function holeMenu()
	clearScreen()
	print("You have chosen to dig a hole.")
	
	print("Please enter an odd number for width:")
	userInput = tonumber(read())
	checkOdd()
	width = userInput
	
	print("Please enter an odd number for length:")
	userInput = tonumber(read())
	checkOdd()
	length = userInput
	
	print("Please enter how far down to go:")
	height = tonumber(read())
	heightOpp = height * (0-1)
	
	print("You have chosen to dig a "..width.." by "..length.." and")
	print(height.." deep hole. Is this correct (Y/N): ")
	local yesNo = read()
	if yesNo == "y" or yesNo == "Y" then
		hole()
	elseif yesNo == "n" or yesNo == "N" then
		holeMenu()
	else
		print("Invalid input - try again")
		sleep(2)
		holeMenu()
	end
end

function turnMineRight()
	turnRight()
	forward()
	turnRight()
end

function turnMineLeft()
	turnLeft()
	forward()
	turnLeft()
end

function hole()
	beginMine()
	getFirstWidth()
	for i = 1, firstWidth do
		forward()
	end
	turnLeft()
	turnLeft()
	for i = 2, width do
		forward()
	end
	local toGo = 0
	if toGo > 3 then
		distance = 3
		inc = 3
	else
		distance = 1
		inc = 1
	end
	for i = 1, height, inc do
		toGo = height - yCoord
		if toGo > 3 then
			distance = 3
			inc = 3
		else
			distance = 1
			inc = 1
		end
		while zCoord < length do   --This line is causing it, I think
			if xCoord < 0 then
				turnMineRight()
			elseif xCoord > 0 then
				turnMineLeft()
			end
			for j = 2, width do
				forward()
			end
		end
		turnRight()
		turnRight()
		for j = 1, distance do
			down()
		end
		distance = 0
	end
end

function tunnelMenu()
	print("Tunnel menu still in construction")
end

function tunnel()
	print("Still constructing software...")
end

function branchMenu()
	print("Branch menu still in construction")
end

function branch()
	print("Still constructing software...")
end


EDIT2: Just figured out what it is. Or at least I think I have… I've commented the line in question above.
How would I go about avoiding that? I'm really struggling with the actual mining system here as it's nowhere near as simple as I thought it would be or at least, I can't figure out a simple way.

All I'm wanting to do is mine a layer, then go down and mine another layer, then repeat until it's dug all the way down to the specified height. Also, when debugging this, I was thinking that my Y coordinate wasn't changing and that that was the issue, however I've just realised that that's because I don't update the screen when I move up or down. I'm about to add my printVariables() function to both of those.

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?
Edited on 12 February 2014 - 07:35 PM
xBlizzDevious #23
Posted 13 February 2014 - 09:47 AM
I've edited my hole function a bit to try and correct my mining issues… I seem to have done something, but for some reason, when my turtle has finished digging out the first layer, it turns round correctly, then digs down one, then turns to the right again. I cannot figure out why. In theory, it's not getting to any function which runs a turn command until it's gone down 3. Here is my current code:

Spoiler

function hole()
    beginMine()
    getFirstWidth()
    for i = 1, firstWidth do
        forward()
    end
    turnLeft()
    turnLeft()
    for i = 2, width do
        forward()
    end
    
    local toGo = 0
    local inc = 0
    if toGo > 3 then
        distance = 3
        inc = 3
    else
        distance = 1
        inc = 1
    end
    
    for i = 1, height, inc do
        for j = 2, length do
            if xCoord < 0 and curDir == "left" then
                if zCoord == length then
                    turnMineLeft()
                else
                    turnMineRight()
                end
            elseif xCoord < 0 and curDir == "right" then
                if zCoord == length then
                    turnMineRight()
                else
                    turnMineLeft()
                end
            elseif xCoord > 0 and curDir == "right" then
                if zCoord == length then
                    turnMineRight()
                else
                    turnMineLeft()
                end
            elseif xCoord > 0 and curDir == "left" then
                if zCoord == length then
                    turnMineLeft()
                else
                    turnMineRight()
                end
            else
                print("I don't know what to do!")
                return
            end
            for k = 2, width do
                forward()
            end
        end
        turnRight()
        turnRight()
        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
        distance = 0
    end
end

Any ideas? And am I going in completely the wrong direction with this (code-wise, not turtle directions)?
Bomb Bloke #24
Posted 13 February 2014 - 07:58 PM
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.
xBlizzDevious #25
Posted 14 February 2014 - 10:11 AM
-snip-
(Really long post)

Thanks for all this help. It makes a bit more sense now. And not only that, I've managed to get my turtle to dig the first two or 3 layers correctly now. However, to make it work the way I'm planning so far, I need to do a repeat loop until one of two statements is true. ie.

repeat
	--Some code
until zCoord == 1 or zCoord == length

How would I go about making that work as I just get the "unexpected symbol" error with "or" in that line. What's the alternative?

EDIT: Thought of a workaround! I ran an if statement at the end and set a variable to true or false that is then used in the "until" line. MY MINER WORKS!!!!! To an extent…
Edited on 14 February 2014 - 09:35 AM
Bomb Bloke #26
Posted 14 February 2014 - 11:17 AM
It sounds like it's taking this:

until zCoord == 1 or zCoord == length

… to mean this:

until zCoord == (1 or zCoord) == length

… which isn't valid. Don't see why it'd do that, but you should also be able to avoid it by specifically coding it as this:

until (zCoord == 1) or (zCoord == length)
Lyqyd #27
Posted 14 February 2014 - 12:23 PM
It wouldn't do that unless there is a bug in LuaJ with until statements (doubtful); Lua's order of operations specifically prevents that. There might be a case wherein the code we're seeing isn't the actual code that wasn't working in the program.
xBlizzDevious #28
Posted 14 February 2014 - 12:56 PM
It sounds like it's taking this:

until zCoord == 1 or zCoord == length

… to mean this:

until zCoord == (1 or zCoord) == length

… which isn't valid. Don't see why it'd do that, but you should also be able to avoid it by specifically coding it as this:

until (zCoord == 1) or (zCoord == length)

That does seem odd. Well putting them into brackets works so thanks for that.

The other day, I tried to access the excavate file from within the turtle but I couldn't find it. So today I decided I'd have a look in the CC Jar file and found the file so I had a look through it, and it makes it seem so simple to do the same thing. I didn't really follow the entirety of the program, but it uses some ways of defining variables that I didn't know you could, and he's passing variables around a lot too.

I'm just working on my return path system and a fuelling system, along with anti-over-filled-inventory system. Not really sure what the best way to fuel the thing would be, but I'm thinking of using a system to calculate fuel costs but I'm not entirely sure on what they are.

Could you specify exactly which commands use fuel and how much fuel they use?

Next question - mainly for debugging purposes - is it possible to have a command to pause the current action, whatever it's doing and then input another command (from the list of functions the turtle can do) more easily tell it to do things.
ie, it's mid-mine and I want to tell it to return to the surface and refuel, I could press "S" or something to stop it and then type returnPath() to run my returnPath function. Is that possible?

It wouldn't do that unless there is a bug in LuaJ with until statements (doubtful); Lua's order of operations specifically prevents that. There might be a case wherein the code we're seeing isn't the actual code that wasn't working in the program.

I've changed the code now, but I'm almost 100% sure that it was written exactly as stated above and it was not allowing me to run the API. If I used the apiTest function (that I think CometWolf got me to use - that's so handy by the way) it told me that there was an error on line 407 with an unexpected symbol. Line 407 was the "until" line.



EDIT: Another question: how would I go about making the turtle go down one instead of three when it is near the intended depth so that it will end up on the correct level and properly finish? My random code that I think should have worked in some other languages that doesn't work in this was about the only way I think it'd really have made sense.
Edited on 14 February 2014 - 12:09 PM
Lyqyd #29
Posted 14 February 2014 - 01:10 PM
The up, down, forward and back turtle movements use one fuel point each time they are successfully executed.

The error may have been caused by a malformed or incomplete statement on the line before the until.
Bomb Bloke #30
Posted 14 February 2014 - 06:42 PM
Next question - mainly for debugging purposes - is it possible to have a command to pause the current action, whatever it's doing and then input another command (from the list of functions the turtle can do) more easily tell it to do things.
ie, it's mid-mine and I want to tell it to return to the surface and refuel, I could press "S" or something to stop it and then type returnPath() to run my returnPath function. Is that possible?
Yeah, but because getting the turtle to respond to keyboard input involves having it listen for related events, and most turtle-action commands cause all other events to be discarded, it's a bit of a process…

The idea is that you define a function that handles all the "turtle work" - eg, your "hole()" function - and another one that does nothing but sit there waiting for user input. You then pass both of these functions to the parallel API, which runs 'em both side by side for you and makes sure each gets a copy of all events - each function can then pull what they like from their copy of the event queue without worrying about what the other sees.

For example, this thread has a bit of a discussion on the matter, and an example at the bottom as to how to deal with it.

EDIT: Another question: how would I go about making the turtle go down one instead of three when it is near the intended depth so that it will end up on the correct level and properly finish? My random code that I think should have worked in some other languages that doesn't work in this was about the only way I think it'd really have made sense.
Your earlier code likely handled this correctly, but you later kinda mangled your "distance" calculating code, and I haven't seen it since I pointed out that it needed correction. What's that segment look like now?
xBlizzDevious #31
Posted 14 February 2014 - 08:14 PM
Next question - mainly for debugging purposes - is it possible to have a command to pause the current action, whatever it's doing and then input another command (from the list of functions the turtle can do) more easily tell it to do things.
ie, it's mid-mine and I want to tell it to return to the surface and refuel, I could press "S" or something to stop it and then type returnPath() to run my returnPath function. Is that possible?
Yeah, but because getting the turtle to respond to keyboard input involves having it listen for related events, and most turtle-action commands cause all other events to be discarded, it's a bit of a process…

The idea is that you define a function that handles all the "turtle work" - eg, your "hole()" function - and another one that does nothing but sit there waiting for user input. You then pass both of these functions to the parallel API, which runs 'em both side by side for you and makes sure each gets a copy of all events - each function can then pull what they like from their copy of the event queue without worrying about what the other sees.

For example, this thread has a bit of a discussion on the matter, and an example at the bottom as to how to deal with it.

EDIT: Another question: how would I go about making the turtle go down one instead of three when it is near the intended depth so that it will end up on the correct level and properly finish? My random code that I think should have worked in some other languages that doesn't work in this was about the only way I think it'd really have made sense.
Your earlier code likely handled this correctly, but you later kinda mangled your "distance" calculating code, and I haven't seen it since I pointed out that it needed correction. What's that segment look like now?

The parallel API sounds like it could be a nightmare. Not looked at the link yet but will maybe check it out later.

Code-wise, I've changed a LOT of code since and I can't really remember what was where and where it's gone. Here's the whole lot in its current form. I'm currently getting an error on line 323 saying that there is a "then" expected. Also, I've started commenting some of my code since I keep posting back here. Haha.


Spoiler

function setVars()
    xCoord = 0
    yCoord = 0
    zCoord = 0
    headForward = true
    distance = 0
    firstWidth = 0
    width = 0
    height = 0
    length = 0
    heightOpp = 0
    curDir = "forward"
    userInput = ""
    wasX = 0
    wasY = 0
    wasZ = 0
    wasDir = ""
    estFuel = 0
end

function clearScreen()
    term.clear()
    term.setCursorPos(1,1)
end

function printVariables()
    clearScreen()
    print("Currently digging a "..width.." by "..length.." hole")
    print("Mining down "..heightOpp.." blocks")
    print("X Difference: "..xCoord)
    print("Y Difference: "..yCoord)
    print("Z Difference: "..zCoord)
    print("Current Direction: "..curDir)
    print("Current fuel: "..turtle.getFuelLevel())
end

function checkOdd()
    if (userInput % 2 == 0) then
        print("That is an even number.")
        print("Please input an ODD number:")
        userInput = tonumber(read())
        checkOdd()
    else
        return
    end
end

function forward()
    if turtle.detect() == true then
        turtle.dig()
    end
    
    if turtle.detectUp() == true then
        turtle.digUp()
    end
    
    if turtle.detectDown() == true then
        turtle.digDown()
    end
    
    if turtle.forward() == true then
        addPath()
    else
        forward()
    end
    checkFuelLoop()
    checkInvLoop()
end

function up()
    if turtle.detectUp() then
        if not turtle.digUp() then
            return
        end
    end
    while not turtle.up() do
        turtle.attackUp()
        turtle.digUp()
    end
    yCoord = yCoord + 1
    printVariables()
    checkFuelLoop()
    checkInvLoop()
end

function down()
    if turtle.detectUp() then
        turtle.digUp()
    end
    if turtle.detectDown() then
        if not turtle.digDown() then
            return
        end
    end
    while not turtle.down() do
        turtle.attackDown()
        turtle.digDown()
    end
    yCoord = yCoord - 1
    printVariables()
    checkFuelLoop()
    checkInvLoop()
end

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()
    headForward = true
end

function turnLeft()
    if turtle.turnLeft() == true then
        if curDir == "forward" then
            curDir = "left"
        elseif curDir == "left" then
            curDir = "back"
        elseif curDir == "back" then
            curDir = "right"
        elseif curDir == "right" then
            curDir = "forward"
        end
    end
end

function turnRight()
    if turtle.turnRight() == true then
        if curDir == "forward" then
            curDir = "right"
        elseif curDir == "left" then
            curDir = "forward"
        elseif curDir == "back" then
            curDir = "left"
        elseif curDir == "right" then
            curDir = "back"
        end
    end
end

function faceRight()
    if curDir == "forward" then
        turnRight()
        print("Facing right")
    elseif curDir == "right" then
        print("Facing right")
    elseif curDir == "back" then
        turnLeft()
        print("Facing right")
    elseif curDir == "left" then
        turnRight()
        turnRight()
        print("Facing right")
    end
end

function faceLeft()
    if curDir == "forward" then
        turnLeft()
        print("Facing left")
    elseif curDir == "right" then
        turnLeft()
        turnLeft()
        print("Facing left")
    elseif curDir == "back" then
        turnRight()
        print("Facing left")
    elseif curDir == "left" then
        print("Facing left")
    end
end

function faceForward()
    if curDir == "forward" then
        print("Facing forward")
    elseif curDir == "right" then
        turnLeft()
        print("Facing forward")
    elseif curDir == "back" then
        turnRight()
        turnRight()
        print("Facing forward")
    elseif curDir == "left" then
        turnRight()
        print("Facing forward")
    end
end

function faceBack()
    if curDir == "forward" then
        turnRight()
        turnRight()
        print("Facing back")
    elseif curDir == "right" then
        turnLeft()
        print("Facing back")
    elseif curDir == "back" then
        print("Facing back")
    elseif curDir == "left" then
        turnLeft()
        print("Facing left")
    end
end

function addPath()
    if curDir == "forward" then
        zCoord = zCoord + 1
    end
    
    if curDir == "back" then
        zCoord = zCoord - 1
    end
    
    if curDir == "right" then
        xCoord = xCoord + 1
    end
    
    if curDir == "left" then
        xCoord = xCoord - 1
    end
end

function returnPath()
    wasX = xCoord
    wasY = yCoord
    wasZ = zCoord
    wasDir = curDir
    
    if yCoord < 0 then
        for i = 0, yCoord, -1 do
            up()
        end
    elseif yCoord > 0 then
        for i = 0, yCoord, 1 do
            down()
        end
    end
    
    if xCoord < 0 then
        faceRight()
        for i = 0, xCoord, -1 do
            forward()
        end
    elseif xCoord > 0 then
        faceLeft()
        for i = 0, xCoord, 1 do
            forward()
        end
    end
    
    if zCoord < 0 then
        faceForward()
        for i = 0, zCoord, -1 do
            forward()
        end
    elseif zCoord > 0 then
        faceBack()
        for i = 0, zCoord, 1 do
            forward()
        end
    end
    
    faceBack()
    turtle.forward()
end

function goBack()
    faceForward()
    turtle.forward()
    zCoord = 1
    if wasY < 0 then
        for i = 0, wasY, -1 do
            down()()
        end
    elseif wasY > 0 then
        for i = 0, wasY, 1 do
            up()
        end
    end
    
    if wasX < 0 then
        faceLeft()
        for i = 0, wasX, -1 do
            forward()
        end
    elseif wasX > 0 then
        faceRight()
        for i = 0, wasX, 1 do
            forward()
        end
    end
    
    if wasZ < 0 then
        faceBack()
        for i = 0, wasZ, -1 do
            forward()
        end
    elseif wasZ > 0 then
        faceForward()
        for i = 0, wasZ, 1 do
            forward()
        end
    end
    
    if wasDir == "forward" then    --Face previous direction
        faceForward()
    elseif wasDir == "right" then
        faceRight()
    elseif wasDir == "left" then
        faceLeft()
    elseif wasDir == "back" then
        faceBack()
    end
    
    if zCoord != wasZ then    --Check that we got back to the right location	  ****This is line 323****
        print("Did not get back to the correct Z point")
    end
    if xCoord != wasX then
        print("Did not get back to the correct X point")
    end
    if yCoord != wasY then
        print("Did not get back to the correct Y point")
    end
    sleep(10)
end

function getFirstWidth()
    firstWidth = math.floor((width/2))
    print("The first width is: "..firstWidth)
end

function turnMineRight()
    turnRight()
    forward()
    turnRight()
end

function turnMineLeft()
    turnLeft()
    forward()
    turnLeft()
end

function checkInvFull()
    local invCount = 0
    for i = 1, 16 do
        if turtle.getItemCount(i) > 0 then
            invCount = invCount + 1
        end
    end
    if invCount == 16 then
        return true
    else
        return false
    end
end

function emptyInv()
    faceBack()
    for i = 2, 16 do
        turtle.select(i)
        while not turtle.drop() do
            print("Either there's no chest or it's full")
        end
    end
    faceForward()
end

function refuel()
    faceLeft()
    for i = 1, 16 do
        turtle.select(i)
        if turtle.refuel(0) then
            while turtle.getFuelLevel < (estimateFuel() * 1.1) do
                if i == 1 then
                    turtle.refuel((turtle.getItemCount()-1))
                else
                    turtle.refuel()
                end
            end
        end
    end
    faceForward()
end

function estimateFuel()
    estFuel = math.ceil((width * length) * (height / 2.8))
    return estFuel
end

function checkInvLoop()
    if checkInvFull() then
        returnPath()
        emptyInv()
        goBack()
    end
end
    
function checkFuelLoop()
    if turtle.getFuelLevel() < 500 then
        returnPath()
        refuel()
        goBack()
    end
end

function holeMenu()
    setVars()
    
    clearScreen()
    print("You have chosen to dig a hole.")
    
    print("Please enter an odd number for width:")
    userInput = tonumber(read())
    checkOdd()
    width = userInput
    
    print("Please enter an odd number for length:")
    userInput = tonumber(read())
    checkOdd()
    length = userInput
    
    print("Please enter how far down to go:")
    height = tonumber(read())
    heightOpp = height * (0-1)
    
    print("You have chosen to dig a "..width.." by "..length.." and")
    print(height.." deep hole. This will consume an ")
    print("estimated "..estimateFuel().." units of fuel")
    print("Is this OK? (Y/N): ")
    local yesNo = read()
    if yesNo == "y" or yesNo == "Y" then
        hole()
    elseif yesNo == "n" or yesNo == "N" then
        holeMenu()
    else
        print("Invalid input - try again")
        sleep(2)
        holeMenu()
    end
end


function hole()
    while estimateFuel() > turtle.getFuelLevel() do    --Check fuel level and refuel if need be
        clearScreen()
        print("I estimate that I will use more fuel than I have")
        print("Refuelling...")
        faceLeft()
        while not turtle.suck() do
            print("I need a fuel chest to my left")
            sleep(5)
        end
        while not refuel() do
            print("I can't refuel with current inventory.")
            print("Please provide me with a fuel chest.")
            sleep(5)
        end
    end
    faceForward()

    beginMine()    --Get into position to mine
    getFirstWidth()    --Calculate half of overall width so that you can start mining from the middle
    for i = 1, firstWidth do    --Dig out the first layer of the right side
        forward()
    end
    turnLeft()    --Turn right around and dig the rest of the first layer
    turnLeft()
    for i = 2, width do
        forward()
    end
--[[
    for i = 2, length do    --Dig first layer of the mine
        if xCoord < 0 and curDir == "left" then
            if zCoord == length then
                turnMineLeft()
            else
                turnMineRight()
            end
        elseif xCoord < 0 and curDir == "right" then
            if zCoord == length then
                turnMineRight()
            else
                turnMineLeft()
            end
        elseif xCoord > 0 and curDir == "right" then
            if zCoord == length then
                turnMineRight()
            else
                turnMineLeft()
            end
        elseif xCoord > 0 and curDir == "left" then
            if zCoord == length then
                turnMineLeft()
            else
                turnMineRight()
            end
        else
            print("I don't know what to do!")
            return
        end
        for j = 2, width do
            forward()
        end
    end
    turnRight()    --Turn turtle around and dig down
    turnRight()
    for i = 1, 3 do
        down()
    end
    headForward = false
    for i = 2, width do
        forward()
    end
    ]]--
    --    ^^    Is the first layer specific function required anymore?
    -- Above comment is not a question to you, it's notes for me.
    repeat    --Dig remaining layers
        repeat
            if headForward == false and xCoord > 0 then
                turnMineRight()
            elseif headForward == false and xCoord < 0 then
                turnMineLeft()
            elseif headForward == true and xCoord > 0 then
                turnMineLeft()
            elseif headForward == true and xCoord < 0 then
                turnMineRight()
            end
            for i = 2, width do
                forward()
            end
        until (zCoord == 1) or (zCoord == length)
        turnRight()    --Turn turtle around and dig down
        turnRight()
        for i = 1, 3 do
            down()
        end
        if zCoord == 1 then
            headForward = true
        elseif zCoord == length then
            headForward = false
        end
        for i = 2, width do
            forward()
        end
    until yCoord == heightOpp + 1
    repeat    --Once reached final layer, finish digging that layer before stopping
        if headForward == false and xCoord > 0 then
            turnMineRight()
        elseif headForward == false and xCoord < 0 then
            turnMineLeft()
        elseif headForward == true and xCoord > 0 then
            turnMineLeft()
        elseif headForward == true and xCoord < 0 then
            turnMineRight()
        end
        for i = 2, width do
            forward()
        end
    until zCoord == length
    clearScreen()    --Clear screen, print information
    print("I think I've finished mining!")
    print("Returning home now...")
    returnPath()
    print("I'm home")
    emptyInv()
end

function tunnelMenu()
    print("Tunnel menu still in construction")
end

function tunnel()
    print("Still constructing software...")
end

function branchMenu()
    print("Branch menu still in construction")
end

function branch()
    print("Still constructing software...")
end
Bomb Bloke #32
Posted 15 February 2014 - 02:10 AM
The parallel API sounds like it could be a nightmare. Not looked at the link yet but will maybe check it out later.
It's actually fairly simple to use, even if the knowledge as to why you'd use it and what it actually does is rather in-depth. You'd want to look more into events first, I guess.

Code-wise, I've changed a LOT of code since and I can't really remember what was where and where it's gone. Here's the whole lot in its current form. I'm currently getting an error on line 323 saying that there is a "then" expected. Also, I've started commenting some of my code since I keep posting back here. Haha.
323 is using "!=" to represent "is not" - you're wanting "~=" there and throughout the next few lines.

Your descending code has been simplified a tad since I last saw it; around line 543 we've now got:

        for i = 1, 3 do
            down()
        end

Previously you were using a "distance" variable, which was either set to 1 or 3 depending on whether you were near the bottom or not.

This is really where ternarys come in handy. Lua doesn't have one, but it's possible to rig up something fairly similar so that may as well be used here.

Let's say that if we can go down three without exceeding our max depth, we'll do that, otherwise we'll go down whatever amount would bring us to the max depth.

One way to write it would be similar to what you were doing before:

        if heightOpp + 3 < yCoord
        	distance = 3
        else
        	distance = yCoord - heightOpp - 1
        end

        for i = 1, distance do
            down()
        end

Using the technique in the link, this can be reduced:

        for i = 1, (heightOpp + 3 < yCoord and 3 or yCoord - heightOpp - 1) do
            down()
        end

That'd make it go down either 3, 2 or 1 levels. If you specifically want it to either go 3 or 1 (but never 2), you'd just use:

        for i = 1, (heightOpp + 3 < yCoord and 3 or 1) do
            down()
        end
xBlizzDevious #33
Posted 15 February 2014 - 05:34 PM
-snip-

I'm not really sure about that ternary thing and how it works, but what you've said works perfectly (for doing 3s, anyway, haven't managed to get to the bottom of a mineshaft yet)!

When emptying out its inventory, my turtle was doing some baffling things, for example, he was heading to the correct location, emptying his inventory and then turning around and going back one block, then returning to just in front of the chest, then mining through it for a few blocks. So I looked at my code and then realised that I could change the way it turns around. I've also not figured out the problem with it not heading back properly. Anyways, as you'll see by my "faceXXXX" functions, I've changed them a lot, however, now he just spins around constantly and makes me think of the song "You spin me right round" by Dead or Alive… Haha! So I thought of adding the "tostring" function in to see if that was the issue, but no. I have no idea why that's not working at all.

Here's the code:
Spoiler

function setVars()
	xCoord = 0
	yCoord = 0
	zCoord = 0
	headForward = true
	distance = 0
	firstWidth = 0
	width = 0
	height = 0
	length = 0
	heightOpp = 0
	curDir = "forward"
	userInput = ""
	wasX = 0
	wasY = 0
	wasZ = 0
	wasDir = ""
	estFuel = 0
end

function clearScreen()
	term.clear()
	term.setCursorPos(1,1)
end

function printVariables()
	clearScreen()
	print("Currently digging a "..width.." by "..length.." hole")
	print("Mining down "..heightOpp.." blocks")
	print("X Difference: "..xCoord)
	print("Y Difference: "..yCoord)
	print("Z Difference: "..zCoord)
	print("Current Direction: "..curDir)
	print("Current fuel: "..turtle.getFuelLevel())
end

function checkOdd()
	if (userInput % 2 == 0) then
		print("That is an even number.")
		print("Please input an ODD number:")
		userInput = tonumber(read())
		checkOdd()
	else
		return
	end
end

function forward()
	if turtle.detect() == true then
		turtle.dig()
	end
	
	if turtle.detectUp() == true then
		turtle.digUp()
	end
	
	if turtle.detectDown() == true then
		turtle.digDown()
	end
	
	if turtle.forward() == true then
		addPath()
	else
		forward()
	end
	printVariables()
	checkFuelLoop()
	checkInvLoop()
end

function up()
	if turtle.detectUp() then
		if not turtle.digUp() then
			return
		end
	end
	while not turtle.up() do
		turtle.attackUp()
		turtle.digUp()
	end
	yCoord = yCoord + 1
	printVariables()
	checkFuelLoop()
	checkInvLoop()
end

function down()
	if turtle.detectUp() then
		turtle.digUp()
	end
	if turtle.detectDown() then
		if not turtle.digDown() then
			return
		end
	end
	while not turtle.down() do
		turtle.attackDown()
		turtle.digDown()
	end
	yCoord = yCoord - 1
	printVariables()
	checkFuelLoop()
	checkInvLoop()
end

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()
	headForward = true
end

function turnLeft()
	if turtle.turnLeft() == true then
		if curDir == "forward" then
			curDir = "left"
		elseif curDir == "left" then
			curDir = "back"
		elseif curDir == "back" then
			curDir = "right"
		elseif curDir == "right" then
			curDir = "forward"
		end
	end
end

function turnRight()
	if turtle.turnRight() then
		if curDir == "forward" then
			curDir = "right"
		elseif curDir == "left" then
			curDir = "forward"
		elseif curDir == "back" then
			curDir = "left"
		elseif curDir == "right" then
			curDir = "back"
		end
	end
end

function faceRight()
	while tostring(curDir) ~= tostring("right") do
		turnRight()
	end
end

function faceLeft()
	while not tostring(curDir) ~= tostring("left") do
		turnRight()
	end
end

function faceForward()
	while not tostring(curDir) ~= tostring("forward") do
		turnRight()
	end
end

function faceBack()
	while not tostring(curDir) ~= tostring("back") do
		turnRight()
	end
end

function addPath()
	if curDir == "forward" then
		zCoord = zCoord + 1
	end
	
	if curDir == "back" then
		zCoord = zCoord - 1
	end
	
	if curDir == "right" then
		xCoord = xCoord + 1
	end
	
	if curDir == "left" then
		xCoord = xCoord - 1
	end
end

function returnPath()
	wasX = xCoord
	wasY = yCoord
	wasZ = zCoord
	wasDir = curDir
	
	if yCoord < 0 then
		for i = 0, yCoord, -1 do
			up()
		end
	elseif yCoord > 0 then
		for i = 0, yCoord, 1 do
			down()
		end
	end
	
	if xCoord < 0 then
		faceRight()
		for i = 0, xCoord, -1 do
			forward()
		end
	elseif xCoord > 0 then
		faceLeft()
		for i = 0, xCoord, 1 do
			forward()
		end
	end
	
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	faceBack()
end

function goBack()
	faceForward()
	turtle.forward()
	zCoord = 1
	xCoord = 0
	yCoord = 0

	if wasZ < 0 then
		faceBack()
		for i = 0, wasZ, -1 do
			forward()
		end
	elseif wasZ > 0 then
		faceForward()
		for i = 0, wasZ, 1 do
			forward()
		end
	end
	faceForward()
	if wasX < 0 then
		faceLeft()
		for i = 0, wasX, -1 do
			forward()
		end
	elseif wasX > 0 then
		faceRight()
		for i = 0, wasX, 1 do
			forward()
		end
	end
	faceForward()
	if wasY < 0 then
		for i = 0, wasY, -1 do
			down()()
		end
	elseif wasY > 0 then
		for i = 0, wasY, 1 do
			up()
		end
	end
	
	if wasDir == "forward" then	--Face previous direction
		faceForward()
	elseif wasDir == "right" then
		faceRight()
	elseif wasDir == "left" then
		faceLeft()
	elseif wasDir == "back" then
		faceBack()
	end
	
	turtle.select(1)
	if zCoord ~= wasZ then	--Check that we got back to the right location
		print("Did not get back to the correct Z point")
		return false
	end
	if xCoord ~= wasX then
		print("Did not get back to the correct X point")
		return false
	end
	if yCoord ~= wasY then
		print("Did not get back to the correct Y point")
		return false
	end
	return true
end

function getFirstWidth()
	firstWidth = math.floor((width/2))
	print("The first width is: "..firstWidth)
end

function turnMineRight()
	turnRight()
	forward()
	turnRight()
end

function turnMineLeft()
	turnLeft()
	forward()
	turnLeft()
end

function checkInvFull()
	local invCount = 0
	for i = 1, 16 do
		if turtle.getItemCount(i) > 0 then
			invCount = invCount + 1
		end
	end
	if invCount == 16 then
		invCount = 0
		return true
	else
		invCount = 0
		return false
	end
end

function emptyInv()
	faceBack()
	for i = 2, 16 do
		turtle.select(i)
		turtle.drop()
	end
	faceForward()
end

function refuel()
	faceLeft()
	for i = 1, 16 do
		turtle.select(i)
		if turtle.refuel(0) then
			while turtle.getFuelLevel < (estimateFuel() * 1.1) do
				if i == 1 then
					turtle.refuel((turtle.getItemCount()-1))
				else
					turtle.refuel()
				end
			end
		end
	end
	faceForward()
end

function estimateFuel()
	estFuel = math.ceil((width * length) * (height / 2.8))
	return estFuel
end

function checkInvLoop()
	if checkInvFull() then
		returnPath()
		emptyInv()
		goBack()
	end
end
	
function checkFuelLoop()
	if turtle.getFuelLevel() < 500 then
		returnPath()
		refuel()
		goBack()
	end
end

function holeMenu()
	setVars()
	
	clearScreen()
	print("You have chosen to dig a hole.")
	
	print("Please enter an odd number for width:")
	userInput = tonumber(read())
	checkOdd()
	width = userInput
	
	print("Please enter an odd number for length:")
	userInput = tonumber(read())
	checkOdd()
	length = userInput
	
	print("Please enter how far down to go:")
	height = tonumber(read())
	heightOpp = height * (0-1)
	
	print("You have chosen to dig a "..width.." by "..length.." and")
	print(height.." deep hole. This will consume an ")
	print("estimated "..estimateFuel().." units of fuel")
	print("Is this OK? (Y/N): ")
	local yesNo = read()
	if yesNo == "y" or yesNo == "Y" then
		hole()
	elseif yesNo == "n" or yesNo == "N" then
		holeMenu()
	else
		print("Invalid input - try again")
		sleep(2)
		holeMenu()
	end
end


function hole()
	while estimateFuel() > turtle.getFuelLevel() do	--Check fuel level and refuel if need be
		clearScreen()
		print("I estimate that I will use more fuel than I have")
		print("Refuelling...")
		faceLeft()
		while not turtle.suck() do
			print("I need a fuel chest to my left")
			sleep(5)
		end
		while not refuel() do
			print("I can't refuel with current inventory.")
			print("Please provide me with a fuel chest.")
			sleep(5)
		end
	end
	faceForward()

	beginMine()	--Get into position to mine
	getFirstWidth()	--Calculate half of overall width so that you can start mining from the middle
	for i = 1, firstWidth do	--Dig out the first layer of the right side
		forward()
	end
	turnLeft()	--Turn right around and dig the rest of the first layer
	turnLeft()
	for i = 2, width do
		forward()
	end
--[[
	for i = 2, length do	--Dig first layer of the mine
		if xCoord < 0 and curDir == "left" then
			if zCoord == length then
				turnMineLeft()
			else
				turnMineRight()
			end
		elseif xCoord < 0 and curDir == "right" then
			if zCoord == length then
				turnMineRight()
			else
				turnMineLeft()
			end
		elseif xCoord > 0 and curDir == "right" then
			if zCoord == length then
				turnMineRight()
			else
				turnMineLeft()
			end
		elseif xCoord > 0 and curDir == "left" then
			if zCoord == length then
				turnMineLeft()
			else
				turnMineRight()
			end
		else
			print("I don't know what to do!")
			return
		end
		for j = 2, width do
			forward()
		end
	end
	turnRight()	--Turn turtle around and dig down
	turnRight()
	for i = 1, (heightOpp + 3 < yCoord and 3 or yCoord - heightOpp - 1) do
		down()
	end
	headForward = false
	for i = 2, width do
		forward()
	end
	]]--
	--	^^	Is the first layer specific function required anymore?
	repeat	--Dig remaining layers
		repeat
			if headForward == false and xCoord > 0 then
				turnMineRight()
			elseif headForward == false and xCoord < 0 then
				turnMineLeft()
			elseif headForward == true and xCoord > 0 then
				turnMineLeft()
			elseif headForward == true and xCoord < 0 then
				turnMineRight()
			end
			for i = 2, width do
				forward()
			end
		until (zCoord == 1) or (zCoord == length)
		turnRight()	--Turn turtle around and dig down
		turnRight()
		for i = 1, 3 do
			down()
		end
		if zCoord == 1 then
			headForward = true
		elseif zCoord == length then
			headForward = false
		end
		for i = 2, width do
			forward()
		end
	until yCoord == heightOpp + 1
	repeat	--Once reached final layer, finish digging that layer before stopping
		if headForward == false and xCoord > 0 then
			turnMineRight()
		elseif headForward == false and xCoord < 0 then
			turnMineLeft()
		elseif headForward == true and xCoord > 0 then
			turnMineLeft()
		elseif headForward == true and xCoord < 0 then
			turnMineRight()
		end
		for i = 2, width do
			forward()
		end
	until zCoord == length
	clearScreen()	--Clear screen, print information
	print("I think I've finished mining!")
	print("Returning home now...")
	returnPath()
	print("I'm home")
	emptyInv()
end

function tunnelMenu()
	print("Tunnel menu still in construction")
end

function tunnel()
	print("Still constructing software...")
end

function branchMenu()
	print("Branch menu still in construction")
end

function branch()
	print("Still constructing software...")
end
Edited on 15 February 2014 - 04:35 PM
Bomb Bloke #34
Posted 15 February 2014 - 08:29 PM
You could rewrite your facing functions along these lines:

function faceRight()
        if curDir == "back" then turnLeft()
        else while curDir ~= "right" do turnRight() end end
end

This'd either turn once or twice, never thrice. I can't see anything that'd lead to the turtle spinning forever - assuming it has fuel.

Better yet, you could incorporate parameters, allowing you to merge all four facing functions into one:

function face(targetDirection)
        if (targetDirection == "right" and curDir == "back") 
        or (targetDirection == "forward" and curDir == "right")
        or (targetDirection == "back" and curDir == "left")
        or (targetDirection == "left" and curDir == "forward") then
        	turnLeft()
        else
        	while curDir ~= targetDirection do turnRight() end
        end
end

Say you call this function like so:

face("right")

The string with the word "right" gets passed as a parameter to the "face" function, which stores it in the variable "targetDirection" for the duration of the function call.

This means that you can rewrite chunks of code like this:

        if wasDir == "forward" then     --Face previous direction
                faceForward()
        elseif wasDir == "right" then
                faceRight()
        elseif wasDir == "left" then
                faceLeft()
        elseif wasDir == "back" then
                faceBack()
        end

As just this:

face(wasDir)
Edited on 15 February 2014 - 07:33 PM
xBlizzDevious #35
Posted 16 February 2014 - 07:35 PM
-snip

Thanks. The function to make it face the direction you call makes a lot more sense. It also stops it spinning around endlessly and allows it to mine - at least until it fills up…

I honestly can't see what's wrong with my goBack() function, though. When the turtle arrives back by the returnPath() function, it empties out (what appears to be correctly) and then turns to face the mine. It then turns back around and digs in the wrong direction. I can't figure out why. Here's the latest version:

Spoiler

function setVars()
    xCoord = 0
    yCoord = 0
    zCoord = 0
    headForward = true
    distance = 0
    firstWidth = 0
    width = 0
    height = 0
    length = 0
    heightOpp = 0
    curDir = "forward"
    userInput = ""
    wasX = 0
    wasY = 0
    wasZ = 0
    wasDir = ""
    estFuel = 0
end

function clearScreen()
    term.clear()
    term.setCursorPos(1,1)
end

function printVariables()
    clearScreen()
    print("Currently digging a "..width.." by "..length.." hole")
    print("Mining down "..heightOpp.." blocks")
    print("X Difference: "..xCoord)
    print("Y Difference: "..yCoord)
    print("Z Difference: "..zCoord)
    print("Current Direction: "..curDir)
    print("Current fuel: "..turtle.getFuelLevel())
end

function checkOdd()
    if (userInput % 2 == 0) then
        print("That is an even number.")
        print("Please input an ODD number:")
        userInput = tonumber(read())
        checkOdd()
    else
        return
    end
end

function forward()
    if turtle.detect() == true then
        turtle.dig()
    end
    
    if turtle.detectUp() == true then
        turtle.digUp()
    end
    
    if turtle.detectDown() == true then
        turtle.digDown()
    end
    
    if turtle.forward() == true then
        addPath()
    else
        forward()
    end
    printVariables()
    checkFuelLoop()
    checkInvLoop()
end

function up()
    if turtle.detectUp() then
        if not turtle.digUp() then
            return
        end
    end
    while not turtle.up() do
        turtle.attackUp()
        turtle.digUp()
    end
    yCoord = yCoord + 1
    printVariables()
    checkFuelLoop()
    checkInvLoop()
end

function down()
    if turtle.detectUp() then
        turtle.digUp()
    end
    if turtle.detectDown() then
        if not turtle.digDown() then
            return
        end
    end
    while not turtle.down() do
        turtle.attackDown()
        turtle.digDown()
    end
    yCoord = yCoord - 1
    printVariables()
    checkFuelLoop()
    checkInvLoop()
end

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()
    headForward = true
end

function turnLeft()
    if turtle.turnLeft() == true then
        if curDir == "forward" then
            curDir = "left"
        elseif curDir == "left" then
            curDir = "back"
        elseif curDir == "back" then
            curDir = "right"
        elseif curDir == "right" then
            curDir = "forward"
        end
    end
end

function turnRight()
    if turtle.turnRight() then
        if curDir == "forward" then
            curDir = "right"
        elseif curDir == "left" then
            curDir = "forward"
        elseif curDir == "back" then
            curDir = "left"
        elseif curDir == "right" then
            curDir = "back"
        end
    end
end

function face(targetDirection)
    if (targetDirection == "right" and curDir == "back")
    or (targetDirection == "forward" and curDir == "right")
    or (targetDirection == "back" and curDir == "left")
    or (targetDirection == "left" and curDir == "forward") then
        turnLeft()
    else
        while curDir ~= targetDirection do turnRight() end
    end
end

function addPath()
    if curDir == "forward" then
        zCoord = zCoord + 1
    end
    
    if curDir == "back" then
        zCoord = zCoord - 1
    end
    
    if curDir == "right" then
        xCoord = xCoord + 1
    end
    
    if curDir == "left" then
        xCoord = xCoord - 1
    end
end

function returnPath()
    wasX = xCoord
    wasY = yCoord
    wasZ = zCoord
    wasDir = curDir
    
    if yCoord < 0 then
        for i = 0, yCoord, -1 do
            up()
        end
    elseif yCoord > 0 then
        for i = 0, yCoord, 1 do
            down()
        end
    end
    
    if xCoord < 0 then
        face("right")
        for i = 0, xCoord, -1 do
            forward()
        end
    elseif xCoord > 0 then
        face("left")
        for i = 0, xCoord, 1 do
            forward()
        end
    end
    
    if zCoord < 0 then
        face("forward")
        for i = 0, zCoord, -1 do
            forward()
        end
    elseif zCoord > 0 then
        face("back")
        for i = 0, zCoord, 1 do
            forward()
        end
    end
    
    face("back")
end

function goBack()
    face("forward")
    turtle.forward()
    zCoord = 1
    xCoord = 0
    yCoord = 0

    if wasZ > 1 then
        face("forward")
        for i = 1, wasZ, 1 do
            forward()
        end
    end
    
    if wasX < 0 then
        face("left")
        for i = 0, wasX, -1 do
            forward()
        end
    elseif wasX > 0 then
        face("right")
        for i = 0, wasX, 1 do
            forward()
        end
    end
    
    if wasY < 0 then
        for i = 0, wasY, -1 do
            down()
        end
    elseif wasY > 0 then
        for i = 0, wasY, 1 do
            up()
        end
    end

    face(wasDir)
    
    turtle.select(1)
    if zCoord ~= wasZ then    --Check that we got back to the right location
        print("Did not get back to the correct Z point")
        return false
    end
    if xCoord ~= wasX then
        print("Did not get back to the correct X point")
        return false
    end
    if yCoord ~= wasY then
        print("Did not get back to the correct Y point")
        return false
    end
    return true
end

function getFirstWidth()
    firstWidth = math.floor((width/2))
    print("The first width is: "..firstWidth)
end

function turnMineRight()
    turnRight()
    forward()
    turnRight()
end

function turnMineLeft()
    turnLeft()
    forward()
    turnLeft()
end

function checkInvFull()
    local invCount = 0
    for i = 1, 16 do
        if turtle.getItemCount(i) > 0 then
            invCount = invCount + 1
        end
    end
    if invCount == 16 then
        invCount = 0
        return true
    else
        invCount = 0
        return false
    end
end

function emptyInv()
    face("back")
    for i = 2, 16 do
        turtle.select(i)
        turtle.drop()
    end
    face("forward")
end

function refuel()
    face("left")
    for i = 1, 16 do
        turtle.select(i)
        if turtle.refuel(0) then
            while turtle.getFuelLevel < (estimateFuel() * 1.1) do
                if i == 1 then
                    turtle.refuel((turtle.getItemCount()-1))
                else
                    turtle.refuel()
                end
            end
        end
    end
    face("forward")
end

function estimateFuel()
    estFuel = math.ceil((width * length) * (height / 2.8))
    return estFuel
end

function checkInvLoop()
    if checkInvFull() then
        returnPath()
        emptyInv()
        goBack()
    end
end
    
function checkFuelLoop()
    if turtle.getFuelLevel() < 500 then
        returnPath()
        refuel()
        goBack()
    end
end

function holeMenu()
    setVars()
    
    clearScreen()
    print("You have chosen to dig a hole.")
    
    print("Please enter an odd number for width:")
    userInput = tonumber(read())
    checkOdd()
    width = userInput
    
    print("Please enter an odd number for length:")
    userInput = tonumber(read())
    checkOdd()
    length = userInput
    
    print("Please enter how far down to go:")
    height = tonumber(read())
    heightOpp = height * (0-1)
    
    print("You have chosen to dig a "..width.." by "..length.." and")
    print(height.." deep hole. This will consume an ")
    print("estimated "..estimateFuel().." units of fuel")
    print("Is this OK? (Y/N): ")
    local yesNo = read()
    if yesNo == "y" or yesNo == "Y" then
        hole()
    elseif yesNo == "n" or yesNo == "N" then
        holeMenu()
    else
        print("Invalid input - try again")
        sleep(2)
        holeMenu()
    end
end


function hole()
    while estimateFuel() > turtle.getFuelLevel() do    --Check fuel level and refuel if need be
        clearScreen()
        print("I estimate that I will use more fuel than I have")
        print("Refuelling...")
        face("left")
        while not turtle.suck() do
            print("I need a fuel chest to my left")
            sleep(5)
        end
        while not refuel() do
            print("I can't refuel with current inventory.")
            print("Please provide me with a fuel chest.")
            sleep(5)
        end
    end
    face("forward")

    beginMine()    --Get into position to mine
    getFirstWidth()    --Calculate half of overall width so that you can start mining from the middle
    for i = 1, firstWidth do    --Dig out the first layer of the right side
        forward()
    end
    turnLeft()    --Turn right around and dig the rest of the first layer
    turnLeft()
    for i = 2, width do
        forward()
    end

    repeat    --Dig the mine until the specified height is reached.
        repeat
            if headForward == false and xCoord > 0 then
                turnMineRight()
            elseif headForward == false and xCoord < 0 then
                turnMineLeft()
            elseif headForward == true and xCoord > 0 then
                turnMineLeft()
            elseif headForward == true and xCoord < 0 then
                turnMineRight()
            end
            for i = 2, width do
                forward()
            end
        until (zCoord == 1) or (zCoord == length)
        turnRight()    --Turn turtle around and dig down
        turnRight()
        
	    for i = 1, (heightOpp + 3 < yCoord and 3 or yCoord - heightOpp - 1) do
		    down()
	    end
        
        if zCoord == 1 then
            headForward = true
        elseif zCoord == length then
            headForward = false
        end
        for i = 2, width do
            forward()
        end
    until yCoord == heightOpp
    repeat    --Once reached final layer, finish digging that layer before stopping
        if headForward == false and xCoord > 0 then
            turnMineRight()
        elseif headForward == false and xCoord < 0 then
            turnMineLeft()
        elseif headForward == true and xCoord > 0 then
            turnMineLeft()
        elseif headForward == true and xCoord < 0 then
            turnMineRight()
        end
        for i = 2, width do
            forward()
        end
    until zCoord == length
    clearScreen()    --Clear screen, print information
    print("I think I've finished mining!")
    print("Returning home now...")
    returnPath()
    print("I'm home")
    emptyInv()
end

function tunnelMenu()
    print("Tunnel menu still in construction")
end

function tunnel()
    print("Still constructing software...")
end

function branchMenu()
    print("Branch menu still in construction")
end

function branch()
    print("Still constructing software...")
end
Bomb Bloke #36
Posted 16 February 2014 - 09:31 PM
I can't see any logic there that'd make the turtle head the wrong way. I may have to actually test it out later and see exactly how it behaves.

One issue I do see is in your counting. Say the turtle has "xCoord" at 4, and runs "returnPath()". It'll face left, then start a loop where "i" counts from 0 to 4 - that's five iterations in all. I assume that's ok, given that you're saying it manages to dump its load into the chest correctly.

When it goes to run "goBack()", it sets "xCoord" to 0, faces right, then perform another loop where "i" counts from 0 to 4. After doing so, "xCoord" will've been incremented five times, so its final value will be 5 (although it should be back where it started, it now thinks it's somewhere else).

A fix for this would be to simply not set "xCoord" to 0 when starting the "goBack()" function. "yCoord" and "zCoord" have similar issues, of course.
xBlizzDevious #37
Posted 16 February 2014 - 09:37 PM
I can't see any logic there that'd make the turtle head the wrong way. I may have to actually test it out later and see exactly how it behaves.

One issue I do see is in your counting. Say the turtle has "xCoord" at 4, and runs "returnPath()". It'll face left, then start a loop where "i" counts from 0 to 4 - that's five iterations in all. I assume that's ok, given that you're saying it manages to dump its load into the chest correctly.

When it goes to run "goBack()", it sets "xCoord" to 0, faces right, then perform another loop where "i" counts from 0 to 4. After doing so, "xCoord" will've been incremented five times, so its final value will be 5 (although it should be back where it started, it now thinks it's somewhere else).

A fix for this would be to simply not set "xCoord" to 0 when starting the "goBack()" function. "yCoord" and "zCoord" have similar issues, of course.

The resetting of those variables was added after I discovered that this happened. It should be completely useless, but in respect to the 0 to 4, thing, that's because I wrote that function before I realised that it would run 5 times and I haven't changed it. When it ran the first time, it seemed to work. I shall have to test that with it starting at 1, myself.

I'd appreciate if you could test the goBack function as this is really bugging me and I can't figure it out.
TilionDC #38
Posted 16 February 2014 - 11:10 PM
EDIT: I have another quick question: what is the best way to detect when a turtle is full? Is it just to run a scan of how many items in the selected slot through a for loop for 16 once every so often or something? If so, how often would be most suitable?
That's pretty much it, yes. Make a basic function like so:

local function inventoryIsFull()  -- Returns true if the all slots in the turtle's inventory contain items.
	for i=1,16 do
		if turtle.getItemCount(i) == 0 then
			return false
		end
	end
	
	return true
end

As for "how often" to call it? Well, the frequency should be equal to how often you wish to know… Choose a time in the turtle's routine where it'd be convenient to break out and dump stuff, and check then.

if inventoryIsFull() then
	-- Code to go empty the turtle's inventory goes here.
end

EDIT 2: Also, the same question as the last one basically, but substitute the inventory being full for refueling. When is best to refuel and what is the best way to check fuel usage and such?
Again, choose a time that suits you. For example, if I made a turtle that dug layers of stuff downwards until it hit bedrock, I might have it check once every row it digs, or every layer it digs, or maybe just once before it started the whole project. Work out how much fuel it'll consume between each check, and if on any given check it has less then that amount, refuel.

Ok, thanks!

Next question…. I've come across a major bug and I really need to get to sleep so I'm posting this before I head to bed. When my turtle finishes a layer, it is supposed to work out the distance to the end of its path and then go down a certain number of layers, respectively. So, for example, if I tell the miner to dig a 5x3 hole 10 deep, it should check the distance between it's current "yCoord" and its intended height and then travel either 3 blocks down or one block down depending on whether the "toGo" distance is above 3 or not. I've told the miner to print the "toGo" variable and the "distance" variable just before it starts to dig down and they are both correct - 10 and 3 respectively - but for some reason, my miner just digs down as far as he can go.


Here's the latest version of each program:

betterMine:
Spoiler

os.loadAPI("/apis/miner")

function mineMenu()
  term.clear()
  term.setCursorPos(1,1)
  print("Please choose the type of")
  print("mine that you would like:")
  print("1. Hole")
  print("2. Tunnel")
  print("3. Branch Mine")
  print("4. Stairs")
  begin()
end

function begin()
  local userInput = read()
  if userInput == "1" then
	miner.holeMenu()
  elseif userInput == "2" then
	miner.tunnelMenu()
  elseif userInput == "3" then
	miner.branchMenu()
  elseif userInput == "4" then
	miner.stairsMenu()
  else
	print("That was an invalid selection")
	sleep(2)
	mineMenu()
  end
end

mineMenu()

miner:
Spoiler

local xCoord = 0
local yCoord = 0
local zCoord = 0
local distance = 0
local firstWidth = 0
local width = 0
local height = 0
local length = 0
local curDir = "forward"
local userInput = ""

function clearScreen()
	term.clear()
	term.setCursorPos(1,1)
end

function checkOdd()
	if (userInput % 2 == 0) then
		print("That is an even number.")
		print("Please input an ODD number:")
		userInput = read()
		checkOdd()
	else
		return
	end
end

function forward()
	if turtle.detect() == true then
		turtle.dig()
	end
	
	if turtle.detectUp() == true then
		turtle.digUp()
	end
	
	if turtle.detectDown() == true then
		turtle.digDown()
	end
	
	if turtle.forward() == true then
		addPath()
	else
		forward()
	end
end

function up()
	for i = 1, distance, 1 do
		if turtle.detectUp() == false then
			turtle.up()
			yCoord = yCoord + 1
		else
			turtle.digUp()
			up()
		end
	end
end

function down()
	for i = 1, distance, 1 do
		if turtle.detectDown() == false then
			turtle.down()
			yCoord = yCoord - 1
		else
			turtle.digDown()
			down()
		end
	end
	
end

function beginMine()
	if turtle.detect() == true then
		turtle.dig()
	end
	turtle.forward()
	turtle.turnLeft()
	curDir = "left"
end

function turnLeft()
	if turtle.turnLeft() == true then
		if curDir == "forward" then
			curDir = "left"
		elseif curDir == "left" then
			curDir = "back"
		elseif curDir == "back" then
			curDir = "right"
		elseif curDir == "right" then
			curDir = "forward"
		end
	end
end

function turnRight()
	if turtle.turnRight() == true then
		if curDir == "forward" then
			curDir = "right"
		elseif curDir == "left" then
			curDir = "forward"
		elseif curDir == "back" then
			curDir = "left"
		elseif curDir == "right" then
			curDir = "back"
		end
	end
end

function faceRight()
	if curDir == "forward" then
		turnRight()
		print("Facing right")
	elseif curDir == "right" then
		print("Facing right")
	elseif curDir == "back" then
		turnLeft()
		print("Facing right")
	elseif curDir == "left" then
		turnRight()
		turnRight()
		print("Facing right")
	end
end

function faceLeft()
	if curDir == "forward" then
		turnLeft()
		print("Facing left")
	elseif curDir == "right" then
		turnLeft()
		turnLeft()
		print("Facing left")
	elseif curDir == "back" then
		turnRight()
		print("Facing left")
	elseif curDir == "left" then
		print("Facing left")
	end
end

function faceForward()
	if curDir == "forward" then
		print("Facing forward")
	elseif curDir == "right" then
		turnLeft()
		print("Facing forward")
	elseif curDir == "back" then
		turnRight()
		turnRight()
		print("Facing forward")
	elseif curDir == "left" then
		turnRight()
		print("Facing forward")
	end
end

function faceBack()
	if curDir == "forward" then
		turnRight()
		turnRight()
		print("Facing back")
	elseif curDir == "right" then
		turnLeft()
		print("Facing back")
	elseif curDir == "back" then
		print("Facing back")
	elseif curDir == "left" then
		turnLeft()
		print("Facing left")
	end
end

function addPath()
	if curDir == "forward" then
		zCoord = zCoord + 1
	end
	
	if curDir == "back" then
		zCoord = zCoord - 1
	end
	
	if curDir == "right" then
		xCoord = xCoord + 1
	end
	
	if curDir == "left" then
		xCoord = xCoord - 1
	end
end

function returnPath()
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	if xCoord < 0 then
		faceRight()
		for i = 0, xCoord, -1 do
			forward()
		end
	elseif xCoord > 0 then
		faceLeft()
		for i = 0, xCoord, 1 do
			forward()
		end
	end
	
	if zCoord < 0 then
		faceForward()
		for i = 0, zCoord, -1 do
			forward()
		end
	elseif zCoord > 0 then
		faceBack()
		for i = 0, zCoord, 1 do
			forward()
		end
	end
	
	faceBack()
	if yCoord < 0 then
		for i = 0, yCoord, -1 do
			up()
		end
	elseif yCoord > 0 then
		for i = 0, yCoord, 1 do
			down()
		end
	end
end

function getFirstWidth()
	firstWidth = math.floor((width/2))
	print("The first width is: "..firstWidth)
end

function holeMenu()
	clearScreen()
	print("You have chosen to dig a hole.")
	
	print("Please enter an odd number for width:")
	userInput = read()
	checkOdd()
	width = userInput
	
	print("Please enter an odd number for length:")
	userInput = read()
	checkOdd()
	length = userInput
	
	print("Please enter how far down to go:")
	height = read()
	
	print("You have chosen to dig a "..width.." by "..length.." and")
	print(height.." deep hole. Is this correct (Y/N): ")
	local yesNo = read()
	if yesNo == "y" or yesNo == "Y" then
		hole()
	elseif yesNo == "n" or yesNo == "N" then
		holeMenu()
	else
		print("Invalid input - try again")
		sleep(2)
		holeMenu()
	end
end

function hole()
	beginMine()
	getFirstWidth()
	for i = 1, firstWidth, 1 do
		forward()
	end
	for i = 1, height, 1 do
		for j = 3, length, 2 do
			turnRight()
			forward()
			turnRight()
			for k = 2, width, 1 do
				forward()
			end
			turnLeft()
			forward()
			turnLeft()
			for k = 2, width, 1 do
				forward()
			end
		end
		local toGo = height - yCoord
		if toGo > 3 then
			distance = 3
		else
			distance = 1
		end
		print(toGo)
		print(distance)
		sleep(5)
		down()
	end
end

function tunnelMenu()
	print("Tunnel menu still in construction")
end

function tunnel()
	print("Still constructing software...")
end

function branchMenu()
	print("Branch menu still in construction")
end

function branch()
	print("Still constructing software...")
end
I realize this post may come a little late i just thought i should say that its better to use turtle.getItemSpace() instead since some items only stack to 16 or even 1 and then it would count it as 48 respective 63 more items would fit in that slot. But maybe that doens't matter if you are only mining.
xBlizzDevious #39
Posted 17 February 2014 - 01:03 PM
-snip-

That's a good point, actually. Not something I'd have thought of, however, it's a bit irrelevant to the whole, not working thing at the moment. Haha.
Bomb Bloke #40
Posted 18 February 2014 - 12:17 AM
Ah, here we go - I should've cottoned on to this earlier. "forward()" is the function that determines when the turtle should try to go empty its inventory. The functions which actually carry out that process call "forward()", resulting in a ton of recursion. Your "returnPath()" function, by pure coincedence, happens to be rigged such that the recursion usually doesn't matter, but your "goBack()" function isn't.

The solution boils down to ensuring that "forward()" doesn't ever call "checkInvLoop()" while that function is already running.
xBlizzDevious #41
Posted 21 February 2014 - 02:15 PM
Ah, here we go - I should've cottoned on to this earlier. "forward()" is the function that determines when the turtle should try to go empty its inventory. The functions which actually carry out that process call "forward()", resulting in a ton of recursion. Your "returnPath()" function, by pure coincedence, happens to be rigged such that the recursion usually doesn't matter, but your "goBack()" function isn't.

The solution boils down to ensuring that "forward()" doesn't ever call "checkInvLoop()" while that function is already running.

Hmm, well I've made it do something, but it's all working a bit wrong. I'm going to have a break from Minecraft for a few weeks while I focus on college work, but I'll come back to this sometime later on and hopefully get it working properly. Thanks so far for all the help!