How to reset the value when using input

New to FreeBASIC? Post your questions here.
norange
Posts: 1
Joined: Feb 08, 2019 17:38

How to reset the value when using input

Postby norange » Feb 08, 2019 17:44

So I'm having an issue. I'm trying to make a text based adventure game but I'm having trouble with the input. Every time I have input and then go back to that section of code, the input value remains the same and causes issues. This is the code I'm using:

Code: Select all

Declare Sub room1
Declare Sub room2
Declare Sub startmenu

Dim Shared As String room

Dim Shared As BOOLEAN running
running = TRUE

room = "startmenu"

Sub startmenu()
   Dim choice As String
   cls
   Print "welcome to this thing"
   Print
   Print "start or quit?"
   Input "> ", choice
   
   If choice = "start" Then room = "room1"
   If choice = "quit" Then End
   If choice <> "start" And choice <> "quit" Then
      Print
      Print "What?"
      Print
      Sleep
      cls
   EndIf
   
End Sub

Sub room1()
   Dim choice As String
   Print "You're in a room. There's another room. Wanna check it out (y/n)?"
   
   Input "> ", choice
   If choice = "y" Then room = "room2"
   If choice = "n" Then room = "room1"
   If choice <> "y" And choice <> "n" Then
      Print
      Print "What?"
      Print
      Sleep
      Cls
   endif
End Sub

Sub room2()
   Dim choice As String
   Print "You are in another room. Wanna go back to the first (y/n)?"
   Input "> ", choice
   If choice = "y" Then room = "room1
   If choice = "n" Then room = "room2
   If choice <> "y" And choice <> "n" Then
      Print
      Print "What?"
      Print
      Sleep
      Cls
   EndIf
End Sub

While running = TRUE
   
   If room = "startmenu" Then startmenu()
   If room = "room1" Then room1()
   If room = "room2" Then room2()
   
Wend


How can I get around this issue?
fxm
Posts: 9123
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to reset the value when using input

Postby fxm » Feb 09, 2019 8:17

Welcome to the forum.

I will try to answer your specific question without judging your code:
- This behavior is due to the use of the keyword 'Sleep' followed later by the keyword 'Input'.
- Each 'Sleep' keyword in your code waits a key is pressed to continue the code execution, but 'Sleep' does not clear the keyboard buffer and any key pressed during a call to 'Sleep' is retained and can then be read automatically by 'Input'.
- In order to wait for a key press (due to 'Sleep' keyword), and then remove the key from the buffer, 'GetKey' or 'While InKey <> "" : Wend' can be placed after the 'Sleep' keyword.

For example in your code, replace any:

Code: Select all

      Sleep
with:

Code: Select all

      Sleep
      Getkey  '' clear the keyboard buffer, and even in that code case, the 'Sleep' keyword can be outright omitted
or:

Code: Select all

      Sleep
      While Inkey <> ""  '' loop until the Inkey buffer is empty
      Wend

Note:
When 'Sleep' has no parameters (waiting for a key pressed only), the only 'GetKey' keyword can be used instead of 'Sleep'.
Last edited by fxm on Feb 09, 2019 13:57, edited 9 times in total.
fxm
Posts: 9123
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to reset the value when using input

Postby fxm » Feb 09, 2019 10:30

Note for all users:
When the timeout to wait is specified in the 'Sleep' instruction, the only syntax which works in all cases to clear the keyboard buffer (if the user eventually presses a key to abort the waiting) is the second proposal ('While InKey <> "" : Wend'), because if the user does not want to press a key during the waiting, then 'GetKey' will wait for a key pressed (which is not the case with 'InKey').

Test the 2 following codes, specially when user waits for the timeout without pressing any key (with 'GetKey', an additional press on any key is necessary before being able to enter the string):

Code: Select all

Dim As String s

Print "wait 3 seconds or press a key"
Sleep 3000
Print "outputed by timeout or key pressed"
Getkey

Input "enter a string"; s
Print "string entered: " & "'" & s & "'"

Sleep

Code: Select all

Dim As String s

Print "wait 3 seconds or press a key"
Sleep 3000
Print "outputed by timeout or key pressed"
While Inkey <> ""  '' loop until the Inkey buffer is empty
Wend

Input "enter a string"; s
Print "string entered: " & "'" & s & "'"

Sleep
    In addition, 'While InKey <> "" : Wend' instead of a simple 'InKey', is a security against eventual multi key-pressed during the waiting if the CPU is hogged, which cannot be do with 'GetKey'.
I do not know if it is necessary to specify this last subtlety in the documentation on SLEEP and also to clarify the present description and example ?
Last edited by fxm on Feb 09, 2019 16:00, edited 4 times in total.
Tourist Trap
Posts: 2762
Joined: Jun 02, 2015 16:24

Re: How to reset the value when using input

Postby Tourist Trap » Feb 09, 2019 13:36

fxm wrote:I do not know if it is necessary to specify this last subtlety in the documentation on SLEEP and also clarify the present explanation and example ?

Hi fxm,

I felt into things like that in the past and found it difficult to find where was hidden the problem. Clearing the buffer is also a thing to understand when using multikey, so I think personnally that to really write freebasic code one must ear about this kind of thing as much as possible in order to keep it in mind despite the fact it will not look too much intuitive at first sight.
My opinion anyway.
fxm
Posts: 9123
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to reset the value when using input

Postby fxm » Feb 09, 2019 13:56

For 'MultiKey', the documentation description is proper and complete about this behavior, up to proposing the only clearing method which correctly works:
'While Inkey <> "" : Wend'
(loop until the Inkey buffer is empty).
Tourist Trap
Posts: 2762
Joined: Jun 02, 2015 16:24

Re: How to reset the value when using input

Postby Tourist Trap » Feb 09, 2019 14:16

fxm wrote:For 'MultiKey', the documentation description is proper and complete about this behavior, up to proposing the only clearing method which correctly works:
'While Inkey <> "" : Wend'
(loop until the Inkey buffer is empty).

For multikey it's correct yes. What I meant is that this affair of buffer is not limited to multikey as a special case, it's more general in FB. That's something that in my opinion should be very clear for anyone using the language. That has so much implication that myself don't use sleep anymore to pause a program at end, I use Getkey. Still my feeling anyway. If you see how to add a comment on this in the doc I would vote for, otherwise maybe it's something desserving a tutorial. I don't know.
dodicat
Posts: 5913
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to reset the value when using input

Postby dodicat » Feb 09, 2019 15:05

I wonder how many ways there are to clear the keyboard before continuing?
Here is another method.

Code: Select all

print "press a key to continue"

 (input(1))


print "Inkey = ";inkey


print "Press a key to end"
sleep 
fxm
Posts: 9123
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to reset the value when using input

Postby fxm » Feb 09, 2019 15:09

Former documentation text on SLEEP:
.....
Description:
.....
Sleep does not clear the keyboard buffer and any keys pressed during a call to Sleep are retained and can be read using Inkey. In order to wait for a key press, and remove the key from the buffer, Getkey can be used instead.

Examples:

Code: Select all

Print "press a key"
Sleep
GetKey 'clear the keyboard buffer
Print "waiting half second"
Sleep 500
.....

Proposal of new documentation text on SLEEP (more precise but always compact, IMHO):
.....
Description:
.....
Sleep does not clear the keyboard buffer and any keys pressed during a call to Sleep are retained and can be later read by Inkey or GetKey or Input.
When Sleep has no parameters (waiting for a key pressed only), GetKey keyword can be used instead of Sleep.
For the general form of Sleep (with parameters), if the user want to clear the keyword buffer from any eventual keys pressed during the Sleep execution, he can use after the Sleep instruction line something like the following method:

Code: Select all

While Inkey <> "": Wend '' loop until the Inkey buffer is empty
Examples:

Code: Select all

Print "press a key"
Sleep
GetKey 'clear the keyboard buffer, and even in that code case, the 'Sleep' keyword can be outright omitted
Print "waiting half second"
Sleep 500

Code: Select all

Dim As String s

Print "wait 3 seconds or press a key"
Sleep 3000
Print "outputed by timeout or key pressed"
While Inkey <> ""  '' loop until the Inkey buffer is empty
Wend

Input "enter a string"; s
Print "string entered: " & "'" & s & "'"

Sleep
.....
Last edited by fxm on Feb 21, 2019 14:04, edited 3 times in total.
MrSwiss
Posts: 3217
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: How to reset the value when using input

Postby MrSwiss » Feb 09, 2019 15:14

To get back OT (... when using input), by leaving it to input, to deal with it:

Code: Select all

