DO ... LOOP question

Please use this Board for QBasic related requests ( file research, programming, etc.)

Moderators:Administrator, Global Moderator

Post Reply
Otringal
Newbie
Posts:6
Joined:Wed Nov 14, 2007 9:53 pm
Location:Romania
DO ... LOOP question

Post by Otringal » Wed Nov 14, 2007 10:01 pm

hello everyone !!! I have a small problem and I hope u guys can help me out :) first, hereś the code :

Code: Select all

screen 12
cls
do
pset(x,y),6
if inkey$=¨w¨ then y=y-1
if inkey$=¨s¨ then y=y+1
if inkey$=¨a¨ then x=x-1
if inkey$=¨d¨ then x=x+1
if inkey$=¨q¨ then end
loop
As you can see, what I want to do is draw an orange line using the W-A-S-D direction keys and to exit when I press Q. Unfortunately, something seems to go wrong as when I run the program, the whole execution seems stuttered as if the CPU is very very busy ( and it is not trust me ) ... it´s like in those games where u have a low frame rate if u know what I´m talking about ... it seems interrupted as if it would be too complicated. I´ve tested the program on a Pentium 3 and a super Pentium 4 and the results are the same so there HAS TO BE something wrong within my code ... can anyone spot it ? please help me out and thanks

pebe
Full Member
Posts:33
Joined:Tue Apr 02, 2002 12:19 am
Location:Scotland

Post by pebe » Wed Nov 14, 2007 10:49 pm

As I recall, you cannot read inkey$ directly as you have done. I think you need an extra insruction after the 'pset' one that says:
a$=LCASE(inkey$) 'force to lower case in case entry is in caps
Then change the next insrtuctions to:
IF a$="w" THEN y=y-1
etc

As I said, I am going from memory and I may be adrift.

Mac
Full Member
Posts:48
Joined:Wed Jun 29, 2005 2:01 am
Contact:

Post by Mac » Thu Nov 15, 2007 4:15 am

pebe wrote:As I recall, you cannot read inkey$ directly as you have done.
You are definitely correct! Consider the following loop

1 pset(x,y),6
2 if inkey$="w" then y=y-1
3 if inkey$="s" then y=y+1
4 if inkey$="a" then x=x-1
5 if inkey$="d" then x=x+1
6 if inkey$="q" then end

I would guess that at most times, we are in instruction 1 which is the most time-consuming.

OK, now say you press "a".

Finally, instruction 1 finishes and 2 starts. As a result, the inkey$ function activates, and this is done:
2 if "a"="w" then y=y-1

Since "a"<>"w" nothing happens, but now the "a" you entered has been used up. Until you press another key, the sequence continues
3 if ""="s" then y=y+1
4 if ""="a" then x=x-1
5 if ""="d" then x=x+1
6 if ""="q" then end
1 pset(x,y),6
2 if ""="w" then y=y-1
3 if ""="s" then y=y+1

So you see that the only way you could get the program to honor your "a" is to press it at the exact time that instruction 3 is finishing. That is a rare occurrence.

Mac

Otringal
Newbie
Posts:6
Joined:Wed Nov 14, 2007 9:53 pm
Location:Romania

thanks but ...

Post by Otringal » Thu Nov 15, 2007 1:16 pm

thanks but ... hmm Mac, you said that only when I press ¨a¨ will the program go to instruction nr. 2 .... but how come ??? I mean the whole program is a loop .... doesn´t that repeat 18.2 times per second ??? why is it time consuming ? and also, I see that the LCASE$ thing works ... but why is that ??? I mean, when I press the A or a button, the inkey$ takes "a" by default, not "A" ... so why use LCASE anyway ? the input is already in small letters :( please help me understand

Mac
Full Member
Posts:48
Joined:Wed Jun 29, 2005 2:01 am
Contact:

Re: thanks but ...

Post by Mac » Thu Nov 15, 2007 5:17 pm

Otringal wrote:Mac, you said that only when I press ¨a¨ will the program go to instruction nr. 2 .... but how come ???
No, I said
--- OK, now say you press "a".
--- Finally, instruction 1 finishes

But instruction 1 would have finished anyway, whether any key was pressed or not. I was just trying to take a hypothetical case that you were in instruction 1 when you happened to press "a"
Otringal wrote:I mean the whole program is a loop .... doesn´t that repeat 18.2 times per second ??? why is it time consuming ?
No matter how fast the computer is, it still does one instruction at a time.

I can't explain easily how the operating system tests external devices like the keyboard, but basically after any instruction in a QBasic program has completed, the operating system tests external devices. In the case of the keyboard, if it detects a keypress, it puts the value into a buffer. There it sits until tested. Then it is removed.

Run the following program I just wrote for you and see if you start to comprehend. (Don't worry if you don't follow my code, the point is to see the program in operation)

Mac

Code: Select all

DECLARE SUB ShowBuf ()
DECLARE FUNCTION MyKey$ ()
DIM SHARED kbuf AS STRING
CLS : COLOR 3, 4: LOCATE , 30: PRINT "Study of a loop": PRINT
COLOR 0, 7
LOCATE , 4: PRINT "pset(x,y),6"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "w"; CHR$(34); " then y=y-1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "s"; CHR$(34); " then y=y+1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "a"; CHR$(34); " then x=x+1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "d"; CHR$(34); " then x=x-1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "q"; CHR$(34); " then end"
COLOR 7, 0
iloc = 1: x = 50: y = 50
CONST pbase = 10
DO
  ShowBuf
  LOCATE pbase + 2: PRINT "x ="; x; SPACE$(10); "y ="; y; SPACE$(10)
  LOCATE pbase + 4: PRINT SPACE$(10): tDelta = 2
  SELECT CASE iloc
  CASE 1: LOCATE pbase + 4, 1: PRINT "Doing PSET": tDelta = 5
  CASE 2: IF MyKey$ = "w" THEN y = y - 1
  CASE 3: IF MyKey$ = "s" THEN y = y + 1
  CASE 4: IF MyKey$ = "a" THEN x = x - 1
  CASE 5: IF MyKey$ = "d" THEN x = x + 1
  CASE 6:
    IF MyKey$ = "q" THEN
      LOCATE pbase + 6, 1: PRINT "q was recognized"
      END
    END IF
  END SELECT
  LOCATE iloc + 2, 1: PRINT "-->"
  t = TIMER + tDelta
  DO
    w$ = INKEY$
    IF LEN(w$) THEN
      IF w$ = CHR$(27) THEN LOCATE pbase + 6, 1: END
      kbuf = kbuf + w$
      ShowBuf
    END IF
  LOOP WHILE TIMER < t
  LOCATE iloc + 2, 1: PRINT "   "
  iloc = iloc + 1: IF iloc > 6 THEN iloc = 1
LOOP

FUNCTION MyKey$
SELECT CASE LEN(kbuf)
CASE 0: EXIT FUNCTION
CASE 1: MyKey$ = kbuf: kbuf = ""
CASE ELSE: MyKey$ = LEFT$(kbuf, 1): kbuf = MID$(kbuf, 2)
END SELECT
ShowBuf
END FUNCTION

SUB ShowBuf
CONST p = "Content of keyboard buffer: "
LOCATE pbase, 1: PRINT p + SPACE$(LEN(kbuf) + 2)
LOCATE pbase, LEN(p) + 1: PRINT kbuf
END SUB

Otringal
Newbie
Posts:6
Joined:Wed Nov 14, 2007 9:53 pm
Location:Romania

hmm

Post by Otringal » Thu Nov 15, 2007 5:26 pm

hmm I´ll try the code after I´m done with my homework :D ... in the meantime ... so if I press A and the first instruction is set to check for W, now just because A<>W, the bufer will loose the A value and the INKEY$ will remain with nothing until the next press ???

Mac
Full Member
Posts:48
Joined:Wed Jun 29, 2005 2:01 am
Contact:

Re: thanks but ...

Post by Mac » Thu Nov 15, 2007 8:23 pm

Otringal wrote:doesn´t that repeat 18.2 times per second
Don't know where you got 18.2 times per second. Here is a revised demo to show what is happening while a clock is showing time.

Mac

Code: Select all

DECLARE SUB ShowBuf ()
DECLARE FUNCTION MyKey$ ()
DEFSTR A-Z
DIM SHARED kbuf AS STRING, Delta AS SINGLE
DIM Clock AS DOUBLE, InsTime AS DOUBLE
CLS
PRINT "Wait 20 seconds while I see how fast your computer is..."
DIM t AS DOUBLE, c AS LONG
FOR n% = 1 TO 20
  t = TIMER + 1
  DO WHILE TIMER < t: c = c + 3: LOOP
  PRINT n%;
NEXT n%
PRINT : PRINT
PRINT "I found you do"; c; "QBasic instructions in 20 seconds"
PRINT "Which is"; c / 20; "instructions in one second"
InsTime = 1 / (c / 20)
PRINT "Thus on the average one instruction takes ";
PRINT MID$(STR$(1 + InsTime), 3); " seconds."
Clock = 1000
PRINT : PRINT "Let's assume that the pset takes 5 times the average"
PRINT "And at the beginning, the computer clock is"; Clock
PRINT "Then after the pset, the clock will be"; Clock + (5 * InsTime)
PRINT : PRINT "And assume an IF statement is 2 times the average"
PRINT "Then next the clock will be"; Clock + (7 * InsTime)
PRINT : LINE INPUT "Press Enter to begin simulating"; e$

CONST pbase = 12
CLS : COLOR 15, 4: LOCATE , 10
PRINT "Study to show you can't have multiple INKEY$ tests in a loop"
PRINT
COLOR 0, 7
LOCATE , 4: PRINT "pset(x,y),6"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "w"; CHR$(34); " then y=y-1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "s"; CHR$(34); " then y=y+1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "a"; CHR$(34); " then x=x-1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "d"; CHR$(34); " then x=x+1"
LOCATE , 4: PRINT "if inkey$="; CHR$(34); "q"; CHR$(34); " then end"
COLOR 7, 0
DIM x AS INTEGER, y AS INTEGER
x = 50: y = 50
DIM tDelta AS INTEGER ' Assume PSET takes 5, IF takes 2.
DIM oLoc AS INTEGER, iLoc AS INTEGER ' Instruction being executed
iLoc = 1' Start here
DO
  ShowBuf
  LOCATE pbase + 2: PRINT "x ="; x; SPACE$(10); "y ="; y; SPACE$(10)
  LOCATE pbase + 4: PRINT SPACE$(80): tDelta = 2
  LOCATE oLoc + 2, 1: PRINT "   "
  LOCATE iLoc + 2, 1: PRINT "-->"
  LOCATE pbase + 4, 1
  SELECT CASE iLoc
  CASE 1: PRINT "Doing PSET": tDelta = 5
  CASE 2: IF MyKey$ = "w" THEN y = y - 1
  CASE 3: IF MyKey$ = "s" THEN y = y + 1
  CASE 4: IF MyKey$ = "a" THEN x = x - 1
  CASE 5: IF MyKey$ = "d" THEN x = x + 1
  CASE 6:
    IF MyKey$ = "q" THEN
      LOCATE pbase + 6, 1: PRINT "q was recognized"
      END
    END IF
  END SELECT
  DIM t1 AS DOUBLE, t2 AS DOUBLE
  t1 = TIMER + tDelta
  t2 = TIMER + InsTime
  DO
    IF TIMER > t2 THEN
      Clock = Clock + InsTime
      LOCATE pbase - 2, 1
      PRINT "Computer Clock:"; Clock; SPACE$(20)
      t2 = TIMER + InsTime
    END IF
    w$ = INKEY$
    IF LEN(w$) THEN
      IF w$ = CHR$(27) THEN LOCATE pbase + 6, 1: END
      kbuf = kbuf + w$
      ShowBuf
    END IF
  LOOP WHILE TIMER < t1
  oLoc = iLoc
  iLoc = iLoc + 1: IF iLoc > 6 THEN iLoc = 1
LOOP

DEFSNG A-Z
FUNCTION MyKey$
SELECT CASE LEN(kbuf)
CASE 0: PRINT "No key to process": EXIT FUNCTION
CASE 1: w$ = kbuf: kbuf = ""
CASE ELSE: w$ = LEFT$(kbuf, 1): kbuf = MID$(kbuf, 2)
END SELECT
klin = CSRLIN
PRINT "INKEY$ now returning [";
COLOR 11, 9: PRINT w$; : COLOR 7, 0: PRINT "] ";
LINE INPUT "Press Enter to continue"; e$
LOCATE klin, 1: PRINT SPACE$(80)
ShowBuf
MyKey$ = w$
END FUNCTION

SUB ShowBuf
CONST p = "Content of keyboard buffer: "
LOCATE pbase, 1: PRINT p + SPACE$(LEN(kbuf) + 5)
LOCATE pbase, LEN(p) + 1
PRINT "["; : COLOR 11, 9: PRINT kbuf; : COLOR 7, 0: PRINT "]"
COLOR 7, 0
END SUB

Otringal
Newbie
Posts:6
Joined:Wed Nov 14, 2007 9:53 pm
Location:Romania

well

Post by Otringal » Thu Nov 15, 2007 8:29 pm

well a loop repeats every 55 milliseconds and that is equal with 18.2 CPU ticks ... on all processors, no matter how fast they are. I will compile your code soon enough ;) and thanks

