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

Logic error in my program

Started by Pyro_, 24 May 2013 - 10:28 AM
Pyro_ #1
Posted 24 May 2013 - 12:28 PM
Hi all,

I'm new to the forum, but also to Lua. I have extensive coding knowledge in other languages though, such as C, C++, Java…. so on, I'm sure you don't really care. In recent years I've taken some University (College, for Americans) classes as part of my Comp. Sci.; Comp. Sys. Eng. Double degree relating to all kinds of code structure, code practices, data structures, algorithm design… and what have you. So, my point is, I probably have and idea of what you're talking about if you want to be technical :)/>/>

Anyway, I find Lua a little bit hard to pick up on for the simple reason that it seems a little more like scripting rather than coding oriented language, and it has a fairly lax syntax / structure (no hate please).
So I just started out by writing this simple program that will dig a hole of your dimensions in the ground, and I have hit a logic bug, somewhere, I have commented in the code where I think it is. I'm not sure though, I'd prefer a second set of eyes to have a look at my code. Keep in mind though I plan to repurpose, reuse, refactor, and rebuild these basic sub-modules (sub-routines in Lua?) into more complicated programs later on, so you might see some code that *seems* useless for the implementation at the moment, but rest assured, it will be used very soon, or in rare cases in the current implementation.

So, here's the code, feel free to plonk it into minecraft and give it a try. I think the error is in the portion where it tries to resume it's digging once it has filled it's inventory.

(Probably easier to read in a program with syntax highlighting feature)
Spoiler

-- Will mine a hole in the ground

local tArgs = {...}
-- If incorrect no of args is given
if #tArgs ~= 2 then
print("Usage: hole <side length> <depth>")
return
end

-- Size will be the length of the sides of our square hole
local size = tonumber(tArgs[1])
-- StopDepth is the number of levels we are mining in the downwards direction
local stopDepth = tonumber(tArgs[2])

-- Info about turtle's current position and direction. Note that when the turtle is
-- placed, positive x is directly forwards, positive z is to the right
-- Also note, direction vector components should be mutually exclusive, ie if one
-- holds a value, the other *MUST* be zero
local depth = 0
local xPos, zPos = 0,0
local xDir, zDir = 1,0

-- Will be used to save the position and direction of the turtle when we need
-- to refuel/empty the inventory
local xSav, ySav, zSav = 0,0,0
local xDirSav, zDirSav = 0,0

-- Check if there are any free slots in the inventory space
local function isFull()
for n = 1,9 do
if turtle.getItemCount(n) == 0 then
return false
end
end
return true
end

-- Will dig forwards (if required) and move forwards, will also update position
local function moveForward()
while turtle.detect() do
turtle.dig()
sleep(0.8) -- Gravity blocks
end
-- Update position
xPos = xPos + xDir
zPos = zPos + zDir
turtle.forward()
end

-- Simply moves the turtle down, digging if necessary
local function moveDown()
if turtle.detectDown() then
turtle.digDown()
end
-- Update position
depth = depth + 1
turtle.down()
end

-- Similar to moveDown()
local function moveUp()
if turtle.detectUp() then
turtle.digUp()
end
depth = depth - 1
turtle.up()
end

-- Turn right, update direction
local function turnRight()
zDir, xDir = xDir, -zDir
turtle.turnRight()
end

-- Turn left, update direction
local function turnLeft()
zDir, xDir = -xDir, zDir
turtle.turnLeft()
end

-- This will just dump everything in it's inventory directly infront of it.
local function dumpLoad()
local stackCount = 0
for n = 1,9 do
stackCount = turtle.getItemCount(n)
turtle.select(n)
for i = 0, stackCount do
turtle.drop()
end
end
end

