Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- I don't know oyur programming experience
- -- If you are doing CC the chance is not bad that you are a novice
- -- that's why I heavily commented and spread out the program
- -- don't feel offened if you already know all of this ;)
- -- I also had fun writing it :D
- --
- -- PS: Sorry this got really long - I can't ask you to read all of that :O
- -- you will see that in functions I used the word "local" in front of variables
- -- this means that the value can only be used in the current context
- -- if I put local before LAMPS it could be only used in the context of this script
- -- this would make no difference here
- -- (I am also not sure where you could theoretically use LAMPS now)
- --
- -- you just have to use local once (per context)
- -- so if you use local you say "in this context <variable> will now be local from here on"
- --
- -- more importantly I used local in functions to not clutter this level of the script with variables
- --
- -- Have a look at this to understand local better: https://repl.it/Dh7e
- LAMPS = {
- {name = "Energy Storage", abbr = "E", side = "left", color = colors.black},
- {name = "Turbines", abbr = "T", side = "left", color = colors.white},
- {name = "Reactors", abbr = "R", side = "right", color = colors.green},
- {name = "Control Room", abbr = "C", side = "right", color = colors.red},
- }
- -- a small function to convert a boolean value (true/false) to the string "On" or "Off"
- -- function because we use it in a few places
- -- you used strings in the on variable to begin with but to stick with boolean variables leaves less room for error
- -- (e.g. no problem with the case of the "on"/"off" values you save)
- function boolToOnOff(on)
- -- this is like the "ternary" ? operator in other languages
- -- (I found this version here: http://lua-users.org/wiki/TernaryOperator)
- return on and "On" or "Off"
- end
- -- make a given string s always length long, fill with the character "with" from the end in case it isn't
- -- you did this manually as your status output was hardcoded
- function padString(s, length, with)
- return s .. string.rep(with, length - string.len(s))
- end
- -- use rednet.getBundledOutput to get lamp status and store it in the global LAMPS variable
- -- this is handy because then the rest of the program doesn't have to deal with the redstone api directly
- -- but just assume that the values stored in LIGHTS are corrected and we then need
- -- only a single place where we need to make sure that they are correct
- function readStatus()
- for _, lamp in pairs(LAMPS) do
- -- redstone.getBundledOutput and redstone.getBundledInput return a value containing
- -- the information for all colors
- -- use the colors API to work with this value
- -- http://computercraft.info/wiki/Redstone_(API)
- -- http://computercraft.info/wiki/Colors_(API)
- --
- -- the light is on if the output for this color is on or there is another input
- -- (don't know wether you want to account for this)
- -- I split the test to two lines
- lamp.on = colors.test(redstone.getBundledOutput(lamp.side), lamp.color)
- lamp.on = lamp.on or colors.test(redstone.getBundledInput(lamp.side), lamp.color)
- end
- end
- -- I like having this in a function because it
- -- is a nice way to *label* code belonging together and with it the main loop can be really short
- function printStatus()
- term.clear()
- term.setCursorPos(1,1)
- print(" ----------------------------------------") -- 41 characters
- -- | [<one character>] < ? characters> | Status: <3 characters> |
- -- ==> name can be 20 characters long
- for _, lamp in pairs(LAMPS) do
- -- what we need to do here is somehow pad the columns so the output looks nice and orderly like you did manually
- -- I googled a little and found at that the Lua string.format should be able to pad strings
- -- the CC version can't I think...
- -- we'll do it manually here:
- -- for string functions in general I used this page: http://lua-users.org/wiki/StringLibraryTutorial
- local status = padString(boolToOnOff(lamp.on), 3, " ")
- local name = padString(lamp.name, 20, " ")
- local line = string.format("| [%s] %s | Status: %s |", lamp.abbr, name, status)
- print(line)
- end
- print(" ----------------------------------------")
- print("Which lamp would you like to update?")
- end
- -- receives a lamp table from the above list/array and asks the user wether he wants to update it
- function interactiveUpdateLamp(lamp)
- -- print takes multiple arguments, converts them to strings and joins them together
- -- in this case just using the ".." operator, which joins strings, would be just as easy
- print(lamp.name, " are currently ", boolToOnOff(lamp.on))
- -- a problem with your prompt was that the case where the user mistypes wasn't handled
- -- that is why we will use a loop here which we will break from in case a recognized input is received
- --
- -- it is easier to do an infinite loop here and break later rather than
- -- storing the value for the break condition outside of the loop
- while true do
- -- we can use not here: it just turns true to false and false to true
- -- saves a if then else case
- --
- -- I stumbled across this while debugging: write doesn't support taking multiple arguments so you need to use .. here
- write("Would you like to turn them " .. boolToOnOff(not lamp.on) .. "? (yes/no) -> ")
- -- I have written a lot below on why I didn't use read() there
- -- here it is necessary (kind off.. it would be cool to have auto-update of status here as well but I
- -- imagine it to be difficult)
- -- also it wouldn't be as useful here. most of the time you aren't letting the program run while still stuck here
- -- you will just change lamp status and go back to the main screen
- --
- -- use string.low here to make the input lowercase so we automatically handle all cases: Yes YEs yes YES ...
- local input = string.lower(read())
- if input == "yes" or input == "y" then
- -- I haven't recognized this issue with your program before
- -- it wasn't possible to have multiple lamps on the same side on because you always set the colors value to just one color
- -- like I mentioned every color's information is stored in one value so to turn a lamp on you have to get the current status
- -- and then change the single color you want to update
- --
- -- instead use colors.combine and colors.subtract to turn a single color off
- local currentBundledOutput = redstone.getBundledOutput(lamp.side)
- if lamp.on then -- turn off
- redstone.setBundledOutput(lamp.side, colors.subtract(currentBundledOutput, lamp.color))
- else -- turn off
- redstone.setBundledOutput(lamp.side, colors.combine(currentBundledOutput, lamp.color))
- end
- -- we could update lamp.on here but like I said in the comment to the readStatus function
- -- I *think* it is better design to really just set the value here and don't bother updating the state value
- -- I think it's better to do this just at one place
- break
- elseif input == "no" or input == "n" then
- print("Lights Will Remain ", boolToOnOff(lamp.on))
- break
- end
- -- implicit (didn't write it because it is not needed) else means
- -- "in case the user didn't enter yes, y, no, n" loop to the beginning" (because only yes, y, no, n is recognized in the ifs)
- -- which prints the "Would you like to turn them..." prompt again
- end
- end
- -- main loop
- -- I changed the reading bit a little as I wanted the status to update while the program is idling (no key is typed)
- -- this means you can start the program turn a lever on return to the program and the screen will have changed
- -- In general this approach doesn't work as well because read does a lot more work we would need to replicate then:
- -- it listenes for a key type event
- -- prints the key
- -- checks that everything is aligned properly
- -- stores it
- -- handles enter
- -- ... (no idea what else :D)
- -- in our case though we want to listen for a single key
- -- so instead of typeing "E" and enter you just press the e key and the program immediately asks you to update the lights status
- -- if this isn't the behaviour you want I think you have to go back to using read()
- -- (or google around - maybe someone solved this :D)
- -- but I don't know how to auto update then
- -- this would be an exercise for you then ;)
- --
- -- the advantage with using os.pullEvent is that you can listen to *all* events, in our case including the event which indicates that redstone was updated
- -- read *just* listens to key/char events (don't know which, for us they are the same in that they don't include the redstone event ;))
- --
- -- there is an overview of all events: http://www.computercraft.info/wiki/Os.pullEvent
- -- the char event: http://www.computercraft.info/wiki/Char_(event)
- -- the redstone event
- --
- -- os.pullEvent always returns the event name as the first return value and then a varying amount of further values
- -- (depending on the event of course)
- -- in case of the char event just one other value is returned, the key pressed
- -- the redstone event doesn't return any further values. this means that our char variable below will be nil, null, not have a value in the
- -- case of a redstone event. we still need to have two *receiving* variables because we can#t know beforehand which event will be returned
- -- I think the returned stuff can be stored in just one variable as a table as well but this approach is what is used in the examples in the wiki
- -- Initial print current status
- readStatus()
- printStatus()
- while true do
- -- os.pullEvent takes an optional argument to filter events. we will just take all events and filter them ourselves
- local event, key = os.pullEvent()
- local needsRedraw = false
- if event == "redstone" then
- -- redstone has changed (external signal)
- -- need to update the LIGHTS variable then print screen again
- -- as we need to the same in case a key is printed set this flag and check after this if wether it was set inside of the if
- needsRedraw = true
- elseif event == "char" then
- -- check if there is a lamp which is abbreviated by the key just typed (case insensitive)
- for _, lamp in pairs(LAMPS) do
- if string.lower(lamp.abbr) == string.lower(key) then
- interactiveUpdateLamp(lamp)
- needsRedraw = true
- end
- end
- end
- if needsRedraw then
- readStatus()
- printStatus()
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement