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

Attempt to call nil on simple tunnel mining program.

Started by dangloverenator, 27 June 2013 - 06:27 PM
dangloverenator #1
Posted 27 June 2013 - 08:27 PM
So, I'm very new to ComputerCraft, but I really wanted to write my own mining program, rather than copying someone else's, to learn how it all works. I based it off this one here: http://www.computerc...-mining-turtle/ but with a few changes.

I'm more than happy to manually refuel the turtle, but basically what I want is for it to keep going down its tunnel, placing torches every 10 blocks, placing cobble underneath it (so that I can easily walk down and collect stuff later), placing chests behind it and dumping everything in them when its inventory gets full. I want it to return to its starting point when one of the following things happens:
1) it runs out of chests
2) it runs out of torches
3) the fuel level drops below an arbitrary number (I went for 100, but open to suggestions!)
4) there is no block to mine

I'm getting an attempt to call nil at line 77 (calling the digforward() function inside the run() function), have tried a few different things but can't for the life of me work out why! Anyone? The code is here:

Spoiler

local chests = turtle.getItemCount(1)
local torches = turtle.getItemCount(2)
local cobble = turtle.getItemCount(3)
local length = 0
local fuel = turtle.getFuelLevel()

function dump()
  if turtle.getItemCount(16) > 0 then
	turtle.turnLeft()
	turtle.turnLeft()
	turtle.select(1)
	turtle.place()
	for i = 4,16 do
	turtle.select(i)
	turtle.drop()
	turtle.turnLeft()
	turtle.turnLeft()
	chests = chests - 1
  end

function cobble()
  if turtle.detectDown() == false then
	turtle.select(3)
	turtle.place()
  end
end

function home()
  dump()
  turtle.turnLeft()
  turtle.turnLeft()
  turtle.up()
  for i = 1,length,1 do
	turtle.forward(i)
  end
  turtle.down()
  if torch == 0 then
	print ("No more torches!")
  elseif chests == 0 then
	print ("No more chests!")
  elseif fuel > 100 then
	print ("Fuel level low!")
  else
	print ("Nothing to mine!")
  end

function digforward()
  if turtle.detect() then
	turtle.dig()
  end
  cobble()
  turtle.forward()
  turtle.digUp()
  dump()
  length = length + 1
end
end
	elseif turtle.detect() == false then
  home()
end
end


function light()
  turtle.turnLeft()
  turtle.turnLeft()
  turtle.select(2)
  turtle.place()
  turtle.turnLeft()
  turtle.turnLeft()
  torches = torches - 1
end

function run()
  while (torches > 0) and (chests > 0) and (cobble > 0) and (fuel > 100) do
  for i = 1,10,1 do
  digforward()
  end
  light()
  end
  home()
  end

run()

Thanks in advance!
Lyqyd #2
Posted 27 June 2013 - 09:56 PM
Split into new topic.
trakos #3
Posted 28 June 2013 - 07:25 AM
I can't understand your code, there is something wrong with how you "end" your functions. Function digforward appears to be inside dump() function or something. I guess that's the reason why it's not defined.

Try fixing your indentation and checking where you end your functions.
dangloverenator #4
Posted 28 June 2013 - 07:59 AM
EDIT: so I *think* I fixed the coding errors (it's not throwing me any more error messages anyway), but the turtle is now just sitting and doing nothing when I try and run the program! Here is the updated code… (Also, I'm still pretty unsure as to how the indentation should be done, so if anyone wanted to give me a few pointers that would be great.)

Spoiler

local chests = turtle.getItemCount(1)
local torches = turtle.getItemCount(2)
local cobble = turtle.getItemCount(3)
local length = 0
local fuel = turtle.getFuelLevel()

function dump()
  if turtle.getItemCount(16) > 0 then
    turtle.turnLeft()
    turtle.turnLeft()
    turtle.select(1)
    turtle.place()
    for i = 4,16 do
    turtle.select(i)
    turtle.drop()
    turtle.turnLeft()
    turtle.turnLeft()
    chests = chests - 1
  end
end

function cobble()
  if turtle.detectDown() == false then
    turtle.select(3)
    turtle.place()
  end
end

function home()
  dump() 
  turtle.turnLeft()
  turtle.turnLeft()
  turtle.up()
  for i = 1,length,1 do
    turtle.forward(i)
  end
  turtle.down()
  if torch == 0 then
    print ("No more torches!")
  elseif chests == 0 then
    print ("No more chests!")
  elseif fuel > 100 then
    print ("Fuel level low!")
  else
    print ("Nothing to mine!")
  end

