Advertisement
thedafelix

lamps

Sep 26th, 2016
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.40 KB | None | 0 0
  1. -- I don't know oyur programming experience
  2. -- If you are doing CC the chance is not bad that you are a novice
  3. -- that's why I heavily commented and spread out the program
  4. -- don't feel offened if you already know all of this ;)
  5. -- I also had fun writing it :D
  6. --
  7. -- PS: Sorry this got really long - I can't ask you to read all of that :O
  8.  
  9. -- you will see that in functions I used the word "local" in front of variables
  10. -- this means that the value can only be used in the current context
  11. -- if I put local before LAMPS it could be only used in the context of this script
  12. -- this would make no difference here
  13. -- (I am also not sure where you could theoretically use LAMPS now)
  14. --
  15. -- you just have to use local once (per context)
  16. -- so if you use local you say "in this context <variable> will now be local from here on"
  17. --
  18. -- more importantly I used local in functions to not clutter this level of the script with variables
  19. --
  20. -- Have a look at this to understand local better: https://repl.it/Dh7e
  21.  
  22. LAMPS = {
  23.   {name = "Energy Storage", abbr = "E", side = "left", color = colors.black},
  24.   {name = "Turbines", abbr = "T", side = "left", color = colors.white},
  25.   {name = "Reactors", abbr = "R", side = "right", color = colors.green},
  26.   {name = "Control Room", abbr = "C", side = "right", color = colors.red},
  27. }
  28.  
  29.  
  30. -- a small function to convert a boolean value (true/false) to the string "On" or "Off"
  31. -- function because we use it in a few places
  32. -- you used strings in the on variable to begin with but to stick with boolean variables leaves less room for error
  33. -- (e.g. no problem with the case of the "on"/"off" values you save)
  34. function boolToOnOff(on)
  35.   -- this is like the "ternary" ? operator in other languages
  36.   -- (I found this version here: http://lua-users.org/wiki/TernaryOperator)
  37.   return on and "On" or "Off"
  38. end
  39.  
  40.  
  41. -- make a given string s always length long, fill with the character "with" from the end in case it isn't
  42. -- you did this manually as your status output was hardcoded
  43. function padString(s, length, with)
  44.   return s .. string.rep(with, length - string.len(s))
  45. end
  46.  
  47.  
  48. -- use rednet.getBundledOutput to get lamp status and store it in the global LAMPS variable
  49. -- this is handy because then the rest of the program doesn't have to deal with the redstone api directly
  50. -- but just assume that the values stored in LIGHTS are corrected and we then need
  51. -- only a single place where we need to make sure that they are correct
  52. function readStatus()
  53.   for _, lamp in pairs(LAMPS) do
  54.     -- redstone.getBundledOutput and redstone.getBundledInput return a value containing
  55.     -- the information for all colors
  56.     -- use the colors API to work with this value
  57.     -- http://computercraft.info/wiki/Redstone_(API)
  58.     -- http://computercraft.info/wiki/Colors_(API)
  59.     --
  60.     -- the light is on if the output for this color is on or there is another input
  61.     -- (don't know wether you want to account for this)
  62.     -- I split the test to two lines
  63.     lamp.on = colors.test(redstone.getBundledOutput(lamp.side), lamp.color)
  64.     lamp.on = lamp.on or colors.test(redstone.getBundledInput(lamp.side), lamp.color)
  65.   end
  66. end
  67.  
  68.  
  69. -- I like having this in a function because it
  70. -- is a nice way to *label* code belonging together and with it the main loop can be really short
  71. function printStatus()
  72.   term.clear()
  73.   term.setCursorPos(1,1)
  74.  
  75.   print(" ----------------------------------------") -- 41 characters
  76.   -- | [<one character>] < ? characters> | Status: <3 characters> |
  77.   -- ==> name can be 20 characters long
  78.  
  79.   for _, lamp in pairs(LAMPS) do
  80.     -- what we need to do here is somehow pad the columns so the output looks nice and orderly like you did manually
  81.     -- I googled a little and found at that the Lua string.format should be able to pad strings
  82.     -- the CC version can't I think...
  83.     -- we'll do it manually here:
  84.  
  85.     -- for string functions in general I used this page: http://lua-users.org/wiki/StringLibraryTutorial
  86.  
  87.     local status = padString(boolToOnOff(lamp.on), 3, " ")
  88.     local name = padString(lamp.name, 20, " ")
  89.  
  90.     local line = string.format("| [%s] %s | Status: %s |", lamp.abbr, name, status)
  91.     print(line)
  92.   end
  93.  
  94.   print(" ----------------------------------------")
  95.   print("Which lamp would you like to update?")
  96. end
  97.  
  98.  
  99. -- receives a lamp table from the above list/array and asks the user wether he wants to update it
  100. function interactiveUpdateLamp(lamp)
  101.   -- print takes multiple arguments, converts them to strings and joins them together
  102.   -- in this case just using the ".." operator, which joins strings, would be just as easy
  103.   print(lamp.name, " are currently ", boolToOnOff(lamp.on))
  104.  
  105.  
  106.   -- a problem with your prompt was that the case where the user mistypes wasn't handled
  107.   -- that is why we will use a loop here which we will break from in case a recognized input is received
  108.   --
  109.   -- it is easier to do an infinite loop here and break later rather than
  110.   -- storing the value for the break condition outside of the loop
  111.   while true do
  112.     -- we can use not here: it just turns true to false and false to true
  113.     -- saves a if then else case
  114.     --
  115.     -- I stumbled across this while debugging: write doesn't support taking multiple arguments so you need to use .. here
  116.     write("Would you like to turn them " .. boolToOnOff(not lamp.on) .. "? (yes/no) -> ")
  117.  
  118.     -- I have written a lot below on why I didn't use read() there
  119.     -- here it is necessary (kind off.. it would be cool to have auto-update of status here as well but I
  120.     -- imagine it to be difficult)
  121.     -- also it wouldn't be as useful here. most of the time you aren't letting the program run while still stuck here
  122.     -- you will just change lamp status and go back to the main screen
  123.     --
  124.     -- use string.low here to make the input lowercase so we automatically handle all cases: Yes YEs yes YES ...
  125.     local input = string.lower(read())
  126.  
  127.     if input == "yes" or input == "y" then
  128.       -- I haven't recognized this issue with your program before
  129.       -- it wasn't possible to have multiple lamps on the same side on because you always set the colors value to just one color
  130.       -- 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
  131.       -- and then change the single color you want to update
  132.       --
  133.       -- instead use colors.combine and colors.subtract to turn a single color off
  134.       local currentBundledOutput = redstone.getBundledOutput(lamp.side)
  135.  
  136.       if lamp.on then -- turn off
  137.         redstone.setBundledOutput(lamp.side, colors.subtract(currentBundledOutput, lamp.color))
  138.       else -- turn off
  139.         redstone.setBundledOutput(lamp.side, colors.combine(currentBundledOutput, lamp.color))
  140.       end
  141.  
  142.       -- we could update lamp.on here but like I said in the comment to the readStatus function
  143.       -- I *think* it is better design to really just set the value here and don't bother updating the state value
  144.       -- I think it's better to do this just at one place
  145.       break
  146.  
  147.     elseif input == "no" or input == "n" then
  148.       print("Lights Will Remain ", boolToOnOff(lamp.on))
  149.       break
  150.     end
  151.  
  152.     -- implicit (didn't write it because it is not needed) else means
  153.     -- "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)
  154.     -- which prints the "Would you like to turn them..." prompt again
  155.   end
  156. end
  157.  
  158.  
  159. -- main loop
  160. -- I changed the reading bit a little as I wanted the status to update while the program is idling (no key is typed)
  161. -- this means you can start the program turn a lever on return to the program and the screen will have changed
  162. -- In general this approach doesn't work as well because read does a lot more work we would need to replicate then:
  163. --    it listenes for a key type event
  164. --    prints the key
  165. --    checks that everything is aligned properly
  166. --    stores it
  167. --    handles enter
  168. --    ... (no idea what else :D)
  169. -- in our case though we want to listen for a single key
  170. -- so instead of typeing "E" and enter you just press the e key and the program immediately asks you to update the lights status
  171. -- if this isn't the behaviour you want I think you have to go back to using read()
  172. -- (or google around - maybe someone solved this :D)
  173. -- but I don't know how to auto update then
  174. -- this would be an exercise for you then ;)
  175. --
  176. -- 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
  177. -- 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 ;))
  178. --
  179. -- there is an overview of all events: http://www.computercraft.info/wiki/Os.pullEvent
  180. -- the char event: http://www.computercraft.info/wiki/Char_(event)
  181. -- the redstone event
  182. --
  183. -- os.pullEvent always returns the event name as the first return value and then a varying amount of further values
  184. -- (depending on the event of course)
  185. -- in case of the char event just one other value is returned, the key pressed
  186. -- 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
  187. -- case of a redstone event. we still need to have two *receiving* variables because we can#t know beforehand which event will be returned
  188. -- 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
  189.  
  190. -- Initial print current status
  191. readStatus()
  192. printStatus()
  193.  
  194. while true do
  195.   -- os.pullEvent takes an optional argument to filter events. we will just take all events and filter them ourselves
  196.   local event, key = os.pullEvent()
  197.   local needsRedraw = false
  198.  
  199.   if event == "redstone" then
  200.     -- redstone has changed (external signal)
  201.     -- need to update the LIGHTS variable then print screen again
  202.     -- 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
  203.     needsRedraw = true
  204.   elseif event == "char" then
  205.     -- check if there is a lamp which is abbreviated by the key just typed (case insensitive)
  206.     for _, lamp in pairs(LAMPS) do
  207.       if string.lower(lamp.abbr) == string.lower(key) then
  208.         interactiveUpdateLamp(lamp)
  209.         needsRedraw = true
  210.       end
  211.     end
  212.   end
  213.  
  214.   if needsRedraw then
  215.     readStatus()
  216.     printStatus()
  217.   end
  218. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement