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

Tree farm [string:1: attempt to call nil]

Started by jag, 31 October 2012 - 01:02 AM
jag #1
Posted 31 October 2012 - 02:02 AM
So straight forward:
  • I got a tree farm program.
  • It's buggy.
  • Here's the code:
    SpoilerAlso on pastebin: zcmDcV15
    --(( Variables ))--
    
    local cutCount = 0
    
    local moves = {
      dig = {
    	["f"] = turtle.dig,
    	["u"] = turtle.digUp,
    	["d"] = turtle.digDown,
      },
      move = {
    	["f"] = turtle.forward,
    	["u"] = turtle.up,
    	["d"] = turtle.down,
      },
      attack = {
    	["f"] = turtle.attack,
    	["u"] = turtle.attackUp,
    	["d"] = turtle.attackDown,
      },
    }
    
    --(( Functions ))--
    
    function go(direction, fromNum, toNum)
      while not moves.move[direction]() do
    	if fromNum and toNum then
    	  select(fromNum,toNum)
    	end
    	if not moves.dig[direction]() then
    	  moves.attack[direction]()
    	end
    	sleep(.5)
      end
    end
    
    function select(fromNum, toNum, option)
      if not toNum or fromNum == toNum then
    	turtle.select(fromNum)
    	return true
      end
      for slot = fromNum, toNum do
    	option = loadstring("turtle.getItem"..option.."(slot)")
    	if option() > 0 then
    	  turtle.select(slot)
    	  return true
    	end
      end
      return false
    end
    
    function cutTree()
      if turtle.getItemSpace(1) > 0 then
    	turtle.select(1)
      else
       if not select(5,16,"Space") then
    	 turtle.select(1)
    	 return false
       end
      end
      go("f")
      turtle.select(1)
      while turtle.compareUp() do
    	if not select(5,16,"Space") then
    	  turtle.select(1)
    	  return false
    	end
    	go("u",5,16)
      end
      while not turtle.detectDown() do
    	go("d",5,16)
      end
      if not turtle.back() then
    	for turns = 1, 2 do
    	  turtle.turnLeft()
    	end
    	go("f",5,16)
    	for turns = 1, 2 do
    	  turtle.turnRight()
    	end
      end
      return true
    end
    
    --(( Main program ))--
    
    if not fs.exists("."..shell.getRunningProgram().."Data") then
      file = fs.open("."..shell.getRunningProgram().."Data","w")
      file.write(cutCount)
      file.close()
    else
      file = fs.open("."..shell.getRunningProgram().."Data","r")
      cutCount = tonumber(file.readLine())
      file.close()
    end
    
    term.setCursorPos(1,1)
    term.clear()
    
    while true do
      if turtle.getItemCount(1) < 1 then
    	break
      end
      term.setCursorPos(1,1)
      term.clear()
      print("Remove the log to stop!")
      print()
      print("Have log in slot 1!")
      print("Have saplings in slot 2-4!")
      print()
      print("Trees cut: "..cutCount)
      print()
    
      if not turtle.detect() then
    	if not select(2,4,"count") then
    	  print("Out of saplings!")
    	  break
    	end
    	while not turtle.place() do
    	  moves.attack["f"]()
    	  sleep(.5)
    	end
      end
    
      turtle.select(1)
      if turtle.compare() then
    	if chopTree() then
    	  cutCount = cutCount + 1
    	  file = fs.open("."..shell.getRunningProgram().."Data","w")
    	  file.write(cutCount)
    	  file.close()
    	else
    	  print("Failed to chop tree!")
    	  break
    	end
      end
    
      sleep(.5)
    end
    
    turtle.select(1)
So the error that I'm getting is:
string:1: attempt to call nil
I've never seen this error before and I can't find any solutions on the interwebz.

EDIT:​ I caught one typo:

-- on line 118
    if not select(2,4,"count") then
-- misspelled count
-- first letter should be uppercase
    if not select(2,4,"Count") then
Now I'm getting another error, and I haven't seen this one either before:
string:1: Expected number
ChunLing #2
Posted 31 October 2012 - 07:44 AM
This kind of error usually indicates that you have tried to use loadstring on a bit of code that was syntactically valid (so loadstring turned it into a function named "string") but then you ran it and it was missing something.
option = loadstring("turtle.getItem"..option.."(slot)")
Works if you feed it "Space" or "Count" as the option. But at one point you fed it "count"
if not select(2,4,"count") then 
You might have fed it something bad in other places, I'm not sure. But this is kinda a wonky use of loadstring, methinks. You should just say "turtle["getItem"..option](slot)" instead of using loadstring to retype option and then running option here. And not just because loadstring errors are difficult to debug (really you should always pcall functions made by loadstring, I should do that myself). Calls of loadstring require the creation of a whole new virtual environment, they're super inefficient ways to do things that you might do any other way.
jag #3
Posted 31 October 2012 - 01:18 PM
This kind of error usually indicates that you have tried to use loadstring on a bit of code that was syntactically valid (so loadstring turned it into a function named "string") but then you ran it and it was missing something.
option = loadstring("turtle.getItem"..option.."(slot)")
Works if you feed it "Space" or "Count" as the option. But at one point you fed it "count"
if not select(2,4,"count") then 
You might have fed it something bad in other places, I'm not sure. But this is kinda a wonky use of loadstring, methinks. You should just say "turtle["getItem"..option](slot)" instead of using loadstring to retype option and then running option here. And not just because loadstring errors are difficult to debug (really you should always pcall functions made by loadstring, I should do that myself). Calls of loadstring require the creation of a whole new virtual environment, they're super inefficient ways to do things that you might do any other way.
Ah good idea with the
turtle["getItem"..option](slot)
idea! Thanks!
I'm going to try it now..
ChunLing #4
Posted 31 October 2012 - 11:03 PM
You still have to feed it correctly, only "Space" and "Count", but at least if it fails you know instantly what failed. And it's much faster execution-wise.
jag #5
Posted 31 October 2012 - 11:26 PM
But what if I do

option = option:lower()
option = option:gsub("%a",string.upper(),1)
Wouldn't that work?
ChunLing #6
Posted 31 October 2012 - 11:42 PM
… :P/>/>
Just feed it correctly. I mean, yeah, you can use string functions to ensure that user entered strings are more rather than less correct, but for the fixed strings in your code, they should just be right.

You had me going there. :P/>/>
jag #7
Posted 01 November 2012 - 01:01 AM
Thanks for the help btw!