-- This is where the fun begins, this function (should) make the turtle return to the 'Home' corner
-- ie this is the corner that it started in (but it won't take it to the starting depth)
-- This will be used to reset the turtle in order to dig down another level, or before it returns
-- to it's starting point (and depth)
local function returnCorner()
if xPos > 0 then
-- The goal here is to negate the x displacement, the first step is to point it in the negative x
-- direction
if xDir > 0 then
turnRight()
turnRight()
elseif zPos ~= 0 then
if zPos > 0 then
turnRight()
elseif zPos < 0 then
turnLeft()
end
end
-- Then we just move it in the negative x direction until it hits 0 displacement
while xPos > 0 do
moveForward()
end
end
-- Now we repeat the process for the z displacement, first, orient the turtle in the correct
-- direction (negative z)
if zPos > 0 then
if zDir > 0 then
turnLeft()
turnLeft()
elseif xPos ~= 0 then
if xPos > 0 then
turnLeft()
elseif xPos < 0 then
turnRight()
end
end
-- Then move the turtle forward until it hits 0 displacement
while zPos > 0 do
moveForward()
end
-- Rotate the turtle so that it faces the direction it started in (towards the inside of the hole,
-- in the positive x direction)
turnRight()
end
end

-- This is similar to returnCorener, except it will take the turtle back to the starting height also,
-- where we will generally have a chest for it to spew its contents into
local function returnHome()
returnCorner()
while depth > 0 do
moveUp()
end
-- Turn around and empty inv into chest, then turn around again (positive x)
turnRight()
turnRight()
dumpLoad()
turnRight()
turnRight()
end

-- This should save the turtles current position and direction, so that we can
-- move around (eg empty inventory) and come back to where we left off
local function saveDig()
xSav = xPos
zSav = zPos
ySav = depth
xDirSav = xDir
zDirSav = zDir
end

-- This function should return the turtle to the saved coordinates, so that we
-- can continue to dig our hole... But it's broken, I think
local function resumeDig()
-- First, orient the turtle in the positive x direction, so we can adjust for our x displacement
if xDir < 0 then
turnRight()
turnRight()
elseif zDir > 0 then
turnLeft()
elseif zDir < 0 then
turnRight()
end
-- If we started from the home corner, then our displacement will be zero, so our move
-- command becomes a tad more simple, however, if we are inside the hole somewhere for
-- any reason, then we will need to adjust for our current position
if xPos == 0 then
while xPos ~= xSav do
moveForward()
end
elseif xPos > 0 then
local deltaX = xSav - xPos
for n = 1,deltaX do
moveForward()
end
end
-- Orient the turtle in the positive z direction
turnRight()
-- Follow the same logic as we did in x
if zPos == 0 then
while zPos ~= zSav do
moveForward()
end
elseif zPos > 0 then
local deltaZ = zSav - zPos
for n = 1,deltaZ do
moveForward()
end
end
-- We must also account for the depth that we were digging at we, again, use the same logic
-- as x and z, just in the y direction
if depth == 0 then
while depth ~= ySav do
moveDown()
end
elseif depth > 0 then
local deltaY = ySav - depth
for n = 1,deltaY do
moveDown()
end
end
-- Finally, account for whatever direction we were facing when we left off
while xDir ~= xDirSav do
turnRight()
end
while zDir ~= zDirSav do
turnRight()
end
end

-- This finction should dig one complete hole
local function digOut()
-- For every layer we were told to dig, we just need to repeat the same operation,
-- of digging out that layer
for m = 1,stopDepth do
-- This is where we dig out the individual layers, this first nested for loop
-- controls how many colums the turtle will dig (in this case, because we are
-- digging a square hole, it is the same as the number of rows we are digging)
for n = 1, size do
-- This second nested for loop control our digging of one column (along the x axis)
for nn = 2, size do
moveForward()
-- If the turtle is full, we tell it to move to the home position (where it started)
-- which is where it will spew up on the ground, or into a chest if we put one there
if isFull() then
saveDig()
returnHome()
resumeDig()
end
end
-- This controls the turn into the next column at the end of digging the last column,
-- if the column we just dug was the last one, we want to skip this step.
if n ~= size then
if n % 2 > 0 then
-- For odd rows we want to turn right (seeing as we start from row 1 and not row 0)
turnRight()
moveForward()
turnRight()
else
-- And even rows we turn left
turnLeft()
moveForward()
turnLeft()
end
end
end
-- Move the turtle to the home corner, ready for either the next layer, or to go home
returnCorner()
if m ~= stopDepth then
moveDown()
end
end
-- Return the turtle to it's starting point when we are done
returnHome()
end
-- LUA is a weird language, but this is the equivalent of the main() method
print("Beginning...")
digOut()
print("Finished...")

Thanks,
Pyro_
Lyqyd #2
Posted 24 May 2013 - 01:48 PM
Split into new topic.
theoriginalbit #3
Posted 24 May 2013 - 10:19 PM
Hello Pyro_

It will probably be easier if you are to dump future programs into pastebin, the syntax highlighting on these forums is pathetic at best, and is highlighting for C, not Lua (oh joy). And obviously when we have the pastebin program on the CC computers it makes it easier to get it to test :)/> Oh and pastebin also preserves indenting.

As you attend uni and are doing a very advanced course (which actually sounds a lot like mine, content wise) you are probably very used to reading developer documentation, as such, and if you haven't already, to help get a better grasp on Lua if you have a skim of the PIL (since you would understand most of what it covers from uni), the ComputerCraft wiki (for CC specific APIs) and even some of the lua-users.org tutorials.

I have a couple of suggestions before getting onto the problem that I noticed while reading over your code.
  1. Your moveUp function does not take into consideration falling blocks, you may want to add that in, you never know and better safe than sorry.
  2. You have a lot of turnRight() x2 and turnLeft() x2 scattered around, to help readability it might be worth making a turnAround function
  3. One consideration you might want to make when attempting to move the turtle is that it could be out of fuel and/or running into a mob which means it hasn't actually moved and would have thrown off your position tracking
Now to the problem… Well what is the one you're getting? does it just not go back to where it is meant to resume digging?
The problem that I can find is with returnCorner, that is called on each level of digging. It is not turning back to the home direction before attempting to go home, so of course it just runs off into the distance. One suggestion that I could make to make the solution for this easier, is to attempt to make a single function to deal with moving from one position to another, that way you can reuse it for your returnCorner, returnHome, and resumeDig functions, and you know that they will work every time since they are all running the same code (with the difference of start and end coords of course).

Lastly
SpoilerI noticed your comment at the bottom
LUA is a weird language, but this is the equivalent of the main() method
I've actually started to get into the habit of making the programs like so

local function main(argc, argv)
  --# code here
end

main( #{...}, {...} )

— TheOriginalBIT
Lyqyd #4
Posted 25 May 2013 - 12:38 AM
Pastebin is good for longer scripts (>300 lines), but it is far more convenient to look at shorter ones on the forums rather than pastebin. It's much easier for mobile users, and desktop users can copy/paste into their favorite text editor. :)/>
Pyro_ #5
Posted 25 May 2013 - 02:46 AM
Hey,

Thanks theoriginalbit and Lyqyd,

I had forgotten about pastebin (sorry). I did have a look around google, but the most I could find were some bad tutorials on Lua, which none of them related to ComputerCraft, which demands a slightly different coding style than regular Lua. I'll read over the dev doc, API and some of those tuts and get a better feel for Lua with relation to CC, then implement those changes you suggested.

In regards to the problem (heh I forgot to say what it was) it return to home correctly and dumps it's load (sounds wrong, doesn't it?) into the chest fine, but when it tries to resume from where it left off, it just does nothing for some time, then starts mining from the top again… (but it doesn't reset it's depth, so it *thinks* it's on the correct level).

I have to go to a lecture now, but when I get back I'll start working on those changes.

Thanks,
Pyro_
Pyro_ #6
Posted 25 May 2013 - 04:14 AM
This is the pastebin of the original program

http://pastebin.com/77xB7XQe
Bomb Bloke #7
Posted 25 May 2013 - 10:18 PM
While unrelated, the "dumpLoad()" function has a couple of issues:

"turtle.drop()" will dump the entire contents of the selected slot (the full stack) in one go. Calling it once for every item that was in a full stack results in one success and 63 failures. I suspect this may be why the turtle is pausing at the chest for longer then expected.

Furthermore, a loop phrased as "for i = 0, stackCount do" will start counting at 0 and proceed up to (and including) the value of stackCount. In a case of a full stack, that means it goes from 0 to 64, meaning it performs 65 iterations. Though, again, you shouldn't be performing this particular loop at all.

Performing if checks before while checks is often redundant. For example, in the "resumeDig()" function, when trying to go back to the old depth all you need to write is "while depth ~= ySav do moveDown() end". There's no need for all that extra business about checking to see if you should run the while loop, because the while loop's already going to check itself. The "deltaY" stuff is pointless for the exact same reason - the while loop is already rigged to stop at the correct depth regardless as to where it starts. Lines 204 through to 213 can be condensed to one line, and with this in mind you can probably spot the other areas in the program that could use the same attention.

I can't see any reason why the turtle would not return to the correct depth, though. I'd recommend putting some print statements in the resumeDig() function to make sure it's actually getting executed, and to confirm whether the turtle thinks its location is changing.

When you say the turtle "thinks" it's at the "correct" level, do you mean it thinks it's at the level it is (in which case the resumeDig() function definitely isn't getting called properly somehow), or the level you wanted it to be at (in which case the turtle is attempting to move down but failing, as though it were out of fuel or something)?
Pyro_ #8
Posted 27 May 2013 - 11:47 AM
Hey all,

So I finally got around to implementing some of those changes, and for the most part, I've pretty much rewritten the code. This time I've hit a snag in my program again. I think it exists in the digOut() function, at the bottom of the code, because unit tests seem to show that the other functions are working correctly. Anyway, so what happens is that at the end of the current layer that the turtle is digging, it digs an extra 'strip', then at the end of the whole program, it seems to not want to rise the y axis back up to the starting location.

Give it a try and see what the results are for yourself, but basically I'm a little stumped again, and I have a Software Engineering test tomorrow so I can't stay up and debug.

Thanks,
Pyro_

http://pastebin.com/9ajCmarq
theoriginalbit #9
Posted 27 May 2013 - 12:41 PM
Hey Pyro_,

Ok firstly, at least this version of the program gets past the first level for me :P/>

Well this is interesting. This is a 2x2 dig: http://puu.sh/32kgJ.png … very interesting results.

Ok the problem. This is actually an interesting one, I'm not too sure why the loops run in the first place because you're actually giving it strings, not numbers. The runtime args will come in as strings. Just make this one change

size = tonumber(argv[1])
depth = tonumber(argv[2])

Another problem I noticed was on line 244 and 247 you have a typo, you typed 'm' instead of 'n'.

As for that one random extra notch out the side, fixing the above issues also seems to fix that except for the first layer, I'm not too sure why and I have to go to bed after typing this up for the same reason as you, so I can't investigate any more tonight into this problem. Sorry.

A useful tip for the future, the function tonumber can also accept a radix so when presented with a hex string, lets say E, if you do tonumber("e", 16) it will convert it to decimal 14.

There is 1 more observations that I have made that isn't actually breaking the program, but is just a little thing.

Observation: When returning to the corner to start the next level (which btw, bad on fuel usage) the turtle will turn 3 times to the left instead of once to the right, maybe you could put a conditional in to stop that something like, if current facing is target + 1 then turn the turtle right, else turn the turtle left until it reaches the target.

Also I assume you're using a ComputerCraft version that before 1.4? I say this for 3 reasons, there is a lack of fuel checking, there is no attack code for if a mob is detected (turtle.attack, returns boolean on mob presence, should check only if cannot move), and you're emptying 9 slots instead of 16. This last one could be easily made possible by using code like this:

local slotCount = os.version() >= "ComputerCraft 1.4" and 16 or 9
then in your loops

for i = 1, slotCount do
  -- select and drop
end
Note: yes Lua does have a Ternary operator (of sorts) and yes in Lua you can do operators such as < > =< => on strings (crazy right?!)

— TheOriginalBIT
H4X0RZ #10
Posted 27 May 2013 - 01:01 PM
Pastebin is good for longer scripts (>300 lines), but it is far more convenient to look at shorter ones on the forums rather than pastebin. It's much easier for mobile users, and desktop users can copy/paste into their favorite text editor. :)/>/>
Yea, that's right!

And pastebin doesn't on mobiles -.-
Pyro_ #11
Posted 27 May 2013 - 11:12 PM
Hey theoriginalbit,

Thanks for picking up those errors. I didn't even notice that I'd forgotten the tonumber function, I just assumed that the program would fail if there was some kind of type mismatch, apparently not… I'm at Uni all day today until 6pm AWST (Aussie Western standard time, gmt +8) but I'll probably do some more debugging this afternoon. I have a sneaking suspicion that if I split the digOut function into separate functions, like digLayer, digStrip and such, I'll have less dramas. Also, at the moment, I'm more worried about getting the program to a functional state, then I'll worry about fuel optimisation and error handling such as with mobs and refueling and rednet and what not.

Oh yeah, and I'm running whatever version of CC that tekkit currently has implemented. I think it's the one previous to the current release, as tekkit is still on minecraft 1.5.1. I'm still learning the language and api also, so I tend to miss things like turtle.attack (that and I didn't want it to kill me if I accidentally stood in front of it).

Thanks again,
Pyro_
Pyro_ #12
Posted 27 May 2013 - 11:17 PM
Freack100,

Pastebin works fine on my mobile?
What phone do you have?

Pyro_
BigSHinyToys #13
Posted 27 May 2013 - 11:46 PM
Mining scripts sound easy "just use a few for i = 1,bla statements and it should would work fine" but in reality you end up problems like the one you decides about with digging a row too many.

Seeing as you have an interest in algorithms.This is the most compact / simplest mining script I could come up with.
http://pastebin.com/Zba7zE33
Pyro_ #14
Posted 28 May 2013 - 12:18 AM
Hey BigSHinyToys,

I agree, also, it doesn't help that I'm writing a script for a virtual vehicle inside a game on top of a virtual machine inside of an operating system.

Nonetheless, with this particular algorithm, I'm less interested in the result of the program and more interested in the syntax and interface with the turtle API.
SpoilerWarning! Opinion contained within!
SpoilerYour script, while I don't pretend to be a professional software engineer, in my opinion is a little hacker-ish. The code is not really maintainable or reusable, and the coupling and cohesion between and inside of your functions is a little more tight/low than I would code. But I like it's simplicity. :)/>
Thanks,
Pyro_
Pyro_ #15
Posted 28 May 2013 - 09:59 AM
So,

to anybody who's still interested in this thread, I've done some more work on the program.

I seem to have ironed out the bugs regarding digging the actual hole, and I've moved on to adding flags to the program; the program now contains two optional flags,

-s : which is speed mode, so it skips checking for falling blocks (good if you are digging a hole from surface down etc, and know there won't be any falling blocks to get in the way.
-fc : fuel chest, this is a chest that you can place directly to the left of the turtle that contains fuel of some sort, and when the turtle is mining, if it detects it is going to run out of fuel at some point before it can make it back to the fuel chest, it will automatically navigate back to the home location, dump it's current load, and refuel one stack of whatever's in the fuel chest, then continue on where it left off.

It has two save spots, with mutex variables so they cannot be accidentally overwritten, so even if it if currently using a save spot to go and do something, it will be able to preserve that data, refuel, then go back to doing what it was before, without overwriting that save data. This is fairly useless at the moment, until I can figure out how to call the refuel function from the move functions without inducing a paradox (see the note below).

Note, the -fc flag still needs some work, like checking that what it gets out of the fuel chest successfully refuels it, or refuelling the whole chest at once or something, also, the fuel detection algorithm needs some work, as it currently only checks fuel when it's moving forwards, as part of the digStrip function, I originally had planned to have it check fuel in the moveForward/Up/Down functions, but that would require me paradoxically ordering my functions (ie refuel would have to be above the move functions, but then refuel requires the move functions to work, so it would have to be below the move functions). I imagine there is a way of doing this that I'm just not seeing yet, but you're welcome to help :)/>

Thanks all,
Pyro_

http://pastebin.com/E9g2C9hg
theoriginalbit #16
Posted 28 May 2013 - 10:13 AM
Well its good that you're getting it all fixed up and in a working state.

One thing I will tell you, is that in the new versions of ComputerCraft if you do turtle.refuel(0) it will tell you if a particular item is a fuel source without using it up any, you could use this information to sort the turtles spoils into the two chests (fuel and resources).

— BIT
Pyro_ #17
Posted 28 May 2013 - 10:18 AM
Hrm, that's interesting, and probably going to keep me up for a while now ._.

Would you by any chance happen to have any thoughts on the paradoxical ordering of functions at all?

Cheers,
Pyro_
Bomb Bloke #18
Posted 28 May 2013 - 10:20 AM
AFAIK it doesn't matter how you order your functions. I've got a function that calls two other functions, one defined above it, one defined below. Works fine. At least, I'm assuming "position in the source code" is what you're talking about, as opposed to "calling them in such-and-such an order".

On the other hand, I don't declare my functions as "local", and my code doesn't work when I do. Haven't sussed out why as yet.

I can tell you that having the movement functions call the refuel function is a bad idea, at least, so long as the refuel function is calling those same movement functions in such a way that they call the refuel function again and so on until you hit an overflow. Though I get the impression that won't trouble you for long.
Pyro_ #19
Posted 28 May 2013 - 10:28 AM
Ah, I've protected against that with the isRefuelling variable. Having the movement functions check if the turtle needs refuelling seems to be the only safe way to ensure that the turtle doesn't, say, climb 200 blocks and run out of fuel because fuel level isn't being checked when it moves. If you know what I mean?

Also, what do you mean 'not declare as local', ie you just truncate the 'local' construct from the function declaration?
BigSHinyToys #20
Posted 28 May 2013 - 10:29 AM
Your script, while I don't pretend to be a professional software engineer, in my opinion is a little hacker-ish. The code is not really maintainable or reusable, and the coupling and cohesion between and inside of your functions is a little more tight/low than I would code. But I like it's simplicity. :)/>
Thanks,
Pyro_
I have never been formally taught to program so I have never hear of "coupling" and "cohesion" . looking it up I found the wiki .
Coupling (computer programming)
Cohesion (computer science)