function digforward()
  if turtle.detect() then
    turtle.dig()
    cobble()
    turtle.forward()
    turtle.digUp()
    dump()
    length = length + 1
  elseif turtle.detect() == false then
    home()
  end
end   

function light()
  turtle.turnLeft()
  turtle.turnLeft()
  turtle.select(2)
  turtle.place()
  turtle.turnLeft()
  turtle.turnLeft()
  torches = torches - 1
 end

function run()
  while (torches > 0) and (chests > 0) and (cobble > 0) and (fuel > 100) do
  for i = 1,10,1 do
  digforward()
  end
  light()
  end
  home()
  end
end

run()
end
Bomb Bloke #5
Posted 28 June 2013 - 09:20 AM
The idea is to move your margin a little to the right every time you enter a function/if/while/for block (that is to say, anything that needs an "end" on the end), then move it back to the left when you finish that block.

Correct indentation is not needed for your code to work, but makes it FAR easier to read and hence troubleshoot. You're certainly on the right track with it, but you seem a little unclear on what blocks need to be "end"ed.

For example, you don't indent the code under the "for" loop you start on line 13. If you had, you'd likely've noticed that you're missing an "end" statement prior to starting the function on line 22. The home() function is also missing an "end" statement at its bottom, which the indentation should've made clear to you.

To "make up" for this, you've crammed the required extra "end"s into the run() function and also at the very bottom of the program, but neither of them should be there.
dangloverenator #6
Posted 28 June 2013 - 11:50 AM
Thanks for all the replies! Following your advice, I went through and fixed the indentation, it definitely did help! I also got rid of the cobble() function entirely. So this is the finished (and working!) program:

Spoiler

local chests = turtle.getItemCount(1)
local torches = turtle.getItemCount(2)
local length = 0
local fuel = turtle.getFuelLevel()

function dump()
  if turtle.getItemCount(16) > 0 then
    turtle.turnLeft()
    turtle.turnLeft()
    turtle.select(1)
    turtle.place()
    for i = 3,16,1 do
      turtle.select(i)
      turtle.drop()
    end
    turtle.turnLeft()
    turtle.turnLeft()
    chests = chests - 1
  end
end

function home()
 if torches == 0 or chests == 0 or fuel < 100 or turtle.detect() == false then 
   turtle.turnLeft()
   turtle.turnLeft()
   turtle.up()
     for i = 1,length,1 do
       turtle.forward(i)
     end
  end
  turtle.down()
 if torches == 0 then
   print ("No more torches!")
 elseif chests == 0 then
   print ("No more chests!")
 elseif fuel < 100 then
   print ("Fuel level low!")
 elseif turtle.detect() == false then
   print ("Nothing to mine!")
 end
end

function digforward()
  if turtle.detect() then
    turtle.dig()
    turtle.forward()
    turtle.digUp()
    dump()
    length = length + 1
  end
end   

function light()
  turtle.turnLeft()
  turtle.turnLeft()
  turtle.select(2)
  turtle.place()
  turtle.turnLeft()
  turtle.turnLeft()
  torches = torches - 1
end

function run()
  while (torches > 0) and (chests > 0) and (fuel > 100) and turtle.detect() do
    for i = 1,10,1 do
      digforward()
    end
    light()
    dump()
    home()
  end
end

print ("Make sure I have chests in slot 1 and torches in slot 2")        
run()

I still want to tweak it a bit further (using an enderchest instead of multiple wooden chests would be cool), but for now this is working great. Suggestions as to how it could be improved are also very welcome.

Thanks all!
Bomb Bloke #7
Posted 28 June 2013 - 12:34 PM
Lines such as this:

fuel = turtle.getFuelLevel()

… set the variable ("fuel") to the output of the function ("turtle.getFuelLevel()") at the time you call it. It will not automatically update. Say the turtle has 400 fuel; you run the above, and the "fuel" variable gets set to 400. A hundred turtle movements later, it'll still be 400, unless you either manually run a "fuel = fuel - 1" every time the turtle moves or you reset it to the current output of "turtle.getFuelLevel()" every now and then.

Personally I'd just do away with the "fuel" variable and refer to "turtle.getFuelLevel()" whenever I wanted to use that information. Given that your code only needs to check it at occasional intervals there's no notable saving in processing time to be had by avoiding the extra function calls.

Your digging function may encounter issues if it encounters gravel or the like, which takes about 0.8 seconds to fall (if memory serves). The usual way around this is to construct a "while not turtle.forward() do" loop, and put your digging (and ideally sleep) commands inside that (the turtle will keep trying to dig until it's able to move forward successfully).