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

Reading A Line From The Screen (need help)

Started by Ange1ofD4rkness, 31 May 2012 - 09:44 PM
Ange1ofD4rkness #1
Posted 31 May 2012 - 11:44 PM
First of all thanks for anyone who can help me with my problem here.

Anyway, I am new to lua, but not to programming. Currently I am working on a program that will work as a password protected door, but can also accepts redstone input as what you might say are fail safes for the door (or changes in state).

The program is meant to work off a series of events as seen is this beginning version of the code (I am working on a new version and this is the base of it, and where my problem lies).


function main()

while true do
	doorColor()
	event, param1 = os.pullEvent()

	if event == "key" and param1 == 28 then
	   --(press enter key)
	   if doorColorLock == false then --(okay to open)
		  term.clear()
		  term.setCursorPos(1,1)
	   end
   end

   if event == "redstone" and param1 == "top" then
	   --(reactor problem signal)
	   doorColor()
   end

   if event == "redstone" and param1 == "back" then
	   --(lock down signal)
	   doorColor()
   end
end

end

So what this computer will be doing is the following
  • Recieve a signal from a restone source (wireless), if this redstone signal is true, lock the door, and display a message (as well as a few other things).
  • Recieve from another redstone source (wireless), with the same function as the first (just triggered by something else).
  • Determine the state of the door (open or closed, which is determined by another redstone source) and display a message based on the state. If the door is closed it asks for a password, if opened a y/n command.
  • If the the door is closed/opened from the other side then change the message and such as mentioned in bullet point 3.
Okay I think I got it all down. As you can see I was trying to do all of this through events (I haven't entered all of these yet, the 3rd bullet point is still needed, but not needed for this part).

The first event is suppose to detect when the user presses the Enter key (or Return for our older audiences). The reason I did this was because the read() command has a great nack for pausing the whole system waiting on the user.

So here's where my question lies, I know it took me awhile (sorry). Is there a way to read a line from the screen (the command line)?

The reason I put the Enter event was that I hoped that when the user would press the Enter key I could read in a certain typed line and check to see if the string matched with a password for instance, but if one of the other events were to occur, such as the doors state changing, or one of the other redstone sources changing, it would execute that event instead, and not wait for the user to finish typing and press Enter (which the read() command does).

Again thanks for any help. I do hope that something here is possible (C# has spoiled mean with almost no restrictions to what I want to do in comparison to other languages).
MysticT #2
Posted 31 May 2012 - 11:57 PM
You can't read what's already on the screen, but you can handle the "key" and "char" events to get the input, just like read() does but handling other events at the same time.
Example:

local sInput = ""

while true do
  local evt, arg = os.pullEvent()
  if evt == "char" then
    sInput = sInput..arg
  elseif evt == "key" then
    if arg == 28 then -- Enter
	  -- Enter pressed, do something with the input
    elseif arg == 14 then -- Backspace
	  sInput = string.sub(sInput, 1, -2) -- erase the last character
    end
  elseif evt == "redstone" then
    -- do something for redstone event
  end
end
Of course you would have to make some changes, maybe add some more keys support, etc. But it should help you get started.
You can take a look at the read() code to know how it works, it's on the bios.lua file.
Ange1ofD4rkness #3
Posted 01 June 2012 - 08:48 AM
OMG how did I not think of this.

Let me get ths right, I register each key stoke and store it in a string and when the Enter key is pressed I check that string with the other right? If that is the case I feel like an idiot for not thinking of that, it's so simple … *facepalm*. Now I'll just have to add an event for Backspace.

Any good tips for removing a character from a string? I mean can I treat it like an array of chars (for loop copy over … however I don't really like doing that)?
Lyqyd #4
Posted 01 June 2012 - 03:02 PM
Check through the code MysticT posted above; his example includes backspace.
Ange1ofD4rkness #5
Posted 01 June 2012 - 08:57 PM
Check through the code MysticT posted above; his example includes backspace.

Whoops over read that, thanks for pointing that out.

Thanks again for all the help, I love these forums all of a sudden
Ange1ofD4rkness #6
Posted 01 June 2012 - 11:43 PM
Okay so got another question now. Here's my code now


function main()
doorStateMessage()
keyInput = ""
while true do
  --doorColor()
  event, param1 = os.pullEvent()
  if event == "char" then
   --(if a key is pressed store it)
   keyInput = keyInput..param1
  
   write(param1)
  elseif event == "key" then
   --(if a key is pressed, like Enter)
   if param1 == 28 then --(Enter)
	if doorColorLock == false then
	 doorStatus(keyInput)
	end
	keyInput = ""
   elseif param1 == 14 then --(Backspace)
	keyInput = string.sub(keyInput, 1, -2)
	--(this erases last character)
	doorStateMessage()
	write(keyInput)
   end
  elseif event == "redstone" then
   if param1 == "top" then
	--(reactor problem signal)
	print("reactproblem")
	sleep(10)
	doorColor()
	if rs.getInput("top") == true
	and reactorDoorLock == false then
	 term.clear()
	 term.setCursorPos(1,1)
	 write("The Door Has Been Locked Due")
	 write(" To An Issue In The Reactor")	   print(" Room.")
	 write("This Is Being Done For Your")
	 print(" Safety")
	 reactorDoorLock = true
	elseif rs.getInput("top") == false
	and reactorDoorLock == true then
	 term.clear()
	 term.setCursorPos(1,1)
	
	 doorStateMessage()
	 reactorDoorLock = false
	end
   elseif param1 == "back" then
	--(lock down signal)
	print("LockDown")
	sleep(10)
	doorColor()
	if rs.getInput("back") == true
	and lockdownDoorLock == false then
	 term.clear()
	 term.setCursorPos(1,1)
	 write("Lock Down Command Has")
	 print(" Occured")
	 lockdownDoorLock = true
	elseif rs.getInput("back") == false
	and lockdownDoorLock == true then
	 term.clear()
	 term.setCursorPos(1,1)
	
	 doorStateMessage()
	 lockdownDoorLock = false
	end
   elseif param1 == "right" then
	--(door changed states)
	if rs.getInput("right") == true then
	 --(closed)
	 term.clear()
	 term.setCursorPos(1,1)
	 write("Please Enter The Password To")
	 print(" Open The Door")
	 write("Password = ")
	 keyInput = ""
	else --(opened)
	 term.clear()
	 term.setCursorPos(1,1)
	 write("Would You Like To Close The")
	 print(" Door? (y/n)")
	 keyInput = ""
	end  
   end
  end
end
end


I got it to work properly with the password and the y/n event, ext. The problem I am having now is the redstone events. None of these will work and I can't seem to figure out why. You'll notice that the doorColor() code that's commented out at the beginning of main. When that was not commented out if would work but the door would spaz open and close (which would be expected as it is a while statement).

So my question now is why won't these statements execute when the redstone state changes? You'll see those two boolean variables "reactorDoorLock", and "lockdownDoorLock ". Those were used earlier on when I was having a stupid error with the doorColor() mentioned above (stupid on my part). Even if these were to factor is there's still that last elseif for "param1 == right" which executes when the door is closed or opened from the otherside (or another source) … but they don't

BTW this is what the back of the computer looks like


The blue line toggles the state of the door (sends a pulse out that flips a toggle latch). The white determines whether or not the door is closed. The left side where you see the red wire coming out, that simples indicates the door is locked for other reason with red or green light. And the two wireless redstones you see, when on, are suppose to lock the door shut prevent the user from using the door (a lock down you might say)

(I just altered the design a little, the two lamps are stone and the NOT was replaced with a wire, and the lamps were moved to out of range of this photo)
MysticT #7
Posted 02 June 2012 - 12:08 AM
The "redstone" event has no arguments, so you have to use rs.getInput("side") to see if it's on. If you need to know wich one changed (it turned on or off) you need to store the last input and compare to that.
Example:

local tInput = {}
for _,s in ipairs(rs.getSides()) do
  tInput[s] = rs.getInput(s)
end

local function updateInput()
  for _,s in ipairs(rs.getSides()) do
    local b = rs.getInput(s)
    if tInput[s] ~= b then
	  tInput[s] = b
	  return s
    end
  end
end

while true do
  local evt, arg = os.pullEvent()
  if evt == "redstone" then
    local side = updateInput()
    if side == "top" then
	  -- redstone change on top
	  -- you can check if the input is on or off with tInput["side"]
    elseif side == "left" then
	  -- redstone change on left
    -- add all the sides you want here
    end
  end
end
Ange1ofD4rkness #8
Posted 02 June 2012 - 12:13 AM
Really? I thought they did … hmm guess the wiki needs an update for computercraft (well one of them)

http://minecraftcomputercraft.wikia.com/wiki/Events

It said it did have the side in the argument.

BTW the code you posted, I am trying to make sense of it so correct pleae if I am wrong. Pretty much it creates an array with the status of each side of the computer correct? And then when you call updateInput() it looks for a change and if it detects it, it sends back the side that was change correct? Also what are the values "_,s" and "ipairs" suppose to represent? (I am trying to learn as well so I don't just keep running back for help)
my_hat_stinks #9
Posted 02 June 2012 - 12:17 AM

Try the one hosted on this domain? http://computercraft.info/wiki/index.php?title=Main_Page :)/>/>
Ange1ofD4rkness #10
Posted 02 June 2012 - 12:18 AM

*facepalm* yeah that would seem like a good idea wouldn't it?
my_hat_stinks #11
Posted 02 June 2012 - 12:32 AM
BTW the code you posted, I am trying to make sense of it so correct pleae if I am wrong. Pretty much it creates an array with the status of each side of the computer correct? And then when you call updateInput() it looks for a change and if it detects it, it sends back the side that was change correct? Also what are the values "_,s" and "ipairs" suppose to represent? (I am trying to learn as well so I don't just keep running back for help)

I was meaning to get around to doing a loops tutorial for the wiki…

Obviously, you can see that's a for loop, which runs through a specific number of times
The pairs or ipairs loop is a for loop, but rather than your specific "Run x times", you run for the amount of keys in the table

Pairs and ipairs loops use two values, rather than the normal one for a for loop:
for Key, Value in pairs( Table ) do end

The key is the location in the table, the value what is stored at that place
Table[Key] is the same as Value

pairs loops usually use k and v, as opposed to the usual i for normal for loops. But, of course, it makes no difference :)/>/>

The underscore simply means we don't need the key, so it's telling lua to ignore it

So, we're running through the table getting all the values

pairs runs through the table in any order, ipairs orders it as much as possible :)/>/>
Ange1ofD4rkness #12
Posted 05 June 2012 - 02:20 AM
Thanks again guys, all the code you have provided has worked out well (for my fully automated nuclear reactor, and no I didn't copy the other guy, I have been working on this system for awhile (which btw is working as expected and brilliant))