I have up till now classified good code as compact and effective. Not knowing OOP that well I have never been in situation where grouping functions into classes was necessary. I write in a more functional style . I guess the combination of those factors leads my code to be unorganized and not coherent.

I thank you for you constructive criticism and will reexamine what I use to define good programing.
Bomb Bloke #21
Posted 28 May 2013 - 10:31 AM
Ah, shoulda spotted that variable sitting up the top there…

Anyway, yes, I use "function somefunction()" instead of "local function somefunction()".
theoriginalbit #22
Posted 28 May 2013 - 10:33 AM
AFAIK it doesn't matter how you order your functions. I've got a function that calls two other functions, one defined above it, one defined below. Works fine. At least, I'm assuming "position in the source code" is what you're talking about, as opposed to "calling them in such-and-such an order".

On the other hand, I don't declare my functions as "local", and my code doesn't work when I do. Haven't sussed out why as yet.
Thats the problem. Lua is a procedural language. This means that a function must be declared before it is called (meaning above all usages in the file). The reason you haven't hit this problem is non-localised functions get loaded into the environment. So this code would not work, getting "attempt to call nil" error.

local function a()
  write("Hello ")
  b()
end
local function b()
  write("World!\n")
end
a()
However this code would


function a()
  write("Hello ")
  b()
end
function b()
  write("World!\n")
end
a()

I can tell you that having the movement functions call the refuel function is a bad idea, at least, so long as the refuel function is calling those same movement functions in such a way that they call the refuel function again and so on until you hit an overflow. Though I get the impression that won't trouble you for long.
Checking the fuel level in the movement functions is actually one of the best ideas, that way you're checking it after each movement and can accurately move around assuming given fuel levels. From the way I assume the refuel function would call the movement functions it would be fine and there would be no stack overflow, as the gotoPos (or whatever it was called) function would be called in the refuel AS long as the refuel surface movement checker isn't constantly called, which is easy to top.
Pyro_ #23
Posted 28 May 2013 - 10:48 AM
Woah, "AS long as the refuel surface movement checker isn't constantly called, which is easy to top." That bit went over my head a little, could you clarify please?

Thanks,
Pyro_
H4X0RZ #24
Posted 28 May 2013 - 10:49 AM
Freack100,

Pastebin works fine on my mobile?
What phone do you have?

Pyro_
HTC Rhyme S510b hourglass
Pyro_ #25
Posted 28 May 2013 - 10:53 AM
That runs Android yeah?

My Samsung Galaxy S4 running Android 4.1.2 Jelly Bean seems to load pastebin fine, but I'm using the Google Chrome browser app.

There is a better browser than Chrome though, search the play store for 'Dolphin Browser'. Trust me, it's better than chrome.
theoriginalbit #26
Posted 28 May 2013 - 10:56 AM
Woah, "AS long as the refuel surface movement checker isn't constantly called, which is easy to top." That bit went over my head a little, could you clarify please?
Its ok, you have already done it with the flag. And I will admit, that was very badly worded, was a little distracted while writing that bit :P/>
Pyro_ #27
Posted 28 May 2013 - 10:58 AM
Haha, I read it a few times and thought… Nah, I'm going to have to ask about that. Maybe he needs a red bull or something :D/>
H4X0RZ #28
Posted 28 May 2013 - 11:02 AM
That runs Android yeah?

My Samsung Galaxy S4 running Android 4.1.2 Jelly Bean seems to load pastebin fine, but I'm using the Google Chrome browser app.

There is a better browser than Chrome though, search the play store for 'Dolphin Browser'. Trust me, it's better than chrome.
I'm using dolphin :)/>

yea, it's android (2.3.5).

Everytime I tried to connect to pastebin, it says "Timeout on Gateway" -.-
Bomb Bloke #29
Posted 28 May 2013 - 11:03 AM
I see… and functions loaded into the "environment" are presumably a bad thing? I'm guessing that means that if the computer stops running that program and switches to a different one, it still has those functions loaded and available for use - at least until such time as it reboots. Would this be right?

That's a poser; it's obviously neater to keep them local, but that means that the movement functions cannot call the refuel function if it calls them in return, full stop.

Well if you can't do it, you can't do it! Perhaps have moveToPos start out by calculating whether it's possible to get to the destination without running dry, and return false without moving if it knows it can't. You can then use lines such as "while not moveToPos(x,y,z) then refuel() end" lower down in your code.

I still don't like your use of "if" statements wrapping around "while" statements that check the exact same thing (eg 180 - 188). Expands out the code and gives the interpretor unnecessary work (however slight), yes?
Pyro_ #30
Posted 28 May 2013 - 11:05 AM
That runs Android yeah?

My Samsung Galaxy S4 running Android 4.1.2 Jelly Bean seems to load pastebin fine, but I'm using the Google Chrome browser app.

There is a better browser than Chrome though, search the play store for 'Dolphin Browser'. Trust me, it's better than chrome.
I'm using dolphin :)/>

yea, it's android (2.3.5).

Everytime I tried to connect to pastebin, it says "Timeout on Gateway" -.-

Try connecting with WiFi turned off, (if you have it on) and vice versa :)/>
Pyro_ #31
Posted 28 May 2013 - 11:07 AM
I see… and functions loaded into the "environment" are presumably a bad thing? I'm guessing that means that if the computer stops running that program and switches to a different one, it still has those functions loaded and available for use - at least until such time as it reboots. Would this be right?

Inside a computer system (Especially Windows) when you close a program, all data associated with that program is destroyed and made available for reallocation by the operating system. So they won't stay there forever, at most they'll only stay there until you close Minecraft. But I'm certain that they would be destroyed when your LUA program ceases to exist.

Well if you can't do it, you can't do it! Perhaps have moveToPos start out by calculating whether it's possible to get to the destination without running dry, and return false without moving if it knows it can't.


The problem is moveToPos is not my main movement function, it's kind of a janitor function that only works when I want to move somewhere specific (like back to home corner etc). For the bulk of movement (like 99%) I just call the moveForward function (my version).
theoriginalbit #32
Posted 28 May 2013 - 11:08 AM
I see… and functions loaded into the "environment" are presumably a bad thing? I'm guessing that means that if the computer stops running that program and switches to a different one, it still has those functions loaded and available for use - at least until such time as it reboots. Would this be right?
Well obviously the environments themselves aren't bad, without environments Lua wouldn't work. But yes, any function that you load, either via an api or in your own program that are not local can be accessed by any program, just like non-localized variables.

Well if you can't do it, you can't do it! Perhaps have moveToPos start out by calculating whether it's possible to get to the destination without running dry, and return false without moving if it knows it can't.
That is normally the best option. Knowing that the turtle consumes 1 fuel each time it moves.


Inside a computer system (Especially Windows) when you close a program, all data associated with that program is destroyed and made available for reallocation by the operating system. So they won't stay there forever, at most they'll only stay there until you close Minecraft. But I'm certain that they would be destroyed when your LUA program ceases to exist.
Local variables and functions are destroyed by the gc only when they are not referenced by anything else. Non-localised variables and functions will persist until the ComputerCraft computer is rebooted.
Pyro_ #33
Posted 28 May 2013 - 11:16 AM
That is normally the best option. Knowing that the turtle consumes 1 fuel each time it moves.

Perhaps I can have a global variable that tracks my current fuel level, the move functions simply decrease it by one every time they move the turtle, and I can have a janitor function that checks if the distance to home is going to be more than my current fuel level?
Bomb Bloke #34
Posted 28 May 2013 - 11:20 AM
Not so simple. Each movement the turtle makes doesn't always take it further away from the refueling point. Some moves will bring it closer.