Function main_menu() As String
    Dim As String choice, room = ""

    While room = ""                     ' run until we have a useful answer
        Cls
        choice = ""                     ' assure a empty string
        Print "welcome to this thing"
        Print
        Print "sMenu1, sMenu2 or quit?"
        Input "> ", choice              ' get user answer
   
        Select Case LCase(choice)       ' react accordingly (assuring: lower case _
                                        ' comparison only, while user can use any case)
            Case "smenu1" : room = "room1"
            Case "smenu2" : room = "room2"
            Case "quit"   : room = "quit"
            Case Else                   ' user error handler
                Print : Print "What?"
                Print : Sleep(2000)     ' show message, then ask again
        End Select
        Sleep(20, 1)                    ' prevent CPU hogging
    Wend
    Return room                         ' transfer user choice (to main loop)
End Function


' prog. main loop (since it is endless, he have to provide a exit strategy!)
Do
    Select Case LCase(main_menu())      ' get user input and deal with it
        Case "room1"                    ' call sub_menu1
            ' ...
        Case "room2"                    ' call sub_menu2
            ' ...
        Case "quit" : Exit Do           ' user wants to quit: end loop
        Case Else                       ' error handler
            ' ...
    End Select
Loop
' ----- EOF -----
Tourist Trap
Posts: 2762
Joined: Jun 02, 2015 16:24

Re: How to reset the value when using input

Postby Tourist Trap » Feb 09, 2019 15:16

fxm wrote:Former documentation text on SLEEP

Thanks a lot for the work fxm!
It's insisting but it doesn't leave anymore room for hesitation. Use sleep is convenient only if the keyboard buffer has not to be cleaned up. Otherwise Getkey, or one of the other form is suitable.

All of this reminds me of the principle of the Getstring I mentionned in the tips and tricks: viewtopic.php?f=7&t=26916&p=250088&hilit=getstring#p250042
It's exactly elaborated on these affairs of unclean buffers.

Code: Select all

function GetString() as string
   dim as string gs, k
   gs = Chr(GetKey())
   do
      k = InKey()
      gs &= k
    loop until k=""
    '
    return gs
end function

'demo

Sleep ()
Sleep()
Sleep()

? GetString()
? GetString()
? GetString()

'end
   
fxm
Posts: 9123
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to reset the value when using input

Postby fxm » Feb 09, 2019 15:37

Tourist Trap wrote:Use sleep is convenient only if the keyboard buffer has not to be cleaned up. Otherwise Getkey, or one of the other form is suitable.

I do not agree.
Referring to my previous example at viewtopic.php?p=258122#p258122, how write a simple code without using 'Sleep 3000'.
(wait 3 seconds or press a key, then enter a string)
fxm
Posts: 9123
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to reset the value when using input

Postby fxm » Feb 09, 2019 15:44

Restricting to the only SLEEP documentation page to be improved, what do users think of my proposal (a second example has been added)?
Last edited by fxm on Feb 09, 2019 16:23, edited 1 time in total.
MrSwiss
Posts: 3217
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: How to reset the value when using input

Postby MrSwiss » Feb 09, 2019 15:59

Leave it, as is ... (aka: no need for change)

Reason: the only person here, that has mastered the Art of complexifying everything,
instead of keeping simple things the way they are, should not be the "yardstick" ...
fxm
Posts: 9123
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How to reset the value when using input

Postby fxm » Feb 09, 2019 16:19

If you start to get into non-constructive criticism, your proposed code is not "clean":
If during the 'Sleep (2000)' (body of Case Else), the user presses the <return> key, he re-enters in this part of code and so on ... (as long as user press the <return> key at each second, for example, nothing is displayed on the screen).
If the user presses another key during the 'Sleep(2000)', the character is taken into account in the next 'Input "> ", choice'.
Last edited by fxm on Feb 09, 2019 17:06, edited 2 times in total.
dodicat
Posts: 5913
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to reset the value when using input

Postby dodicat » Feb 09, 2019 16:25

Another possible method to clear the keyboard buffer.

Code: Select all



    dim as function() as string clearbuffer=@inkey()
   


print "Press a key to continue .."

sleep
clearbuffer()

print "len inkey = ";len(inkey)

print "Press a key to end .."

sleep
 

Return to “Beginners”

Who is online

Users browsing this forum: No registered users and 4 guests