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

Turtle not moving forward, it does have fuel

Started by aradjudge, 09 June 2014 - 11:23 PM
aradjudge #1
Posted 10 June 2014 - 01:23 AM
I am trying to create a program that when executed makes a Mining Turtle dig a mine shaft like quarries do. I want to use a turtle though because I would like to designate how deep it goes. The program that I have so far is only for taking care of the first layer. Then I was going to add in the turtle dropping down a level. At that point I would expect it to execute this program again.


I am self taught on programming and have worked with Lua a bit but still make some beginner mistakes. That is why I always double check my programs through codepad to make sure my coding is correct for Lua. After that I try and double check my programing a few times to make sure all that my ComputerCraft API's are correct. I don't think anything is wrong with how I set up my program… but it isn't doing what I would like it to be doing.

I expect of this program to:

Take the value entered for length
then dig a line at that length
after that turn right dig a space and turn right again
then dig a line at that length
after that turn left dig a space and turn left again
then check a value: if check is true then stop, if false then start again from the beginning.

Here is a paste bin of the code I have that is not working. (yes the turtle has fuel in it) :)/>

http://pastebin.com/3BPTqMaF
Lyqyd #2
Posted 10 June 2014 - 01:34 AM
When you say the turtle "has fuel in it", what do you mean? Placed in the inventory, or actually consumed and converted into fuel points?
aradjudge #3
Posted 10 June 2014 - 01:41 AM
actually converted into fuel points. I had that issue and it drove me nuts. with a little bit of google searching i figured it out though. I really try to search high and low to figure something out before asking on forums.
CometWolf #4
Posted 10 June 2014 - 01:46 AM
You're program is just a bunch of function definitions, which you never call afterwards, hence the turtle not doing anything.
aradjudge #5
Posted 10 June 2014 - 01:55 AM
I have looked at a few "How To's" about functions and I have seen some that I don't fully understand and I have seen example programs that do it just how I did. Which just because its on the internet doesn't make it right.

Could you help explain how I set these functions up and then call them to action so that they do as they are programmed.

Thank You.
Bomb Bloke #6
Posted 10 June 2014 - 02:01 AM
Even if you were to call main() at the bottom of the script, having each function call the next in sequence is a bad practise, and can potentially lead to crashes. Such as in your current configuration (where the script never ends).

The reason why is that when you call a function, the previous function stays in RAM, waiting for the next one to end so it can continue. If none of your functions "end", but rather they just keep making more function calls, then eventually you run out of the memory reserved for functions and the whole thing collapses with a stack overflow.

Try implementing some more "for" loops instead.
aradjudge #7
Posted 10 June 2014 - 02:09 AM
That would not be very good. Could I instead of using functions just encase the whole thing in a "for" loop to set how many time it goes back and forth?
Bomb Bloke #8
Posted 10 June 2014 - 02:29 AM
Yes, indeed you could.

Here's a code snippet which might be useful to you:

if bit.band(x,1) == 1 then

It'll resolve as true if x is an odd number, or false if it's not. Handy if you eg want your turtle to alternatively turn left then right on each iteration of your loop.
aradjudge #9
Posted 10 June 2014 - 03:01 PM
Okay. I took the advice of not using functions and instead used nested "for" loops. This actually seemed to be easier (probably because I understand them more) but I have a couple of things I don't know how to fix. I put a lot of thought getting it the way that it is but it has a couple of tweaks.

It does work but…

1. because it uses the nested "for" loops the d(Depth) "for" loop must count in two's or it will double what ever is given for Depth. This makes it so that the Depth value can only be in even numbers.

Can I make it so that it can be odd as well?

2. The w(Width) "for" loop is also doubled in the code as it goes forward and then back. Effectively making it double what ever the user puts in for Width.

Can this also be made into odd numbers as well?

Also could you break this down a little as I don't understand why each part is as it is, and how I could implement it into the program.

if bit.band(x,1) == 1 then

Could someone also explain functions a little. How to use them and when a prime time to use them should be and like in this example when a bad time to use them would be. Or even just point me in the right direction to a good explanation as anything I search for online goes over my head and uses examples that don't relate to CC.

Here is the Pastebin. I added a few Comments as well to explain what I intended with each piece.
http://pastebin.com/qETiQNes

Thank You Very Much. Without you my program would still not work. haha
KingofGamesYami #10
Posted 10 June 2014 - 03:30 PM

for i = 1, 10 do  --#loop
 if bit.band( i, 1 ) == 1 then  --#statement
   print( i.." is odd" )
 else
   print( i.." is even" )
 end
end
try running this code and see if you understand what it is doing. Another way of doing the same thing:

for i = 1, 10 do
 if i % 2 == 1 then --#using the remainder function, we can see if a number is evenly divisible by two or not.  We can also use it for any other number, such as 3 or 10.
  print( i.." is odd" )
 else
  print( i.." is even" )
 end
end

functions are great when you have a huge project that does a lot of stuff, such as an OS. Or if you call the same code a lot. An example of a useful function:

local function findPeripheral( name ) --#supply this with a valid peripheral name and it will find that peripheral
 for _, side in ipairs( rs.getSides() ) do  --# rs.getSides() returns a table containing all the sides of the computer, "up" "down" "right" "left" etc.  the _ means we are not using that value
  if peripheral.getType( side ) == name then  --# peripheral.getType( side ) returns the name of the peripheral on that side
   return side  --#return returns a value to the caller
  end
 end
 return false --#since return ends the function, this will not be called unless the side isn't found
end

--#now, an example of using this function
local side = findPeripheral( "monitor" )
local mon  --#localize mon, because we don't want to fill the global table up
if side then  --#side will act as true if it is not nil or false
 mon = peripheral.wrap( side )  --#wrap the peripheral, which we know is a monitor
else
 error( "no monitor attached" )  --#error because the user has no monitor attached, and we need one
end
Bomb Bloke #11
Posted 10 June 2014 - 03:51 PM
Another way of doing the same thing:

An important distinction here is that although the result is much the same, getting the modulus is typically slower, and gets slower still as "i" increases.

I guess a place to start reading about how the binary comparison actually "works" would be the CC wiki documentation for bit.band(), though you don't really need to know in order to use it here. Still, feel free to ask if you're really interested.

Anyway, consider this usage:

for i = 1, w do  -- Step-size defaults to 1 if not specified.
	for j = 1, l do 
		turtle.dig()
		turtle.forward()
	end

	if bit.band(i,1) == 1 then
		-- if "i" is odd, turn into the lane to the right:
		turtle.turnRight()
		turtle.dig()
		turtle.forward()
		turtle.turnRight()
	else
		-- if "i" is even, turn into the lane to the left:		
		turtle.turnLeft()
		turtle.dig()
		turtle.forward()
		turtle.turnLeft()
	end
end

You may need to experiment with it a bit, but you can hopefully see how it answers your questions about "needing to travel in twos" - the trick is to do one line per repetition, and use conditional checks to determine how each line should be performed.

Another less elegant method would be to use a dedicated "direction" variable - for example, set it to "true" when turning left, then "false" when turning right, and use its current value to determine where to go on each iteration of your loops.
aradjudge #12
Posted 10 June 2014 - 05:25 PM
You just blew my mind like the recent article I read about how Quantum Teleportation is now possible!

I will work with this new little tid bit you two have bestowed upon me and work it into my code. If I have any more questions I will bring them back here and if everything is working as I planed I will also state so when I finish with this code.

If i understand Binary Comparison currently: As the number gets larger the binary representation of that number would get longer. Hence more to look at.

At what point would this create a significant problem? Would this at any point in CC slow down the server in any way or would it just slow down the turtle itself as it tries to figure out which way it needs to turn?
aradjudge #13
Posted 10 June 2014 - 10:20 PM
Okay so I put the bit.band in and I was all exited for it to work out. I dropped my turtle, ran the program and it started working… and then i was very disappointed and perplexed at the same time.

I took what you guys showed me and entered it manually.(helps me learn it to type it all out as opposed to copy pasting) When i tested the first time I put one's in places that l's should have been. After I looked over it a few times and running it a couple of times. I can not figure out why it is acting in the way that it is.

When I run the program with all three values as five. It digs five in length and it digs five wide. When it reaches the fifth width it goes down as it should. Then it digs one more length and then just stops right there.

Could I get a second pair of eyes to look at the program and see if I missed something?

http://pastebin.com/qETiQNes

Thank You!
Bomb Bloke #14
Posted 11 June 2014 - 12:51 AM
On line 37 you've got an l instead of a 1.

On line 43 you've got a "turt" instead of a "turn".

I'm not sure why you've got lines 9-29 near-identical to lines 31-51.

You might consider breaking out of your "i" loop early on the last iteration, preventing the last lane change. Maybe stick something like this on line 14:

if i == w then break end

Putting an "i" loop (like the width-counter one on line 9) inside another "i" loop (like the depth-counter one on line 8) is technically do-able (due to the way variable scope works in Lua), but I can't recommend it. For one thing, using the same variable name for each makes it very tricky to perform calculations involving the two different values.

Once the turtle's gone down a level, consider making it turn a 180. Then have a think about how adding the current depth counter to the current width counter within your bit.band() checks would affect their outcomes as the turtle descends.
Bomb Bloke #15
Posted 11 June 2014 - 01:05 AM
If i understand Binary Comparison currently: As the number gets larger the binary representation of that number would get longer. Hence more to look at.

Yes and no. Under binary, decimal, hex, whatever - it's true that the number gets longer as it gets larger regardless.

However, when a number is stored in a computer's memory, it pre-emptively sets aside a certain amount of RAM to store that number, and it generally doesn't matter how large the number is - that amount is usually the same regardless, until you start talking about absolutely huge figures. Hence comparison checks between numbers typically take about the same amount of time.

Divisions to determine modulus, on the other hand, do take longer as the numbers get larger. That said, with modern processors you'd have difficulty even detecting the difference until you start dealing with some very large numbers indeed.

At what point would this create a significant problem? Would this at any point in CC slow down the server in any way or would it just slow down the turtle itself as it tries to figure out which way it needs to turn?

ComputerCraft runs code in its own thread, so generally it doesn't matter what your code does, non-CC-related operations on the server will be unaffected.

On the other hand, CC can only run one bit of code at a time. If you place two turtles down and set them off, what's actually happening is that CC is running the code of one until it detects a pause in its execution (say the turtle moves, or the system is waiting for a keypress, or something), then it takes that opportunity to start running the code of the next turtle (switching again when that one pauses).

Again, thanks to the massive amount of power available to the average processor these days, you typically won't notice any slow down until you've got a fair number of computers running at once. However, the more efficient your code is, the more systems you can potentially have going without ill effects.

Note that if any one system runs code for more than ten seconds without pausing, ComputerCraft will assume it's stuck and automatically crash the script involved in order to prevent all the other computers in the world from "locking up" while they wait for it.
aradjudge #16
Posted 11 June 2014 - 03:04 AM
Line 37 and 41 were ridiculous mistakes. They definitely happen though when looking at the same code for a really long time. Kind of embarrassed about it actually.

I trimmed it up, I guess I felt that it had to be doubled so that it would make its way back after going the first way. I see now that is not necessary.

I put the break in and from what I understand it should break the "i" loop for width and then move to digging down and turning around. So if Width was entered as one then it should dig a line drop and then turn around and dig back. When I test this it digs a line turns right and then digs down and turns around digging lines like this:


from the top, getting lower with each line that moves right.
[][][][][][]
  [][][][][][]
    [][][][][][]

Made a new Pastebin with how I changed it. Did i put the break in the wrong place… or am I misinterpreting what it is supposed to do?
http://pastebin.com/uD0s6niq

That is something I will definitely keep in mind about numbers in programming. Also that is an interesting tid bit about CC that I did not know and I will keep that in mind when using CC for large operations. I don't plan on making anything two big right now but my computer lock program is only getting bigger and bigger as I learn more about CC. :D/>

Thank You! again for your help. I hope to be able to contribute back to the forum as I learn more about CC and how it works.
Bomb Bloke #17
Posted 11 June 2014 - 01:12 PM
Must admit I sat down and tested it out before I realised what was causing that one.

"io.read()" always returns a string, otherwise known as a "collection of characters". d, w and l hence get allocated in memory as "text" storing variables, not "number" storing variables.

In some instances, Lua lets you get away with this. If you try to add a number to a string, it'll typically automagically figure out that if the contents of the string represents a number, then you're asking it to add that to the other number, and proceed without complaint. Likewise, when you go to run your "for" loops, Lua is automagically treating your strings as numbers.

In other instances, it doesn't. When you go to check if i == w, it doesn't matter what number i is set to - it'll never be a string, so it'll never match.

Anyway, the solution is to specifically convert the strings to numbers when they're collected, eg:

d = tonumber( read() )

Bearing in mind that "read()" does pretty much the same thing as "io.read()".

Sometimes it can be handy to check what sort of value is in a given variable - the "type()" function can get that info for you. Just for kicks, try running this some time:

print("\"2\" is a " .. type( "2" ))
print("2 is a " .. type( 2 ))
print("print is a " .. type( print ))
print("rednet is a " .. type( rednet ))
print("asdf is " .. type( asdf ))

Anyway! That leaves only a couple more issues in your script. :)/>
aradjudge #18
Posted 11 June 2014 - 06:06 PM
I will have to make sure that I use tonumber() for now on with numbers. One of those things to just do in good practice to not relay on "automagic" to get the job done.

What is the difference between read() and io.read()? I have read in some places that they do the exact same thing and I have heard people say that they do close to the same thing.

I played around with the type() function and that will be a handy tool for double checking what I want to have or use and what I am really getting. I understand it except for why in the first line you put …("\"2\" is a "… why all the slash marks as apposed to …("2 is a "…? Also what is the significance of the ..? I tried a couple out for myself and quickly found that without the .. it did not work. I would suppose that is because it is within the print function and that in so many words breaks it out… or somehow signifies that a value should be placed instead of printing type(). if you could explain that a little though please.

For the program:

I added in the tonumbers() which worked out very well. My code was complete and ready to go. In test though I found that on its last run for depth it would skip digging another width because it had reached its number and it would break out. It would still dig one more down and turn around though. With all that you have taught me I quickly dropped a 'if x == d then break end' right above that. I thought that this would be all ready to go and I tested it and got very excited… only to be disappointed later. I tested it the first time with an odd number for width which works just fine. Later realizing that even numbers still staircase.

The program does everything right on odd widths because it alternates turns and with the 180 brings it back. If ending on an even though it drops and then continues to the right. creating this staircase effect like before. I tried playing with this a bit. Even tried to create a couple of functions that would get called to correct this error but they all failed to current the problem. There has to be a way to fix this but I have no idea how to do it. I will continue to experiment and see what I can find.

I also had another question about CC. If I throw a turtle into the world and set it to work. I hang out and it works just fine of course. What would happen, if anything if I left the area? If the chunk that it is working in is no longer loaded for me or anyone on the server will it keep running? Does the turtle keep it loaded?

I'm pretty sure this is the same Pastebin address but wanted to throw it in because I have been pretty good about dropping it in my posts each time and didn't this last time.

http://pastebin.com/uD0s6niq
KingofGamesYami #19
Posted 11 June 2014 - 06:15 PM
.. adds two strings together

astring = "hello"
anotherstring = "world"
combinedstring = astring.." "..anotherstring --#this is the same as "hello world"

Edit: also works on numbers, forgot to mention

"hello "..2 --#hello 2

The turtle will not load the chunk. The program will terminate undetectably. This is a major frustration for a lot of people, which is why I am making/have made/am trying to make/failing at making a progress api. If there is a chunk loader in the area, or another player, it will continue to work until the chunk unloads. However, when the chunk loads again after being unloaded the turtle will run the startup script, not whatever it was doing.
Edited on 11 June 2014 - 04:19 PM
Lyqyd #20
Posted 11 June 2014 - 06:27 PM
io.read calls read without any arguments, so character masking and command history features are not available when using io.read.
Bomb Bloke #21
Posted 12 June 2014 - 02:58 AM
I understand it except for why in the first line you put …("\"2\" is a "… why all the slash marks as apposed to …("2 is a "…?

In Lua (and indeed in a lot of languages), if you place a backslash in a string it's treated as an "escape" character. This means that the following character is to be treated in a special way.

Say you want to print a quotation mark. Catch is, you use quotation marks to signify the start and end of what you want to print! Try running this and see how far you get:

print(""")

The quote is one of those characters that can be escaped, and in this case doing so tells Lua that you actually want to represent a quotation mark within the string. Eg:

print("\"")

\n is another common usage of the escape character - that indicates that you want to perform a line break. Given how quotes are treated, you can probably guess what to do if you want to put an actual backslash within your strings.

I tested it the first time with an odd number for width which works just fine. Later realizing that even numbers still staircase. The program does everything right on odd widths because it alternates turns and with the 180 brings it back. If ending on an even though it drops and then continues to the right. creating this staircase effect like before. I tried playing with this a bit. Even tried to create a couple of functions that would get called to correct this error but they all failed to current the problem. There has to be a way to fix this but I have no idea how to do it.

Consider: At present, the turtle travels along a pattern where for each layer it will turn right/left/right/left/etc. That's fine for an odd width, but not for an even one - in an even situation, it'd need to do one layer according to the right/left pattern, the next according to a left/right pattern, then back to right/left, and so on downwards.

Now, you could expand out the turning check to determine whether or not the width is even or not, and if it is, then add the current depth counter to the current width counter when performing the bit.band() check to determine direction. This would achieve the desired effect, but the code would be a bit lengthy and ugly.

(Well, without a ternary, but let's not get into those yet.)

What I'd suggest is to wait until the end of each layer, then check to see if the width is odd. If it is, then do the usual 180 and continue, but if not, then turn just 90 degrees and switch the width and the length of the shaft around. This then makes the right/left pattern viable for all layers.

The code would look like this:

		turtle.digDown()
		turtle.down()

		if bit.band(w,1) == 1 then
			-- Width of the shaft is odd, carry on as before:
			turtle.turnRight()
			turtle.turnRight()
		else
			-- Width of the shaft is even; change the orientation of the dig:
			turtle.turnRight()
			local temp = w
			w = l
			l = temp
		end

By the way, on line 10 you're really wanting to bear in mind that the turtle already starts inside the first block of each lane, and therefore only needs to dig out length - 1 blocks from that point:

                        for j=1, l - 1 do

If the chunk that it is working in is no longer loaded for me or anyone on the server will it keep running? Does the turtle keep it loaded?

KoGY mostly has this covered, but usually the answer is to build and place a dedicated chunk loader in the area. In fact, depending on the mods you've got available, in some cases it's possible to integrate a chunk loader module into the turtles themselves (in a similar way to how you craft them together with crafting tables and pickaxes and so on).

In many circumstances, the GPS API can be invaluable when coding turtles that can restart themselves after eg a server reboot. Unfortunately it's not all that useful unless you're dealing with a "fully automated" turtle - eg, one which harvests the same farm over and over again (and so has cause to return often to a certain location in the world anyway, and doesn't really care about what it was doing when the reboot happened specifically), as opposed to a digging turtle, which is unlikely to ever mine out the same shaft more than once and needs to know exactly where it was up to when the restart happened.
aradjudge #22
Posted 12 June 2014 - 06:43 AM
That totally makes sense about the backslash. I think if I had paid attention a little more I would have seen that there were Quotes around the 2 when printed. :rolleyes:/>

I put that code in and of course it works amazingly. I tried something similar to that in a few different ways. Never would I have ever thought to trade l and w and to make only the 90 turn as apposed to the 180.

I did a little research on ternary's. I have no idea how they would be used. From what I read though like the bit.band only giving two possible results a ternary could give three. For this Program it would make it possible to have the third option within the width for statement instead of it being on the outside and separate. Right?

How are ternary's used? If you don't mind breaking that down for me.

As far as the chunk loading going that is pretty lame. I'll just have to hang out in the area. Which isn't to big a deal. If anything it allows me to be a little more proactive IRL while it digs out areas for me. :D/>
Bomb Bloke #23
Posted 12 June 2014 - 07:18 AM
How are ternary's used? If you don't mind breaking that down for me.

These articles have pretty good explanations as to what a programmer's ternary is and how / why you might use one, but you may need to brush up on boolean logic before it makes sense as to how it works. It's indeed a way of compressing down your code.

As a quick example, say you had four pages of information, and two buttons: One which went forward a page, and one which went back. You might code things along these lines:

local curPage = 1

while true do
	-- Draw the current page...
	
	-- Wait for a button press...
	
	if backButtonWasPressed then
		page = page - 1
		if page < 1 then page = 4 end
	end
	
	if forwardButtonWasPressed then
		page = page + 1
		if page > 4 then page = 1 end
	end
end

Ternaries could shrink it like so:

local curPage = 1

while true do
	-- Draw the current page...
	
	-- Wait for a button press...
	
	if backButtonWasPressed then
		page = (page == 1) and 4 or (page - 1)
	end
	
	if forwardButtonWasPressed then 
		page = (page == 4) and 1 or (page + 1)
	end
end