(Edit: Ooops, misread "fuel level" as "distance". But why setup a global variable to track fuel when odds are a similar level of work is involved in repeat-calling turtle.getFuelLevel()? I mean, one would assume functions such as turtle.forward() etc are already updating a persistent value (one you're not supposed to be able to alter, or you could give yourself free fuel!), and that fuel level function simply returns its value?)

I'd recommend giving the moveForward function the same treatment as I suggested with moveToPos (have it return false if it knows the next move would move it outside of refueling range, and let the calling function deal with it). Or better yet, have both those functions call your suggested janitor function (which'll work so long as it accounts for moves both away and towards the fuel chest).

Regardless, the way I see it, you'll always need to trigger the refueling function from where you attempted to call the movement function.
theoriginalbit #35
Posted 28 May 2013 - 11:21 AM
Perhaps I can have a global variable that tracks my current fuel level, the move functions simply decrease it by one every time they move the turtle, and I can have a janitor function that checks if the distance to home is going to be more than my current fuel level?
Sounds like a plan. turtle.getFuelLevel will return a number of how much it has left, or a string or "unlimited" if it's in the mode that fuel isn't required. However I would suggest something like this (for backward compatibility)

local fuelLevel = turtle.getFuelLevel and turtle.getFuelLevel() or "unlimited"

if fuelLevel ~= "unlimited" and fuelLevel < required then
  -- refuel
end

Not so simple. Each movement the turtle makes doesn't always take it further away from the refueling point. Some moves will bring it closer.
Vectors for current dist, and future dist. that is all.
H4X0RZ #36
Posted 28 May 2013 - 11:22 AM
@Pyro_
Still don't work …
Pyro_ #37
Posted 28 May 2013 - 11:40 AM
(Edit: Ooops, misread "fuel level" as "distance". But why setup a global variable to track fuel when odds are a similar level of work is involved in repeat-calling turtle.getFuelLevel()? I mean, one would assume functions such as turtle.forward() etc are already updating a persistent value (one you're not supposed to be able to alter, or you could give yourself free fuel!), and that fuel level function simply returns its value?)

Ah, this comes back to one of my uni classes, we get right down into code optimisation in said class, and deal with micro and nano seconds. So if it takes microseconds to access the api and get the fuel level, but only nano seconds to decrement a variable, then you should opt for the variable method, memory providing.

Sounds like a plan. turtle.getFuelLevel will return a number of how much it has left, or a string or "unlimited" if it's in the mode that fuel isn't required. However I would suggest something like this (for backward compatibility)

local fuelLevel = turtle.getFuelLevel and turtle.getFuelLevel() or "unlimited"

if fuelLevel ~= "unlimited" and fuelLevel < required then
  -- refuel
end

I already have half implemented this in my current code, have a look in my main function, you should see it in there. I like your idea for backwards compatibility though.

Not so simple. Each movement the turtle makes doesn't always take it further away from the refueling point. Some moves will bring it closer.
Vectors for current dist, and future dist. that is all.

I'm with bit on this one, it's easy enough to just add the components of the vector together to get travel distance, then one logical operation to check if it's greater than or equal to the fuel remaining.

@Pyro_
Still don't work …

Try downloading the Chrome app and see if you have the same problem, that would tell you if it was a problem with your phone, or with the Hardware in your house/somewhere between your house and exchange.
theoriginalbit #38
Posted 28 May 2013 - 11:47 AM
I already have half implemented this in my current code, have a look in my main function, you should see it in there. I like your idea for backwards compatibility though.
Sadly it's something most people don't do, backward compatibility. And for most things it is so easy, so I never understand why they don't do it. Checking function pointers FTW.
Pyro_ #39
Posted 28 May 2013 - 12:01 PM
Hey bit,

Just out of curiosity (and before I go to bed), why in this line of your code:


local fuelLevel = turtle.getFuelLevel and turtle.getFuelLevel() or "unlimited"

do you specify
or "unlimited"
? I know that they are short circuited, so if the getFuelLevel function exis


Derp. I figured it out halfway through the sentence. Yeah, time for bed I think.

I'll reply tomorrow :D/>
Catchyas
theoriginalbit #40
Posted 28 May 2013 - 12:19 PM
Derp. I figured it out halfway through the sentence.
Haha yeh, it's a way to do replicate a ternary in Lua. there is one thing you cannot do with it though, and its something like this with Java

val = <some condition> ? null : <some value>
val =<some condition> ? false : <some value>
in Java val will be set to null or false if the condition is false, in Lua, it looks like this

val = <some condition> and nil or <some value>
val = <some condition> and false or <some value>
and obviously with the way that logical and, and or work it means that val will always be set to <some value> and never be nil or false.

Oh btw, side note that you may know, in Lua a value is evaluate as true, nil is evaluated as false. So

if "hello world" then
  -- code
end
the code inside the if statement will always run. and with

if nil then
  -- code
end
the code will never run as nil is evaluated to false. obviously you would never deliberately make an if statement like that, but you may be returning nil from a function. Also if should be noted that any type of evaluation will only use the first return value of a function. So if you did this

function someFunction()
  return nil, true
end

if someFunction() then
  -- code
end
the code will never run as the first value would evaluate to false, so if you're doing it based off a certain input you would need to capture the return values and then check them

function someFunction()
  return nil, true, "this worked"
end

local idkWhatThisWouldBe, success, message = someFunction()

if success then
  print(message)
end
Pyro_ #41
Posted 28 May 2013 - 09:19 PM
Ahhh. Very interesting to know, thanks bit. So then, are 'nil' and 'false' the only terms which will be evaluated to false? ie in C, '0' is also evaluated as false.

Pyro_
theoriginalbit #42
Posted 28 May 2013 - 11:21 PM
nil and false are indeed the only two that evaluate to false. if you plug the following code in, you will find that it will print 0

print(true and 0 or 'weird')

— BIT
Pyro_ #43
Posted 29 May 2013 - 02:53 AM
Done some more work on the program,

Program now implements fuel checking correctly, (it makes the refuel function load into the environment, the only way to non-paradoxically call it), and checks fuel level every movement. It keeps track of the fuel level in a global variable, and sets said variable in main, before the hole has begun to be dug and also in the refuel function, just after it has refuelled from the fuel chest.

I've also cleaned up the input validation, so that it will now print the command usage if you provide it any invalid arguments.

As for new functionality, it can now dig rectangles, rather than squares, and I've added fuel usage backwards compatability (pre 1.4). Just note that the -fc command becomes useless pre 1.4, as does the home chest.

Next on my list of features to implement:
= EDIT: -sort argument, so that it will sort it's spoils into the fuel chest if the -fc flag has been set, so that it can use mined fuel (like coal) as part of the fuel chest system
= EDIT 2: -help argument that displays help page/s?
= CC version checking and disabling of -fc command as necessary
= Circular holes?
= Rednet -r command, send status updates over rednet (will need to code receiver program too) (I need to research how rednet works first)

Can you guys bug test this for me if you have spare time please? I'd appreciate it alot.

Thanks,
Pyro_

http://pastebin.com/tvxxDNF8
theoriginalbit #44
Posted 29 May 2013 - 03:37 AM
Pyro_,

I will check when home, currently in Software Development for Mobile Devices lecture ;)/>

I really do suggest adding a -help flag.

Also I suggest a slightly better method for checking the flags. Something like this (example from an old project I was working on with someone) [disclaimer: code not written by me, written by NeverCast; code not be 100% working;]
Spoiler


local options = {
  input = "",
  output = "",
  ifmt = "ls",
  ofmt = "cct",
  force = false,
  useKeyframes = false,
  keyframeFrequency = 50,
  live = false
}

for i = 1, #args do
  local arg = args[i]
  if arg == "-if" then
	options.ifmt = args[i+1] or ""
	i = i + 1
  elseif arg == "-of" then
	options.ofmt = args[i+1] or ""
	i = i + 1
  elseif arg == "-f" then
	options.force = true
  elseif arg == "-kf" or arg == "--use-keyframes" then
	options.useKeyFrames = true
  elseif arg == "-kfreq" or arg == "--keyframe-frequency" then
	options.keyframeFrequency = tonumber(args[i+1] or "50")
	i = i + 1
  elseif arg == "-live" then
	options.live = true
  elseif string.sub(arg,1,1) == "-" then
	print(usage)
	return
  elseif options.input == "" then
	options.input = args[i]
  elseif options.output == "" then
	options.output = args[i]
  end	
end
As you can see with the above code it would allow any order on the flags.

— BIT
Edited on 29 May 2013 - 01:39 AM
Pyro_ #45
Posted 29 May 2013 - 04:12 AM
Aha,

I couldn't remember how to do it that way. I could only remember the way I did it :rolleyes:/>
Thanks for bringing it up, I'll get to implementing it now :)/>

Pyro_
H4X0RZ #46
Posted 29 May 2013 - 05:04 AM
@Pyro_
I've downloaded chrome: still not working…
Pyro_ #47
Posted 29 May 2013 - 07:36 AM
@Pyro_
I've downloaded chrome: still not working…

Hrm… If it's not a problem with your router (if you're using WiFi, which we discounted because you switched off WiFi and tried to access the webpage over radio) and it's not a problem with caching (we discounted this by trying a different web browser) then I daresay it might be an issue out of your control.

Have a read up on this article about what a 504 error is: http://pcsupport.about.com/od/findbyerrormessage/a/504error.htm

That should let you know more about what's going on.

Pyro_
Pyro_ #48
Posted 29 May 2013 - 08:13 AM
So bit,

I have another question for you, I'm going to implement that help page, but I know it's going to be more than a page long. So, what I plan on doing is have the user press a key to navigate to the next page, and so on.

Does CC have an IO event driven system, or am I going to have to use polling or similar? I think I've seen somewhere that it does, but I couldn't find any documentation on it.

Thanks,
Pyro_
Bomb Bloke #49
Posted 29 May 2013 - 09:32 AM
Guess you were looking in the IO API?

http://www.computercraft.info/wiki/Os.pullEvent
Pyro_ #50
Posted 29 May 2013 - 09:40 AM
Thanks Bomb Bloke,

That's exactly what I was looking at before, I just couldn't remember where I saw it.
theoriginalbit #51
Posted 29 May 2013 - 11:25 AM
Hey Pryo_,

Sorry I didn't reply earlier. I would actually suggest to use textutils.pagedPrint with this most of the work is already done for you. All you do is supply it a string and it will provide a `scroll` on key press.

As far as CCLua goes for IO models, term is the display output API, the print and write functions are just wrappers for the term and add some extra functionality. read is the input method from the user, it has 2 params, a mask and a table of input history so the user can scroll through them. And when it comes to file IO, to add the sandboxing that CC has (so you cannot modify files outside of the computer, as this would be BAD), the FS api is the main file IO api, and the IO api itself actually just uses the FS api and adds in just different methods of doing things.

— BIT
Pyro_ #52
Posted 29 May 2013 - 11:49 AM
New update,

Bug fixes, also, I added code to print some help pages, should the user request it.
Unfortunately I can't make 'help hole' work without at least running 'hole' once.

So instead, I opted for 'hole help'

Could you guys give me your opinions?

Thanks,
Pyro_

http://pastebin.com/CLuT2Va5
Pyro_ #53
Posted 29 May 2013 - 11:50 AM
Hey Pryo_, Sorry I didn't reply earlier. I would actually suggest to use textutils.pagedPrint with this most of the work is already done for you. All you do is supply it a string and it will provide a `scroll` on key press. As far as CCLua goes for IO models, term is the display output API, the print and write functions are just wrappers for the term and add some extra functionality. read is the input method from the user, it has 2 params, a mask and a table of input history so the user can scroll through them. And when it comes to file IO, to add the sandboxing that CC has (so you cannot modify files outside of the computer, as this would be BAD), the FS api is the main file IO api, and the IO api itself actually just uses the FS api and adds in just different methods of doing things. — BIT

FUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU….

Oh well, it was a learning experience…

Thanks for the info on API's also BIT

Pyro_
theoriginalbit #54
Posted 29 May 2013 - 07:51 PM
Unfortunately I can't make 'help hole' work without at least running 'hole' once.

So instead, I opted for 'hole help'
Only thing I can really say is the any order flags could be useful? and if you wish there is a way to show the help with the name that they called the program (since they don't have to call it `hole`)

local progName = fs.getName(shell.getRunningProgram())


FUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU….

Oh well, it was a learning experience…
Sorry, but I'm sure as you would understand, uni work got in the way.

— BIT
Pyro_ #55
Posted 30 May 2013 - 02:55 AM
Haha,

I know what you mean bit, I wasn't blaming you, but arather that something like that exists, and I didn't think to look for it.

Pyro_