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

Need another pair of eyes

Started by lecrouch, 29 August 2015 - 04:07 PM
lecrouch #1
Posted 29 August 2015 - 06:07 PM
Hey all, just getting into computercraft, but I'm a somewhat experienced coder.

In any event, I have a slightly modified excavation type script and I am getting a weird bug that I can't seem to find so another set of eyes would be helpful!

Anyway, on line 44, I'm getting attempt to call nil

Sorry about all of the debugging prints. FYI, it is not even getting past or into the travelTo() function that is on line 44.

Help is appreciated!

http://pastebin.com/908FSgQ4

Julian
lecrouch #2
Posted 29 August 2015 - 08:34 PM
Edit: When I said line 44, I really meant, 28 ( had made some changes, and read an old error message)
Exerro #3
Posted 29 August 2015 - 11:23 PM
You're defining travelTo() after the function that calls it at line 28. You need to forward declare the function before using it, something like this.

local a, b
function a()
	b()
end
function b()
	a()
end

Both of those functions would work (and run until a stack overflow), and are still local because they were localised on line 1.
Edited on 29 August 2015 - 10:00 PM
lecrouch #4
Posted 30 August 2015 - 02:23 PM
Thanks for the input dude!

I added the forward declaration, and to be safe, since my functions bounce off of each other quite a bit, I went ahead and just forward declared them all.

Unfortunately, it didn't seem to work, still getting attempt to call nil, however now it is just on line 45.

Here's the new one.
http://pastebin.com/RsJidfXR
Bomb Bloke #5
Posted 31 August 2015 - 12:39 AM
You're declaring travelTo as local twice. That means the attempt to call it, on line 45, is going to point to the version on line 27, not the version defined after the call on line 263.

Remove the term "local" from 263, as well as from the function definitions for all the other local references you pre-declared.
Edited on 30 August 2015 - 10:40 PM
lecrouch #6
Posted 31 August 2015 - 07:22 AM
Okay, cool, I'll give that a go! Thanks for the help and the learnins!

I'm more of a C++ guy, so I've definitely got some growing pains. That being said I just read up a little about local and global variables in the Lua documentation, and it is leading me to believe that I may want to make all of the variables I defined at the top of the code before my function declarations global. Since you skimmed over my code, what's your two cents on that? Did I go a little "local" crazy and have limited myself in scope?
Bomb Bloke #7
Posted 31 August 2015 - 08:50 AM
The idea is that whenever your code references a variable (whether it's a number type or a function pointer or whatever), it'll go digging upwards to find the "closest" scope that contains it. If it's not defined anywhere then the global scope is used.

It's very rare that you'll want to use the global scope. In ComputerCraft, that's the scope shared by all scripts that execute on the system. If you store data within it, then it'll stay there until the system shuts down, persisting after your script completes.

For that reason, 99% of the time you'll want your variables to at least be local to your script, so that 1) other scripts can't alter them and 2) you don't accidentally affect subsequent executions of your own code with pre-set variables from the first. Defining them as such up the very top means that every part of your script can access them, which should be more than sufficient.

Sometimes that reach of scope is more than you need - if you only use a variable in a given function, then defining it as local to just that function means that it'll take the interpreter less time to find it then if you made it local to the whole script. If you're still unsure as to what can be reached where, take a read through this guide.

One comment I suppose I could make about your assignments up the top is that you could merge them all into one line:

local printLoc, goWaitForFuel, returnAndUnload, needFuel, checkInvSpace, turnRight, turnLeft, etc

You don't really need to pre-declare them all, though. It's just a case of making sure that every function is defined in the local space before you try to reference them without the local keyword.

For example, nothing tries to call printLoc() before you define it, so there's no need to pre-declare it. goWaitForFuel() is defined with a reference to returnAndUnload() before returnAndUnload() is defined, so in theory returnAndUnload() should be pre-declared… But you could alternatively just move the returnAndUnload() function definition above the goWaitForFuel() function definition instead. Etc, etc, etc.

If fully re-ordered, you may even find that no pre-declarations are required for your function pointer variables at all. In fact, if you CAN'T re-order things that way, then that in itself is often a sign that you've got functions recursively calling functions (something that's very seldom desirable - for example, in your current script, dealing with low fuel levels potentially involves moving to base, which involves checking the fuel level again, which involves trying to go to base again, which… well, eventually that'll hit a stack overflow).
Exerro #8
Posted 31 August 2015 - 02:43 PM
There may be cases where you want things to bounce off eachother infinitely however, in which case a tailcall is what you want. Let's say you do this:

local a, b
function a() b() end
function b() a() end
That'll cause a stack overflow after ~125 calls of each function.

This, however:

local a, b
function a() return b() end
function b() return a() end
won't ever cause a stack overflow.

