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

lua cc christmas light operator

Started by Karaktar, 04 October 2012 - 09:05 PM
Karaktar #1
Posted 04 October 2012 - 11:05 PM
ok so what im trying to do is write a program that blinks the lights in different ways however i cant get it to do all the lights at the same time im using the redpulse instead of rs.setoutput because its less work and can blink
anyway here is my code its my first full attempt without borrowing from others i think i have it right cept the doing all sides I'm not sure how

local red="redpulse"
local r="right"
local l="left"
local b="back
local t="top"
local f="front"
while true do
if rs.getInput(f) then
shell.run(red,l,1,.5)
shell.run(red,b,1,.5)
shell.run(red,r,1,.5)
shell.run(red,t,1,.5)
shell.run(red,lbrt,2,.5)——-this was my first attempt at doing all it didnt work
end
sleep(0)
end


thank you for any and all help

ps im not sure how to post this as code this is my first post
OmegaVest #2
Posted 04 October 2012 - 11:20 PM
Against my normal arguments, I'm just gonna give you some code, and try to explain it afterward.


bOn = true
for k,v in pairs(rs.getSides()) do
   rs.setOutput(k, bOn)
   bOn = not bOn
end

So, some explanation.

The variable bOn is simply a boolean which signifies whether the blink is in the on state or the off state. You could also make this a table, using the loop I am about to explain.

The for loop is actually generic in construction, but the variables used are important. K and V are the index and content of a single "line" of a table (here rs.getSides, which lists all the sides available). So, when it comes to left, k is "left" and v is the data value associated with the left side, usually a jumble of numbers and letter (called a pointer, I think).

So, we can call k and v as necessary to do certain things, such as create a table with similar indexes, like

bOn[k] = true

Then the rest is simply changing the boolean to its opposite (ie. bOn is now equal to not bOn, so true would become not true, which is false).

I know you used the redpulse, but this is really much simpler, especially since you can put your own sleep in it, or after it.

I have more lesson, but it's been a long day, and I forgot most of what I was about to say.
Cranium #3
Posted 04 October 2012 - 11:26 PM
First of all: Welcome to the forums! We hope to see some really neat code from you in the future.
Second, that's not exactly how code works. You are trying to use shell.run cor everything, which CAN work, eventually, but it is far from ideal. In your example:

shell.run(red,lbrt,2,.5)
I assume you want all of the sides to flash twice, with half second intervals, right? I am going to continue assuming you are.
What you want for this whole thing, is to use your own program code, instead of shells. Shells just add more and more programs. We don't want that. We want to call functions, variables, and tables. We can learn about the more complicated things later.
Say for example, you want to flash out of the right side, five times, with half second intervals. We are wanting this code to go with it:

for i = 1,5 do --this will start a loop, and will run five times
    --1 is the starting point, 5 is the end point
    rs.setOutput("right",true) --this will set the output on the right side ON
    sleep(.5) --this will stop for half a second
    rs.setOutput("right",false) --this will turn off the signal on the right
    sleep(.5) --again, waiting half a second
end --ending the loop we created
I have added comments, (which start with a – in lua, always) that should explain what each part of the code does.
You're new here, so you should use the wiki a bit to get your footing, and check out the useful tips and resources thread that is stickied at the top of the Ask a Pro section. There are some great tools to help you learn how to use ComputerCraft.
Again, welcome to the forums, and Happy Hacking!
Karaktar #4
Posted 04 October 2012 - 11:28 PM
um okay im not sure i follow that completely but thank you omega for your time
Karaktar #5
Posted 04 October 2012 - 11:35 PM
hmmm thanks cranium i guess i was hoping it would be easier then that lol it appears i have alot of typing ahead to get this to work right
oh and yeah im been skulking around here for a while learning as much as i could about lua i used to program in basic and extended basic like many years ago and lua is semi familar but im old and forgetfull