pebe
Full Member
Posts:33
Joined:Tue Apr 02, 2002 12:19 am
Location:Scotland

Re: well

Post by pebe » Thu Nov 15, 2007 8:36 pm

Otringal wrote:well a loop repeats every 55 milliseconds and that is equal with 18.2 CPU ticks ... on all processors, no matter how fast they are. I will compile your code soon enough ;) and thanks
Not so. The speed of a loop depends on its length (number of instructions) and the processor speed. Are you getting mixed up with the rate at which the OS reads the system clock?

Edited:
Try this loop. My computer will go a million times through the loop in 0.2734sec.

r# = 1000000
t1! = TIMER
DO
r# = r# - 1
LOOP UNTIL r# = 0
t2! = TIMER
time! = t2! - t1!
PRINT time!

Otringal
Newbie
Posts:6
Joined:Wed Nov 14, 2007 9:53 pm
Location:Romania

what ?

Post by Otringal » Thu Nov 15, 2007 9:53 pm

every BASIC language derived from the classic BASIC will tell u in the Help ( I don´t remember the exact section ) that a loop will be scanned 18.2 times per second or once every 55 milliseconds ... that´s the HIGHEST rate

pebe
Full Member
Posts:33
Joined:Tue Apr 02, 2002 12:19 am
Location:Scotland

Post by pebe » Thu Nov 15, 2007 10:05 pm

I've never heard of that.

But don't take my word for it. Try the little program above.

Buff
Jr. Member
Posts:22
Joined:Wed May 19, 2004 3:07 pm
Contact:

Post by Buff » Fri Nov 16, 2007 1:46 am

if you only want it to respond to your keyboard input then change
if inkey$=...
to
if a$=...
above those statements use
while a$="":a$=inkey$:wend

at the bottom of the do loop use
a$=""

Code: Select all

DO
  WHILE A$="":A$=INKEY$:A$=UCASE$(A$):WEND
  IF A$="W" then...
 
  IF A$="W" or A$="A" ..... then pset(x,y),6
  A$=""
LOOP

Mac
Full Member
Posts:48
Joined:Wed Jun 29, 2005 2:01 am
Contact:

Post by Mac » Fri Nov 16, 2007 3:21 am

Buff wrote:if you only want it to respond to your keyboard input then ...
Good point. The PSET is probably no impact at all on response from the keyboard, but esthetically it is wasted when the point has not changed.

Another version below, but why waste our time? He refuses to believe that INKEY$ clears the input buffer. He hasn't run my demo that clearly shows how a computer operates. Oh, well, can't resist trying.

Mac

Code: Select all

SCREEN 12
DIM x AS INTEGER, y AS INTEGER
x = 50: y = 50: PSET (x, y), 6
DO
  DO: k$ = INKEY$: LOOP WHILE k$ = ""
  SELECT CASE k$
  CASE "w": y = y - 1
  CASE "s": y = y + 1
  CASE "a": x = x - 1
  CASE "d": x = x + 1
  CASE "q": EXIT DO
  CASE ELSE: k$ = ""
  END SELECT
  IF k$ <> "" THEN PSET (x, y), 6
LOOP
LOCATE 25, 1: LINE INPUT "Piece of Cake - Now press ENTER"; e$
CLS
SYSTEM

Otringal
Newbie
Posts:6
Joined:Wed Nov 14, 2007 9:53 pm
Location:Romania

sorry

Post by Otringal » Fri Nov 16, 2007 5:35 am

oh sorryy .... last night I wanted to try both codes u gave me and my DOS commands won´t work on Windows anymore ... I will have to reinstall my WINXP today as it was damaged long time ago ... and I REALLY wanna try your codes to see how it works ;)

Post Reply