That's because when you return a call to a function, it's known as a tailcall, and since (after loading the function to be called) there is no reason for the function currently executing to remain on the stack, it is popped from the stack before calling the new function. This means you won't get a stack overflow because before it calls the new function it stops calling the current function. Not the best explanation I'm sure, but this might help.
lecrouch #9
Posted 01 September 2015 - 12:51 AM
awsumben and bomb bloke, thank you. I really appreciate the help, not only because it helps further my minecraft addiction but because the concepts you explain are totally applicable to all languages, which is important to me because that's the direction I'm headed professionally. Plus it just goes to show that dicking around in any language does nothing but further your knowledge, even if it's high level like Lua.

So, thanks again, I'll play with it as soon as I can get a free moment from life!

Cheers fellas, and thanks, super stoked on the depth of your responses.
lecrouch #10
Posted 04 September 2015 - 04:41 AM
Alright guys, new issue. Everything works great except my travelTo() function that starts on line 234.

If I pull it out into an isolated program, it works perfect, but something in here seems to be clashing and it doesn't make it past the first if statement.

Ideas?

Thanks!!

http://pastebin.com/XQaq8neb
Edited on 04 September 2015 - 02:54 AM
lecrouch #11
Posted 04 September 2015 - 05:28 AM
added some more debugging prints, looks like at least one of my calls to locArrayIn[1] is coming back nil, so delving down that rabbit hole. If anyone beats me to it, I'm all ears

Edit, nope, ad an issue in my debugging print. Any mod may delete this message

Update: I think I've isolated the problem to my needFuel() function, but still uncertain. I also somewhat manually bypassed that and gave the turtle fuel while it was stuck in a loop, and when it got to the startLoc it got stuck in an endless loop of going up one and down one, so I'll have to address that as well..

Not much of any more luck, made some more revisions to no avail. seems like now it's getting stuck in the travelTo() func. as if it were a loop, and get's stuck trying to go up. Almost as if the main while loop is clashing with it during a call maybe? tells it to go forward, forward doesn't have enough fuel, then tries to go home, and somehow gets there. Only curious thing is I am not getting the print flag from goWaitForFuel()

Pretty lost now. Going to bed!

Cheers for the help!
Edited on 04 September 2015 - 05:02 AM
Bomb Bloke #12
Posted 04 September 2015 - 06:53 AM
This may well be related to the recursion issue I warned you about earlier.

Let's say the turtle hits travelTo() and is low on fuel. It'll soon call moveForward()/moveUp()/whatever, which'll in turn call needFuel() - if there's a lack of on-hand fuel items then that'll lead to goWaitForFuel() being called.

goWaitForFuel() then calls travelTo()… which goes through the above process again, resulting in goWaitForFuel() being called again (with a previous instance still in the stack!), travelTo() being called, goWaitForFuel(), travelTo(), goWaitForFuel()… etc etc etc. The loop won't progress - in such a circumstance, the turtle would sit there printing "MADE IT TO TRAVEL" over and over, until the function stack overflows (because you're continuously calling functions without allowing them to return).

If that's not the specific symptom you're seeing… then what is happening?

calls to locArrayIn[1]

You "call" functions, and "index" into tables. Keep that in mind, as a lot of people seem to get confused when certain errors use the terms.

Another thing, you can simplify this sort of construct:

        if currentLoc[1] == startLoc[1] and currentLoc[2] ==startLoc[2] and currentLoc[3] == startLoc[3] and currentLoc[4] == startLoc[4] then
                return true
        else
                return false
        end

If you've established that "currentLoc[1] == startLoc[1] and currentLoc[2] ==startLoc[2] and currentLoc[3] == startLoc[3] and currentLoc[4] == startLoc[4]" resolves as either true or false, and simply want to return either true or false, then:

return currentLoc[1] == startLoc[1] and currentLoc[2] ==startLoc[2] and currentLoc[3] == startLoc[3] and currentLoc[4] == startLoc[4]
Edited on 04 September 2015 - 04:57 AM
lecrouch #13
Posted 04 September 2015 - 04:39 PM
Bomb Bloke, you hit it on the head, the loop that you described is exactly what I am experiencing. Obviously I have some re-structuring to do. In regards to my ugly as sin isAtStart() function, thanks for the advice on how to clean it up!

Cheers again, you rock!

Update:

Set up a flag for if the turtle was already traveling to get fuel, so that it could bypass the refuel loop madness, and it seems to work well. Only issue at the point is when it comes back up to the surface, it tends to travel idiotically back down, i.e. traveling the whole row, going down one, traveling the full row, etc. So I'll post anything that I come up with. The last pastebin link is the most current version. Thanks again!
Edited on 04 September 2015 - 02:42 PM