also i guess i shouldnt be too suprised that shell.run is using programs instead of functions would it perhaps be easier to write an api for the functions i need then implement that instead ( i know that wont help me atm with less code lol)
Fatal_Exception #6
Posted 04 October 2012 - 11:49 PM
Don't worry too much about an API yet. If you find yourself writing many programs that use the same functions, then it might be useful to separate them out. Otherwise you'll spend all your time writing APIs for things you'll never use again.
Karaktar #7
Posted 04 October 2012 - 11:55 PM
ok thanks no one more question is there an rs.setouput var that does all sides
or at least multiple sides at once or do i need to type out each side and have it run them as one?
Karaktar #8
Posted 05 October 2012 - 12:01 AM
what i mean is as you can see i tried to compress the code as much as possible as it would not just do a loop but grow as i went to light up in a design in my code right now you can see i started with a cycle then went to a flash and was thinking maybe a reverse cycle then i dont know i was going to go from there so for the size this program is gonn be at the end perhaps a api would be better or as is why i went with redpulse instead of just rs.setoutput so basically i think im back to square one maybe?
Cranium #9
Posted 05 October 2012 - 12:10 AM
You can use the function I have here:

local sides = {"left", "right", "front", "back", "top", "bottom"}  --this is how tables are defined in lua
function lights(side)  --how functions are defined
rs.setOutput(side, true)
sleep(.5)
rs.setOutput(side, false)
sleep(.5)
end
--call back to it like this:
for i = 1, #sides do
  lights(sides[i]) --calling back to the table created, with the index changing each time it goes to a new number.
end

You can define patterns using the function I have provided.
Karaktar #10
Posted 05 October 2012 - 12:14 AM
ok i think i understand but if its not to much trouble could you explain a little further i.e.
if using your function code i do
lights(sides)

this will send redstone to all sides in the table or no

and if true

then using same table can i all just one side at a time too?
Cranium #11
Posted 05 October 2012 - 12:20 AM
Yes, the i represents the index number of the table we are referencing. It is also defined as the iterator of the for loop. So as the loop repeats, that number will start from 1, then end at 5. You can change it so it will be for i = 2,3 do, it will only do starting at number 2 (right) and ending at number 3 (front). You can also define in a very long string of rs.setOutput()'s, in a row, basically giving it a script to follow. (This is very apt, because lua is a scripting language after all). You can completely dispense with the for loop, and make a long list of commands to follow. Put that in a never ending loop, and you have a repeating christmas lights display.
BrolofTheViking #12
Posted 05 October 2012 - 12:21 AM
EDIT: Well, Cranium answered far better than I did while I was typing, so this post goes to nothingness.
Karaktar #13
Posted 05 October 2012 - 12:24 AM
oh but wait sorry i just want to be clear so using i will make it light all sides at the same time after which i could define a delay or whatever and or also define a seperate table with delay times and add that to the program to make it change delay sets at varying points in the code ?

edit if thats true this is so much easier then old basic lol
Cranium #14
Posted 05 October 2012 - 12:26 AM
I reread yout post, and noticed something. Did you mean that lights(sides) is supposed to turn them all on? Because alone, it's not. It has to reference the index of the table sides, which is defined here as i. i is only defined by the for loop.

EDIT: I see that's exactly what you meant. We need to define i, or we would have to do lights(sides[#]), where you would put the number instead of "#".
Karaktar #15
Posted 05 October 2012 - 12:28 AM
yes cranium thats what i mean i want to turn all sides on at the same time then cycle through them then i dont something else im guess the table wont work for that
Cranium #16
Posted 05 October 2012 - 12:41 AM

function lights(side,delay)
  rs.setOutput(side,true)
  sleep(delay)
  rs.setOutput(side,false)
  sleep(delay)
end
This would be what you are looking for. You see we added another argument to the function lights(). This allows you to plug in the side you want, and the delay you want. That way, you can choreograph the timing, and the sides.
Example usage would be:

lights("right",.5) --right side, half second intervals
--OR--
for i = 1,#sides do
  lights(sides[i],.5) --we are defining i, and for each time it repeats, switching to another color.
end
Karaktar #17
Posted 05 October 2012 - 12:47 AM
ok so for all lights on at once i would do

lights("right",.5)

then repeat that line with diff sides for each light after to make them all come one at once with that delay ?
Cranium #18
Posted 05 October 2012 - 01:00 AM
well, with the function, they would come on, then turn off. To have them all on at once, simply do this:

for i = 1,#sides do
rs.setOutput(sides[i],true)
end
That will turn them all on, with no delay. Put that in a separate function, and you can call back to it.
Fatal_Exception #19
Posted 05 October 2012 - 01:06 AM
So you want to pulse multiple sides simultaneously, instead of one after the other?

local function redpulseMultiple(sides, count, period)
  for i = 1, count do
	for k, v in pairs(sides) do
	  rs.setOutput(v, true)
	end

	os.sleep(period / 2)

	for k, v in pairs(sides) do
	  rs.setOutput(v, false)
	end

	os.sleep(period / 2)
  end
end

Works just like the redpulse program, only it takes a table of sides instead of a single side.

local sides = {"left", "right", "top"}
redpulseMultiple(sides, 5, 1)
pulses left, top, and right every second for 5 seconds.
Karaktar #20
Posted 05 October 2012 - 01:15 AM
apploigise for my ignorance but now if i understnd that correctly what your saying is the statment

lights("right",.5)

will make them all come on in order like 1=on 1=off 2=on 2=off
or would it be more 1 on 2 on 3 on 4 on 5 on all off
and if that true nad your next statement is correct thi could make that a function would it have delay or would i need to define that as well in a function ?
Karaktar #21
Posted 05 October 2012 - 01:18 AM
i appoligise for my poor grammar

sorry for my lack of good grammar
Karaktar #22
Posted 05 October 2012 - 03:31 AM
ok so this is what i got so far but im not sure how to expand it when i try i get errors

