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

A tricky trick or two, for lua and CC

Started by ChunLing, 22 October 2012 - 01:57 AM
ChunLing #1
Posted 22 October 2012 - 03:57 AM
Are you tired of writing "turtle.[command]()" a dozen times to get your turtle to do some bit of maneuvering? Think you can't use a loop because there isn't a repeating pattern to the commands you're using?

There is an easier way! You can access functions contained in tables (like the turtle API) by the lua table indexing methods. Instead of writing "turtle." a dozen times, put the string indexes of the functions in a table and then use a loop.
local t_commands = {"forward","forward","turnLeft","up","forward","turnRight","place","placeDown",
"turnLeft","forward","forward","attack","attackDown","dropUp","forward","placeUp","turnLeft","down",}
for i,v in ipairs(t_commands) do turtle[v]() end
Run this code, and your turtle will run around acting pretty stupid for a bit. But the point is that we have accomplished in a few lines what would otherwise take quite a lot of lines.

This makes it far easier to look over the sequence of commands and see that they are right, without the same danger of "code fatigue" that makes every line starting with "turtle." and ending with "()" look identical.

The reason that this trick works is because turtle.forward() is just another way of saying turtle["forward"](), and the same is true for every turtle command.
KaoS #2
Posted 22 October 2012 - 05:18 AM
good idea there. just a little advice that may come in useful:

never forget to use ipairs not pairs in the for loop. it is correct above but thought I'd remind you

you can also include a way to do the same command multiple times easily


local t_commands = {2,"forward","turnLeft",3,"up","forward","turnRight","place","placeDown","turnLeft","forward","forward","attack","attackDown","dropUp","forward","placeUp","turnLeft","down",}
local count=0
for i,v in ipairs(t_commands) do
  if type(v)=='number' then
    count=v
  elseif count>0 then
    for done=1,count do turtle[v]() end
    count=0
  else
    turtle[v]()
  end
end

if you include a number before a command then it will execute the next command that many times and it does not expect the number to always be there so you do not have to clutter up your code with 1,cmd,1,cmd etc
ChunLing #3
Posted 22 October 2012 - 05:23 AM
That method also works for passing parameters to the turtle commands that need them. I mean, not that exact method, but something similar. But relatively few of the turtle API functions need parameters, while repeating moves while maneuvering about is pretty common.

"in pairs" v. "in ipairs" tip for the day, if you have a sequential table that needs to be traversed in order, then use "in ipairs". Use "in pairs" for non-sequential tables that do not need to be traversed in any particular order.
ElvishJerricco #4
Posted 22 October 2012 - 06:22 AM
good idea there. just a little advice that may come in useful:

never forget to use ipairs not pairs in the for loop. it is correct above but thought I'd remind you

you can also include a way to do the same command multiple times easily


local t_commands = {2,"forward","turnLeft",3,"up","forward","turnRight","place","placeDown","turnLeft","forward","forward","attack","attackDown","dropUp","forward","placeUp","turnLeft","down",}
local count=0
for i,v in ipairs(t_commands) do
  if type(v)=='number' then
	count=v
  elseif count>0 then
	for done=1,count do turtle[v]() end
	count=0
  else
	turtle[v]()
  end
end

if you include a number before a command then it will execute the next command that many times and it does not expect the number to always be there so you do not have to clutter up your code with 1,cmd,1,cmd etc

pairs works just fine. You just get all keys instead of just number keys.
KaoS #5
Posted 22 October 2012 - 06:24 AM
except that it does not always get the order right. it would work in this case I think but it is always better to be safe
ChunLing #6
Posted 22 October 2012 - 08:35 AM
It would only probably work, not for sure. the pairs function iterates across the table according to it's allocation information rather than index, and while usually a table that is allocated in one go will be in order, this is not necessarily true, and depending on the implementation could be entirely false.

And the whole point of the table was to perform the actions in order.
Cloudy #7
Posted 22 October 2012 - 09:45 AM
Instead of using ipairs you should use
for i = 1, #tab do turtle[tab[i]]() end

Two reasons: ipairs is deprecated, and it's speed is low (hence the deprecation).
KaoS #8
Posted 22 October 2012 - 10:16 AM
ah :)/>/> I didn't know it was slower… that sucks. okay, corrected code:


local t_commands = {2,"forward","turnLeft",3,"up","forward","turnRight","place","placeDown","turnLeft","forward","forward","attack","attackDown","dropUp","forward","placeUp","turnLeft","down",}
local count=0
for i=1,#t_commands) do
  if type(t_commands[i])=='number' then
	    count=t_commands[i]
  elseif count>0 then
	    for done=1,count do turtle[t_commands[i]]() end
	    count=0
  else
	    turtle[t_commands[i]]()
  end
end
jimmio92 #9
Posted 22 October 2012 - 10:53 AM
If you don't mind specifying the times everytime.. you could do this:

local t_commands = {2,"forward", 2,"turnLeft", 2,"forward", 2,"turnRight"}

for i=1, #t_commands, 2 do
	for x=1, t_commands[i] do
		turtle[t_commands[i+1]]()
	end
end
ChunLing #10
Posted 22 October 2012 - 08:48 PM
Crap, I started using ipairs instead of i=1,#table because it looked cool, now it turns out it is slow and obsolete? Stupid ipairs making me waste time… :)/>/> .

Actually, because you can do maths on i in an iterative loop, you can have the program read the next value and jump ahead easier and faster than with ipairs. So you can support passing a numeric parameter or an iteration value easier (or both, if you make it so that when two numbers are in a row one is the iterations and the other is the argument).
ChunLing #11
Posted 28 October 2012 - 01:42 AM
Okay, here's the second trick. All of yous wanting to know all about events and stuff, you don't need to ask the Pros dat.

Just open up your lua (or edit in a file to run) and type:
repeat t_event = {os.pullEvent()} print(textutils.serialize(t_event)) until t_event[2] == "X"
All this does is loop around and pull all the events, then print out the event in a lua format. If the event is from peripherals or whatnot doesn't matter, if it's an event pulled by os.pullEvent() it gets printed and you see exactly what kinds of values are in the event.
Shazz #12
Posted 28 October 2012 - 02:01 AM
Instead of using ipairs you should use
for i = 1, #tab do turtle[tab[i]]() end

Two reasons: ipairs is deprecated, and it's speed is low (hence the deprecation).

That won't work with tables indexed by text/strings, right?
Kingdaro #13
Posted 28 October 2012 - 06:43 AM
except that it does not always get the order right. it would work in this case I think but it is always better to be safe
Pairs goes through the table as elements of it are defined. If the index "3" is before "2", it'll print the third index and then the second. However in this case, when an index is not given in a table, it will always default to the previous index plus one.

In other words, if you define table elements in order, pairs will go through them in order.
ChunLing #14
Posted 28 October 2012 - 06:54 AM
For non-sequential tables, you need to use pairs. But ipairs didn't work for non-sequential tables either, I started using it instead of for i=1,#table do … end because I figured there had to be a reason it existed. But I guess I was wrong, not everything exists for a reason. Or, to put it demotivationally, "It could be that the purpose of your life is to serve as a warning to others."
billysback #15
Posted 28 October 2012 - 08:08 AM
For the discussion between ipairs being slower than pairs;
http://facepunch.com...ad.php?t=875909

this experiment shows the comparisons of speed between the two at different sizes of tables; It seems to portray that for smaller tables ipairs is faster however for much larger tables pairs begins to become more efficient.

Also, if you look down the thread there is a new graph which suggests that a for statement is the fastest way to parse a table.
Spoiler
ChunLing #16
Posted 28 October 2012 - 09:25 AM
Yeah, iterative for should be the cheapest in terms of raw calculations required, that's why I always used it initially. But I thought there had to be a reason for ipairs (I mean, obviously pairs lets you traverse tables that an iterative for wouldn't handle well). But nope, apparently not.