local sides = {"left","back","right","top"}
function light(side,delay)
   rs.setOutput(side,true)
   sleep(delay)
   rs.setOutput(side,false
   sleep(delay)
end
sleep(0)
while true do
  if rs.getInput("front") then
for i = 1, #sides do
   light(side[i],.5)
  end
end
sleep(0)
end

i tried doing this

for y = 2,4,1,3, #sides do
   light(side[y],.5)

however this just messed up both y and i and so the light blinking was random

i think though i am not sure that it might have done them both together at the same time

anyway im trying here sorry to be a pain
Karaktar #23
Posted 05 October 2012 - 03:37 PM
iv been relooking at this and to me it appears the for startment creates a localized loop but im not sure so what im wondering is if i lose the for and just put i = 1, #sides do
will it still work i can't test this right now i have to goto to work but im thinking doing that and added a sleep in between my 2 statements above could solve the problem and allow it to do one then the other i really hope i am making sense
Cranium #24
Posted 05 October 2012 - 04:52 PM
You want it all to stay on, and then to flash ad specified intervals. I assume you want the lights to flash at random, because that's what real christmas lights seem to do. Easy.

local sides = {"left", "right", "back", "top"}
local function lights(delay)
  if not delay then
	for i = 1,#sides do
	  rs.setOutput(sides[i], true)
	end
  else
	local rand = math.random(1,4)
	rs.setOutput(sides[rand],true)
	sleep(delay)
	rs.setOutput(sides[rand],false)
	sleep(delay)
  end
end
local function display(side,delay1,delay2)
  rs.setOutput(side,true)
  sleep(delay1)
  rs.setOutput(side,false)
  sleep(delay2)
end
lights()
sleep(2)
while true do
  local event, p1 = os.pullEvent()
  if event == "redstone" then
    if rs.getInput("front") then
	  local x = math.random(1,4)
	  display(sides[x],.5,.5)
	end
  end
end
The lights here will turn on(after receiving a redstone signal to the front), wait 2 seconds, then start to flash at random with half second intervals.

Edit: I said easy, but I see that I totally just threw a whole bunch of new things at you without thinking… :(/>/>
  1. We did add "os.pullEvent()"
    1. This will stop the script, and wat for an event (such as a redstone signal)
  2. Once it receives the required event, it will check for the input to the front.
  3. If it is on, then it will start to flash at random.
    1. We use a random number generator (math.random()) to generate the index number for our table containing our sides.
    2. Our table is referenced back to using sides[x], where anything we put in the"[ ]" will be a NUMBER referencing the number in the table we want. Since x is being defined by math.random, being between 1 and 4, (the numbers we seeded into the "( )")
  4. We call back to display() by using the sides[x] as the side, .5 being the first delay, and .5 being the second delay.
  5. Since this is all in a "while true do" loop, It will continue to flash.
Karaktar #25
Posted 05 October 2012 - 09:21 PM
think i understand this right now lets say i want to add my own squenence after the random one that is going to do something special

could i do

display(sides[2,4,3,1,4,2,3],.5,.5)

would that work or do i need to use


y = (2,4,3,1,2,4)
display(sides[y],.5,.5)

like that
Cranium #26
Posted 05 October 2012 - 10:09 PM
You would want to call back to display separately in a script. Like this:

display(sides[1],.5,.5)
display(sides[3],.25,.5)
--etc...
You can only add one number in the "[ ]" at a time, unless you are adding a math function, like some variable + some number. ([i+4])
For each time you want the change, you need a new function call. (at least in this instance…)
Karaktar #27
Posted 05 October 2012 - 10:34 PM
ok so i tried that code but heres the problem it only does random light on if i keep turning the front input on and off if i just change it to on once they all come on and stay forever if i turn it off then on one light goes out i hope that made sense
also while typing this code in i noticed somthing odd you have set 2 vars to math.random(1,4)

rand and i not sure why or if that might be the problem otherwise it seems to look like it should work but doesnt and no im not getting any errors so the code is right just not getting my desired output
Cranium #28
Posted 05 October 2012 - 10:42 PM
Wow. Run on sentence…..
I think you are wanting the lights to all be on, but on ONE redstone signal, they should be flashing? I can fix that:

local sides = {"left", "right", "back", "top"}
local function lights(delay)
  if not delay then
	    for i = 1,#sides do
		  rs.setOutput(sides[i], true)
	    end
  else
	    local rand = math.random(1,4)
	    rs.setOutput(sides[rand],true)
	    sleep(delay)
	    rs.setOutput(sides[rand],false)
	    sleep(delay)
  end
end
local function display(side,delay1,delay2)
  rs.setOutput(side,true)
  sleep(delay1)
  rs.setOutput(side,false)
  sleep(delay2)
end
lights()
sleep(2)
local event, p1 = os.pullEvent()
if event == "redstone" then
  if rs.getInput("front") then
    while true do  --infinite loop starts here.
	   local x = math.random(1,4)
	   display(sides[x],.5,.5)
    end
  end
end
In this example, we just moved where the infinite loop starts, marked with the note.
When using math.random, you can define several variables to it. This link might help explain better than I can: http://lua-users.org/wiki/MathLibraryTutorial
Essentially, you use the first variable as the minimum, which we want as 1, the second variable the maximum, which we want as 4. You can use just the maximum, but I got into the habit of using min and max.
Hope that helps!
Karaktar #29
Posted 05 October 2012 - 11:03 PM
sorry bad english what i mean is you attached the math.random to 2 diff definitions in where you said rand = math.random and i = math.random

the other think is you had it right the first time with what you thought i wanted however when i ran the code and sent a redstone signal to nthe front the lights came on and then nothing else happened

but in your explanation they should have come on for 2 secs then started blinking randomly

so what i am saying is that never happened
oh wait it just hit me that yeah moving the loops beginning fixs that lol duh

sorry i will check this adjustment and see if that works first lol

btw thank you very much for all your help even if this doesnt work i think i now have a better enough grasp of the rs call functions and tables to make it work

cheers
Karaktar #30
Posted 05 October 2012 - 11:19 PM
ok moving the loop worked however it stayed running even after i stopped the redstone signal
so to fix that i added a until rs.getInput("front") right beneath the loop figuring i could use a button the start stop the lights
this however through a error [string "startup"]:29: 'end' expected
(to close 'while' at line 26

not sure what to do here i added a extra end at the end and it still gave that error
Orwell #31
Posted 05 October 2012 - 11:46 PM
ok moving the loop worked however it stayed running even after i stopped the redstone signal
so to fix that i added a until rs.getInput("front") right beneath the loop figuring i could use a button the start stop the lights
this however through a error [string "startup"]:29: 'end' expected
(to close 'while' at line 26

not sure what to do here i added a extra end at the end and it still gave that error

if you use until rs.getInput("front"), you should do it like this:

repeat
  [i]code[/i]
until rs.getInput("front")

EDIT: it's much easier for us to help if you post your current code
Cranium #32
Posted 05 October 2012 - 11:49 PM

local sides = {"left", "right", "back", "top"}
local function lights(delay)
  if not delay then
		    for i = 1,#sides do
				  rs.setOutput(sides[i], true)
		    end
  else
		    local rand = math.random(1,4)
		    rs.setOutput(sides[rand],true)
		    sleep(delay)
		    rs.setOutput(sides[rand],false)
		    sleep(delay)
  end
end
local function display(side,delay1,delay2)
  rs.setOutput(side,true)
  sleep(delay1)
  rs.setOutput(side,false)
  sleep(delay2)
end
lights()
sleep(2)
local event, p1 = os.pullEvent()
if event == "redstone" then
  while rs.getInput("front") do  --changed to continue loop while there is a redstone signal on the front side
	 local x = math.random(1,4)
	   display(sides[x],.5,.5)
    end
  end
end
I edited a little and changed the note to fit. I hope it helps.
By the way, when we use math.random, that is just another function call that returns a number. So we can define a variable using math.random as many times as we want. We can have 500 variables, all defined by a result from math.random, and the code would not care. As long as we do not REDEFINE a same variable with it, we won't have a problem.
Karaktar #33
Posted 06 October 2012 - 01:01 AM
orwell thanks for responding i didnt post the whole code because its already there so i just posted what i changed which was all i figured cranium needed since he's been just about the only one working on this i hadn't considered that someone else might jump in but thank you

cranium thanks just so i am clear all you changed was adding the rs.get to the while do statement right or in other words combining the 2 into one so the loop depends on the redtone to front being true correct?
Karaktar #34
Posted 06 October 2012 - 01:07 AM
oh and about the math.random i see what you mean but now i am wondering do we need both rand and i for it to work or wouldnt it be easier just to use rand for everything involving the math.random func

in case that is not clear what i would like to know is why you chose to attach 2 things to it rather then just doing the one?

like is that easier for lua to undertand or is it more for your own reasons like debugging later?
Karaktar #35
Posted 06 October 2012 - 01:37 AM
ok that worked however when i stoped the restone signal to the front and then turned it on again nothing (because the loop had finished) so to fix that i put
 if not rs.getInput("front") then 
lights()
end
  end 
end

and that worked now they turn off and on with power on and off
i cant thank you enough cranium if theres anything i can do to repay you anytime just name it

and yes i think with my new found knowledge there will be more code coming form me btw i think i will post this code in the programs portion of the forums with credit to you for most of the work i hope thats ok
Karaktar #36
Posted 06 October 2012 - 02:12 AM
ok i was wrong that didn't fix it so right now as is i can turn them on and turn them off but after that i have to restart the program
Karaktar #37
Posted 06 October 2012 - 02:13 AM
however i think if i add os.reboot to the end and name it startup that should fix it im a gonna try
Luanub #38
Posted 06 October 2012 - 02:21 AM
You just need to put the code inside of a loop. There should be no reason to do an os.reboot()

Should look something like

local sides = {"left", "right", "back", "top"}
local function lights(delay)
  if not delay then
                    for i = 1,#sides do
                                  rs.setOutput(sides[i], true)
                    end
  else
                    local rand = math.random(1,4)
                    rs.setOutput(sides[rand],true)
                    sleep(delay)
                    rs.setOutput(sides[rand],false)
                    sleep(delay)
  end
end
local function display(side,delay1,delay2)
  rs.setOutput(side,true)
  sleep(delay1)
  rs.setOutput(side,false)
  sleep(delay2)
end
lights()
sleep(2)

while true do  -- added infinite while loop, you will have to ctrl+t to stop this
local event, p1 = os.pullEvent()
if event == "redstone" then
  while rs.getInput("front") do  --changed to continue loop while there is a redstone signal on the front side
         local x = math.random(1,4)
           display(sides[x],.5,.5)
    end
  end
end
end
Karaktar #39
Posted 06 October 2012 - 02:35 AM
hmm one other thing its supposed to hang on the pull event but its not its skipping right past ok heres the code maybe you can spot the error

local sides = {"left","back","right","top"}
local function lights(delay)
  if not delay then
         for i = 1,#sides do
           rs.setOutput(sides[i],true)
        end
   else
        local rand = math.random(1,4)
        rs.setOutput(sides[rand],true)
        sleep(delay)
        rs.setOutput(sides[rand],false
        sleep(delay)
    end
end
local function display(side,delay1,delay2)
   rs.setOutput(side,true)
   sleep(delay1)
   rs.setOutput(side,false)
   sleep(delay2)
end
lights()
sleep(2)
  local event, pl = os.pullevent()
  if even == "redstone" then
       while rs.getInput("front") do
             local x = math.random(1,4)
             display(sides[x],.5,.5)
  elseif not rs.getInput("front") then
lights()
os.reboot()
end
end
end
end

sorry about thye ends at the bottem i couldnt figure where they should indent too

anyway the problem is the program exits and i dont want it to i want it to continue with the only change being lights flashing or lights on depending on the redstone signal to the front on for blinking off for all lights on
Orwell #40
Posted 06 October 2012 - 02:47 AM
hmm one other thing its supposed to hang on the pull event but its not its skipping right past ok heres the code maybe you can spot the error

local sides = {"left","back","right","top"}
local function lights(delay)
  if not delay then
		 for i = 1,#sides do
		   rs.setOutput(sides[i],true)
		end
   else
		local rand = math.random(1,4)
		rs.setOutput(sides[rand],true)
		sleep(delay)
		rs.setOutput(sides[rand],false
		sleep(delay)
	end
end
local function display(side,delay1,delay2)
   rs.setOutput(side,true)
   sleep(delay1)
   rs.setOutput(side,false)
   sleep(delay2)
end
lights()
sleep(2)
  local event, pl = os.pullevent()
  if even == "redstone" then
	   while rs.getInput("front") do
			 local x = math.random(1,4)
			 display(sides[x],.5,.5)
  elseif not rs.getInput("front") then
lights()
os.reboot()
end
end
end
end

sorry about thye ends at the bottem i couldnt figure where they should indent too

anyway the problem is the program exits and i dont want it to i want it to continue with the only change being lights flashing or lights on depending on the redstone signal to the front on for blinking off for all lights on

You should have an 'end' after 'display(sides[x],,5,,5)'. Also, if this is all your code, you have 3 end's to many at the bottom.
Karaktar #41
Posted 06 October 2012 - 05:11 PM
orwell thanks unfortuantly you are wrong if i lose the three ends it gives an error end expected so they are needed im trying to copy paste this code again and edit it but its not working i edited it more in game and i cant paste that because we dont have http enabled on the server its on any tips on putting this code somewhere like in text edit and editing it there then pasting back here?
Luanub #42
Posted 07 October 2012 - 12:18 AM
orwell thanks unfortuantly you are wrong if i lose the three ends it gives an error end expected so they are needed im trying to copy paste this code again and edit it but its not working i edited it more in game and i cant paste that because we dont have http enabled on the server its on any tips on putting this code somewhere like in text edit and editing it there then pasting back here?

That error is because line 9 is missing an ) the ends are extra and one that is valid is in the wrong spot. Sorry I didn't notice this yesterday I was just using what was already posted.

local sides = {"left","back","right","top"}
local function lights(delay)
  if not delay then
    for i = 1,#sides do
	  rs.setOutput(sides[i],true)
    end
  else
    local rand = math.random(1,4)
    rs.setOutput(sides[rand],true)
    sleep(delay)
    rs.setOutput(sides[rand],false)
    sleep(delay)
  end
end
local function display(side,delay1,delay2) 
  rs.setOutput(side,true)
  sleep(delay1)
  rs.setOutput(side,false)
   sleep(delay2)
end
lights()
sleep(2)
local event, pl = os.pullevent()
if even == "redstone" then
  while rs.getInput("front") do
    local x = math.random(1,4)
    display(sides[x],.5,.5)
  end
elseif not rs.getInput("front") then
  lights()
  os.reboot()
end