Posts: 243
Threads: 12
Joined: Aug 2001
Nice work, Meg!
I still had a problem, not having the high scores file, so I did this:
Code: OPEN "BOWLING.HSR" FOR BINARY AS #1
MyLOF = LOF(1)
CLOSE
IF MyLOF > 0 THEN
OPEN "BOWLING.HSR" FOR INPUT AS #1 'OPEN HIGHSCORE FILE
INPUT #1, HighScore.Points% 'GET SCORE FROM FILE
LINE INPUT #1, HighScore.Name$ 'GET NAME FROM FILE
CLOSE #1 'CLOSE HIGHSCORE FILE
ELSE
HighScore.Points% = 0
HighScore.Name$ = "(None)"
OPEN "BOWLING.HSR" FOR OUTPUT AS #1 '..OPEN HISCORE FILE
PRINT #1, Score% '..SAVE SCORE TO FILE
PRINT #1, YourName$ '..SAVE NAME TO FILE
CLOSE #1 '..CLOSE HISCORE FILE
END IF
PRINT "HI-SCORE: ";
PRINT HighScore.Points%; "BY "; HighScore.Name$ 'SHOW THE HIGH SCORE
That would be in the initialization. The other read, testing for high score, can just be a simple OPEN.
Mac
P.S. Novel convention, indenting with OPEN. Many programs have the OPEN and CLOSE far removed, so most never think of it as something like DO LOOP requiring indentation of intervening commands.
Posts: 480
Threads: 24
Joined: Mar 2003
Good adjustment. Yeah, I'm pretty crazy about indentation and comments and whatnot (as you can prolly tell from my code sampes all over this forum).
When I write code, I *always* end the loop/whatever as soon as I write the first line:
Code: FOR i% = 1 TO 10
NEXT i%
OPEN "file.dat" FOR INPUT AS #1
CLOSE #1
WHILE INKEY$ = ""
WEND
Then, I put a space between 'em and start writing the guts, indented. It drives me crazy if I ever write the top line without the bottom one immediately following. >.>
*peace*
Meg.
Posts: 75
Threads: 11
Joined: Nov 2003
It seems like some of you don't care for "GOTO" statments/commands.
It would be safe then to say that you wouldn't like to use the:
JP 120, JE 130, and JNE 140 commands in asm then, right?
(The 120,130,140 are all arbitrary numbers of course.)
As these equate with: JP 120 = GOTO 120 , JE 130 = IF A = A THEN GOTO 130, and JNE 140 = IF A<>B THEN GOTO 140 statments.
The "block" statments make it easier to read/follow (for some), but the GOTO statments can actually min. the size of the program as well as the speed of the program.
Like it or not, in the BLOCK formation each and every line of code is still evaluated(sp?) until the THEN is reached. Even if the first line makes it true. The rest is then compared against the flag, that has already been set if the true statment has been reached to see if it was set. :o
Me thinks we all have our own preferences; and with that in mind, I feel it's safe to say that one way is neither better nor worse than the other. :wink:
(O.K. kids...Have at it!)
adsherm
Posts: 3,279
Threads: 170
Joined: Nov 2003
I indent OPEN...CLOSE sections as well. It makes sense to me to do it...after all, you've got something started (kind of like a DO...LOOP or a FOR...NEXT), so might as well indent all the stuff that happens within that "thing" so you know what goes on between the time it's opened and the time it's closed.
dadsherm: it's been said a million times that in assembly, jumping is your only option; aka you HAVE to use "GOTO". In QB, you don't have to use it...it's not required and if overused, can make debugging a nightmare. The whole reason DO...LOOP and other such code blocks were invented was to make a coder's life easier and make code easier to read. Using GOTOs still has its purposes, but like any tool, can be dangerous in unskilled hands. It's very useful for escaping redundant loops but very bad for major program flow operations.
I'd knock on wood, but my desk is particle board.
Posts: 480
Threads: 24
Joined: Mar 2003
My issue with this program are not that GOTOs are used; it is *how* they are used. The logical flow of the original posted code was terribly unefficient. It looped via GOTO when no loop was needed, running over the same code multiple times when it only needed to be processed once.
Sure, discounting the problem of computer speed--which I attempted to adjust for via my updated code--it is just a matter of opinion. *My* opinion is that code is much easier to plan, follow, and debug if your loops and program jumps make logical sense according to your variables:
If you are bowling and need 10 frames: make a variable Frame% and a FOR/NEXT loop from 1 to 10.
If you are moving a ball left and right while waiting for a keypress: have variables hold the ball's coordinates and the ball's direction, instead of two blocks of code, one which moves right, and one that moves left, with conditional goto statements redirecting program flow after running.
Basically, I like to be able to see where the program is going when the loop STARTS, instead of finding the GOTO and figuring out where it jumps to AFTER the "guts" of the loop have been executed the first time.
Yes, I'll admit it is just opinion in the end. In the meanwhile, I will continue to preach easy-to-follow coding practices to beginner-ish programers, because I believe that it will enable them to advance further by not having to go crazy figuring out why their program doesn't run properly when they do inevitably make a mistake, as we all do. :)
*peace*
Meg.
Posts: 75
Threads: 11
Joined: Nov 2003
Meg and adosorken,
I agree with both of you, well with the exception of the " have to use them" in asm; However to not use them really restricts the size of the program. :roll:
A person can use GOTO's to the extenct that it makes a plate of spagetti look like a straight line. :o
(I remember that's how some of mine were in the beggining days of programming :oops
I guess what I was refering to, are those that look at GOTO commands as an unnecessary evil.
Oh well. I just thought I'd share that with those that read this thread. :wink:
adsherm
Posts: 6,419
Threads: 74
Joined: Mar 2002
Again... I think I'll set the original post in favourites and link to it everytime.
GOTO is useful in several scenarios.
It should be avoided if you are a bad coder or a newbie, but once you know what you are doing, a "GOTO" in time will save your guts, and won't turn your code into spaghetti.
Of course it 'can' be avoided, but you can get faster code using it in some places.
For example, exit a 27 nested loops structure. Without GOTO: you have to go through 27 comparisons. With GOTO: you just jump out.
Don't say "GOTO is bad" just 'cause you listened it somewhere. Specially when you haven't thought in all its applications.
Posts: 243
Threads: 12
Joined: Aug 2001
I further modified the program to allow the user to speed up or slow down the ball movements, etc.
Whenever anything is happening, you can hold down ALT to speed it up or hold down CTRL to slow it down.
This is kept in the high scores file so next time you play, you have the same speed.
Mac
Code: DECLARE SUB Speed (c%)
'THIS PROGRAM IS A SUBMISSION TO QBASICNEWS FORUM WRITTEN BY JOHN KREITLOW.
'IT HAS BEEN REORGANIZED TO REMOVE GOTOs, UNNEEDED LOOPS, AND GENERALLY MADE
'QUITE A BIT EASIER TO FOLLOW, LOGICALLY. PLEASE LET ME KNOW IF THERE ARE
'ANY CHANGES I MADE WHICH ARE TOO DIFFICULT TO UNDERSTAND. THANKS!
'
' - 01/27/2005 MB.
'Also changed by Mac to remove excess file IO (Only read once and only write
'if there are changes).
'Also changed by Mac to allow the user to change speed of operations
' increase (Hold down ALT key)
' decrease (Hold Down CTRL key)
'These changes are recorded for subsequent runs
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Subroutine and Function declarations.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DECLARE SUB Initialize () 'SET UP INITIAL PROGRAM STATE
DECLARE SUB Intro () 'DISPLAY INTRO SCREEN
DECLARE SUB Instructions () 'DISPLAY GAME DIRECTIONS
DECLARE SUB ResetPins () 'MAKE ALL PINS STANDING
DECLARE SUB DrawLane () 'DRAW THE LANE, PINS, AND INFO
DECLARE SUB RollBall () 'ROLL THE BALL, AND CHECK COLLISIONS
DECLARE SUB HitPin (n%) 'RECURSIVE PIN-COLLISION ROUTINE
DECLARE SUB StrikeOrSpare () 'FLASH A MESSAGE FOR STRIKE OR SPARE
DECLARE SUB GameOver () 'END THE CURRENT GAME
DECLARE SUB CheckHighScore () 'SEE IF USER SET A NEW HIGH SCORE
DECLARE FUNCTION GetBallColor% () 'CHOOSE BALL COLOR
DECLARE FUNCTION GetLane% () 'CHOOSE LANE TO RELEASE BALL DOWN
DECLARE FUNCTION GetPower% () 'CHOOSE POWER OF BALL ***NOT USED***
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'The following variables can be used / changed in any subroutine or function
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
COMMON SHARED adjScore% '# OF POINTS SCORED IN CURRENT ROLL
COMMON SHARED Score% 'TOTAL SCORE FOR THE GAME
COMMON SHARED Frame% 'WHICH FRAME IT IS [1 THROUGH 10]
COMMON SHARED Roll% 'WHICH ROLL IT IS [1 THROUGH 2]
COMMON SHARED QuitFlag% '0=CONTINUE GAME, 1=END GAME
COMMON SHARED OneSecond& '# OF LOOPS COMPUTER RUNS / SECOND
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Get High Score and Speed Settings from file (or defaults if no file)
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
TYPE HSS
UserHigh AS INTEGER 'High Score
UserName AS STRING * 20 'Name of Player
S1 AS INTEGER '{
S2 AS INTEGER '{ See SPEED commands
S3 AS INTEGER '{ for usage of this
S4 AS INTEGER '{ speed
S5 AS INTEGER '{
END TYPE
DIM SHARED HSS AS HSS
OPEN "BOWLING.HSS" FOR BINARY AS #1: MyLOF = LOF(1): CLOSE
IF MyLOF = LEN(HSS) THEN 'Correct LengthOfFile (LOF)
OPEN "BOWLING.HSS" FOR RANDOM AS #1 LEN = LEN(HSS)
GET #1, 1, HSS
CLOSE
ELSE
HSS.UserHigh = 0
HSS.UserName = "(None)"
HSS.S1 = 5
HSS.S2 = 50
HSS.S3 = 8
HSS.S4 = 80
HSS.S5 = 7
END IF
' Make a copy to see if user made any changes during game
DIM SHARED HSSOrig AS HSS
HSSOrig = HSS
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Variable TYPE declarations.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
TYPE BallType
x AS INTEGER 'X-COORDINATE OF BALL
y AS INTEGER 'Y-COORDINATE OF BALL
c AS INTEGER 'COLOR OF BALL
p AS INTEGER 'POWER OF BALL ***NOT USED***
END TYPE
DIM SHARED Ball AS BallType 'CREATE A BALL
TYPE PinType
x AS INTEGER 'X-COORDINATE OF PIN
y AS INTEGER 'Y-COORDINATE OF PIN
Up AS INTEGER 'IS THE PIN STANDING? 1=YES 0=NO
END TYPE
DIM SHARED Pin(1 TO 10) AS PinType 'CREATE ARRAY OF 10 PINS
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'These next few lines set up the game to be played.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
CALL Initialize 'INITIALIZE SOME GAME VARIABLES
CALL Intro 'SHOW THE INTRO SCREEN
Ball.c = GetBallColor% 'GET DESIRED BALL COLOR FROM USER
CALL Instructions 'DISPLAY GAME INSTRUCTIONS
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Here is the main game loop. This runs through 10 frames, 2 rolls per frame
'unless the user hits the escape key. If a strike is bowled, the 2nd roll
'gets skipped for that frame.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DO WHILE QuitFlag% = 0 '---MAIN GAME LOOP UNTIL QuitFlag%---
Score% = 0 'SET TOTAL GAME SCORE TO ZERO
FOR Frame% = 1 TO 10 ' ----THIS LOOPS EACH NEW FRAME----
CALL ResetPins ' SET ALL THE PINS TO STANDING
FOR Roll% = 1 TO 2 ' ---THIS LOOPS EACH NEW ROLL---
CALL DrawLane ' DRAW THE LANE, PINS, & INFO
Ball.x = GetLane% ' USER SELECTS LANE TO BOWL DOWN
IF QuitFlag% = 1 THEN ' DID THEY HIT ESCAPE?
Roll% = 2 ' ..YES. THEY CANCELLED BOWL.
Frame% = 10 ' ....SKIP ALL REMAINING FRAMES.
ELSE ' ..NO. THEY ACTUALLY BOWLED.
Ball.p = GetPower% ' ....***POWER DOES NOTHING***
CALL RollBall ' ....ROLL THE BALL DOWN LANE.
END IF '
NEXT Roll% ' -----END OF THE ROLL LOOP-----
NEXT Frame% ' ------END OF THE FRAME LOOP------
CALL GameOver ' END THE CURRENT BOWLING GAME
LOOP '----END LOOP WHEN QuitFlag% IS 1----
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'End the program, return control to the O/S after writing HSS file
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Diffs = 0 ' To see if there are any differences
IF HSS.UserHigh <> HSSOrig.UserHigh THEN Diffs = -1
IF HSS.UserName <> HSSOrig.UserName THEN Diffs = -1
IF HSS.S1 <> HSSOrig.S1 THEN Diffs = -1
IF HSS.S2 <> HSSOrig.S2 THEN Diffs = -1
IF HSS.S3 <> HSSOrig.S3 THEN Diffs = -1 ' -1 is BOOLEAN TRUE (0 is FALSE)
IF HSS.S4 <> HSSOrig.S4 THEN Diffs = -1
IF HSS.S5 <> HSSOrig.S5 THEN Diffs = -1
IF Diffs THEN
OPEN "BOWLING.HSS" FOR RANDOM AS #1 LEN = LEN(HSS)
PUT #1, 1, HSS
CLOSE
END IF
SYSTEM
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'This data contains the x- and y-coordinates of the 10 pins. The Initialize
'subroutine loads this data into the 10-element array, Pin().
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DATA 70 , 10
DATA 110 , 10
DATA 150 , 10
DATA 190 , 10
DATA 90 , 30
DATA 130 , 30
DATA 170 , 30
DATA 110 , 50
DATA 150 , 50
DATA 130 , 70
SUB CheckHighScore
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Check to see whether the user has beaten the high score.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IF Score% > HSS.UserHigh THEN 'HIGH SCORE BEATEN!!
PRINT "CONGRATULATIONS! YOU BEAT THE HIGH" '..\
PRINT "SCORE. YOU SHOULD BE IN THE HALL" '.. > DISPLAY MESSAGE
PRINT "OF FAME!" '../
PRINT
PRINT "OLD HISCORE: "; HSS.UserHigh '..\ SHOW OLD BEST
PRINT "MADE BY: "; HSS.UserName '../ SCORE AND NAME
PRINT
PRINT "YOUR SCORE:"; Score% '..SHOW YOUR SCORE
INPUT "PLEASE ENTER YOUR NAME: ", HSS.UserName '..GET USER NAME
HSS.UserHigh = Score% '..SAVE SCORE
ELSE 'HIGH SCORE NOT BEATEN
PRINT "TOTAL SCORE:" '..\
PRINT Score% '../ SHOW USER SCORE
END IF
END SUB
SUB DrawLane
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Draw the bowling lane. This will happen at the start of each roll.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SCREEN 7 '\ SET AND CLEAR
CLS '/ THE SCREEN
FOR i% = 1 TO 10 '-START LOOP 1 TO 10--
IF Pin(i%).Up THEN 'IS THIS PIN STANDING?
CIRCLE (Pin(i%).x, Pin(i%).y), 5, 15 ' ..YES, SO DRAW IT.
END IF
NEXT i% '---END LOOP AT 10----
LINE (300, 10)-(310, 190), 4, BF 'DRAW RED BOX ON RIGHT
LINE (30, 10)-(30, 190), 15 'DRAW WHITE LINE LEFT
LINE (230, 10)-(230, 190), 15 'DRAW WHITE LINE RIGHT
COLOR 15 'SET COLOR: WHITE
LOCATE 2, 30: PRINT "SCORE:" '\
LOCATE 3, 30: PRINT Score% ' \
LOCATE 5, 30: PRINT "FRAME:" ' \ SHOW THE SCORE,
LOCATE 6, 30: PRINT Frame% ' / FRAME, AND ROLL
LOCATE 8, 30: PRINT "ROLL:" ' /
LOCATE 9, 30: PRINT Roll% '/
END SUB
SUB GameOver
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Either the user bowled the last frame, or hit escape during play.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SCREEN 0 '\
WIDTH 80, 25 ' > SET & CLEAR SCREEN
CLS '/
CALL CheckHighScore 'CHECK FOR NEW HISCORE
PRINT
PRINT "CREATED BY JOHN KREITLOW" '\ CLOSING GAME
PRINT "IN ASSOCIATION WITH RADIUM-V" '/ CREDITS
PRINT
PRINT "Play Again? (Y/N)" 'WANT TO PLAY AGAIN?
DO '-----START LOOP------
k$ = UCASE$(INKEY$) 'MONITOR KEYPRESS
LOOP UNTIL k$ = "Y" OR k$ = "N" '---END WHEN Y OR N---
IF k$ = "N" THEN QuitFlag% = 1 ELSE QuitFlag% = 0 'SET QuitFlag%
END SUB
FUNCTION GetBallColor%
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Change to Screen Mode 7 to display the balls and clear keyboard buffer.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
WHILE INKEY$ <> "": WEND
SCREEN 7
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Make a string to hold the seven ball color values.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
BallColors$ = "01020304051214"
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Display all seven balls, and a message prompting selection.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
FOR i% = 1 TO 7
CIRCLE (i% * 40 - 5, 10), 10, VAL(MID$(BallColors$, i% * 2 - 1, 2))
NEXT i%
LOCATE 12, 5: PRINT "PLEASE SELECT YOUR BALL COLOR."
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'ArrowX% and ArrowY% store the coordinates of the selection indicator.
'By adjusting the ArrowY% value inside of a loop and a random color,
'the indicator appears to be pointing at the selected ball and flashing.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ArrowX% = 5 'START X-COORD
DO
ArrowY% = 8 'START Y-COORD
DO
ArrowY% = ArrowY% - 1 'MOVE ARROW UP
IF ArrowY% = 4 THEN ArrowY% = 7 'RESET ARROW
COLOR INT(RND * 15) + 1 'RANDOM COLOR
LOCATE ArrowY%, ArrowX%: PRINT CHR$(127); 'DRAW ARROW
Speed HSS.S1 'SHORT PAUSE
LOCATE ArrowY%, ArrowX%: PRINT " "; 'ERASE ARROW
k$ = UCASE$(INKEY$) 'CHECK KEYPRESS
LOOP UNTIL k$ <> "" 'EXIT ON KEYPRESS
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'If the user hits left or right arrow keys, adjust ArrowX% if able.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SELECT CASE k$
CASE CHR$(0) + "K"
IF ArrowX% > 5 THEN ArrowX% = ArrowX% - 5
CASE CHR$(0) + "M"
IF ArrowX% < 35 THEN ArrowX% = ArrowX% + 5
END SELECT
LOOP UNTIL k$ = CHR$(13)
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Return to Screen Mode 0.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SCREEN 0
WIDTH 80, 25
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Set the return value of the function to the appropriate color value.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
GetBallColor% = VAL(MID$(BallColors$, (ArrowX% \ 5) * 2 - 1, 2))
END FUNCTION
FUNCTION GetLane%
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'This function returns the lane down which the user rolls their ball.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
WHILE INKEY$ <> "": WEND 'CLEAR KEYBOARD BUFFER
x% = 41 'WHERE BALL IS
xAdj% = 1 'DIRECTION IT'S GOING
DO '-----START LOOP------
x% = x% + xAdj% 'MOVE BALL
IF x% = 41 OR x% = 219 THEN xAdj% = -xAdj% 'REVERSE DIRECTION
CIRCLE (x%, 190), 10, Ball.c 'DRAW BALL IN COLOR
Speed HSS.S2 'PAUSE SHORT MOMENT
CIRCLE (x%, 190), 10, 0 'ERASE BALL
k$ = INKEY$ 'CHECK FOR KEYPRESS
LOOP UNTIL k$ = CHR$(13) OR k$ = CHR$(27) '-END @ ENTER OR ESC--
IF k$ = CHR$(27) THEN QuitFlag% = 1 'IF ESC, SET QuitFlag%
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'This next formula looks complex. Basically, we want the ball's x-coord
'to be: 50, 70, 90, 110, 130, 150, 170, 190, or 210. This formula says:
'
' if ball is between 40 and 60, make it 50
' if ball is between 60 and 80, make it 70
'
' etc, etc...
'
' if ball is between 180 and 200, make it 190
' if ball is between 200 and 220, make it 210
'
'Again, let me know if you have trouble following how this works.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
GetLane% = ((x% - 40) \ 20) * 20 + 50 'CENTER BALL IN LANE
END FUNCTION
FUNCTION GetPower%
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
' *** NOTE TO JOHN ***
'
' I spent a while looking through your code and couldn't figure
'out how the power of the ball affected anything. So I just left
'that part of of the re-written code. However, if you want it in
'here, either let me know, or write it in this area. =)
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
END FUNCTION
SUB HitPin (n%)
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'This routine uses recursion to calculate your score for this roll. It
'it passed the value of the pin your ball hit, then checks to see is the
'pin is standing or not. If it is not, nothing happens and your score
'is unchanged. If the pin is standing, it knocks it over, then calls
'HitPin (itself) on any pins that first pin might have bumped into.
'The variable adjScore% keeps track of the total pin count of the roll.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'First of all, check to see whether a strike or spare was rolled, since
'either of these results in a special score value (i.e. not just the
'number of pins that got knocked over).
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IF n% = 10 THEN 'SPARE OR STRIKE!
IF Roll% = 1 THEN '1ST ROLL, SO STRIKE
CALL StrikeOrSpare '..FLASH MESSAGE
adjScore% = 30 '..SET adjScore% TO 30
Roll% = 2 '..NEXT ROLL SKIPPED
ELSE '2ND ROLL, SO SPARE.
CALL StrikeOrSpare '..FLASH MESSAGE
adjScore% = 20 '..SET adjScore% TO 20
END IF
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'If the 10-pin (front pin) is not hit, there is no strike or spare. So
'next we check to see if the pin is standing. If so, make it knocked
'down, erase it from screen, and increase adjScore% variable.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ELSE 'NO SPARE OR STRIKE!
IF Pin(n%).Up = 1 THEN 'THE PIN IS STANDING
Pin(n%).Up = 0 '..KNOCK IT OVER
CIRCLE (Pin(n%).x, Pin(n%).y), 5, 0 '..ERASE IT
adjScore% = adjScore% + 1 '..ADD 1 TO adjScore%
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Since the pin was standing, we need to see what other pins it
'might knock into. For each one of those, we call HitPin sub.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
SELECT CASE n% 'WHICH PIN ARE WE LOOKING AT?
CASE 5 '..PIN 5
HitPin 1 ' ..PIN 5 HITS PIN 1
HitPin 2 ' ..PIN 5 HITS PIN 2
CASE 6 '..PIN 6
HitPin 2 ' ..PIN 6 HITS PIN 2
HitPin 3 ' ..PIN 6 HITS PIN 3
CASE 7 '..PIN 7
HitPin 3 ' ..PIN 7 HITS PIN 3
HitPin 4 ' ..PIN 7 HITS PIN 4
CASE 8 '..PIN 8
HitPin 5 ' ..PIN 8 HITS PIN 5
HitPin 6 ' ..PIN 8 HITS PIN 6
CASE 9 '..PIN 9
HitPin 6 ' ..PIN 9 HITS PIN 6
HitPin 7 ' ..PIN 9 HITS PIN 7
END SELECT
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Recursion is kind of tricky to understand at first. Imagine
'if you hit pin 9 first. Well, you get 1 point for that, and
'also hit pins 6 and 7. Well, when HitPin 6 and 7 get called,
'those each give you one point. HitPin 6 then hits 2 and 3,
'while HitPin 7 hits pins 3 and 4. But because HitPin 6
'already called HitPin 3, by the time HitPin 7 calls HitPin 3,
'Pin 3 is already knocked over. Let me know if you have any
'trouble following the logic here. =)
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
END IF
END IF
END SUB
SUB Initialize
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Seed the RND() function, set the screen mode.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
RANDOMIZE TIMER 'SEED THE RND() FUNCTION
SCREEN 0 '\
WIDTH 80, 25 ' > SET & CLEAR SCREEN
CLS '/
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Initialize the x- and y-coordinates of the 10 pins and QuitFlag%
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
FOR i% = 1 TO 10 '---START LOOP FIRST PIN---
READ Pin(i%).x 'READ X-COORD FROM DATA
READ Pin(i%).y 'READ Y-COORD FROM DATA
NEXT i% '---END LOOP @ TENTH PIN---
QuitFlag% = 0 'INITIALIZE QuitFlag% TO 0
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Because different computers will run this game at different speeds, we
'need to figure out how fast this computer is running it, so that we can
'make sure pauses within the program always pause for the same length of
'time. To do this, we need to see how many loops this computer goes
'through in one second. We will save this number as OneSecond& and use
'it for all calls to the Pause() sub in the game code.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
PRINT "Determining computer speed..."; 'NOTIFY USER OF SPEED TEST
MarkedTime# = TIMER 'MARK START TIME
FOR t& = 1 TO 2000000 '---LOOP 2 MILLION TIMES---
NEXT t& '---------END LOOP---------
OneSecond& = 2000000 / (TIMER - MarkedTime#) 'CALCULATE LOOPS PER SECOND
PRINT "Done! OneSecond&="; OneSecond& 'NOTIFY USER TEST COMPLETED
END SUB
SUB Instructions
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Explain to the user how to play.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
CLS
PRINT "BOWLING"
PRINT "CREATED BY JOHN KREITLOW"
PRINT "IN ASSOCIATION WITH RADIUM-V"
LOCATE 5, 18: PRINT "BASED ON ACME SOFTWARE'S `BOWLIN' FOR THE TI-83"
PRINT
LOCATE 7, 31: PRINT "PRESS SPACE TO START"
LOCATE 8, 31: PRINT "PRESS ESCAPE TO QUIT"
LOCATE 9, 32: PRINT "+---------------+"
LOCATE 10, 32: PRINT "| LANE RULES |"
LOCATE 11, 32: PRINT "+---------------+"
PRINT
PRINT "STRIKE = 30 POINTS"
PRINT "SPARE = 20 POINTS"
PRINT "HIT `ENTER' AT WANTED SPACE ON THE LANE TO SELECT IT."
PRINT "SELECT STRENGTH, INDICATED AT BASE OF POWER METER. CHOOSE"
PRINT "QUICKLY, BECAUSE YOU WILL MISS A TURN IF YOU TAKE TOO LONG!"
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Show the user the current high score.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
PRINT "HI-SCORE: "; HSS.UserHigh;
PRINT "BY "; HSS.UserName 'SHOW THE HIGH SCORE
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Wait for a keypress. Spacebar will start the game. Escape will quit.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DO '-----START LOOP------
k$ = UCASE$(INKEY$) 'MONITOR KEYPRESSES
LOOP UNTIL k$ = " " OR k$ = CHR$(27) '-END AT SPACE OR ESC-
IF k$ = CHR$(27) THEN QuitFlag% = 1 'IF ESC, SET QuitFlag%
END SUB
SUB Intro
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Draw an intro screen showing a ball rolling a strike.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
CLS 'CLEAR THE SCREEN
LOCATE 2, 37: PRINT "O O O O" '\
LOCATE 3, 37: PRINT " O O O" ' \ DRAW A RACK OF PINS
LOCATE 4, 37: PRINT " O O" ' / AT TOP OF THE SCREEN
LOCATE 5, 37: PRINT " O" '/
FOR i% = 23 TO 1 STEP -1 '---START LOOP BALL AT BOTTOM---
LOCATE i%, 37 'POSITION CURSOR AT BALL'S SPOT
PRINT " 0 "; 'DRAW ERASING LINE WITH BALL
Speed HSS.S3 'SHORT PAUSE
LOCATE i%, 40 'POSITION CURSOR AT BALL'S SPOT
PRINT " "; 'ERASE THE BALL
NEXT i% '---END LOOP WHEN BALL AT TOP---
END SUB
SUB ResetPins
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Set all 10 pins so that they are standing.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
FOR i% = 1 TO 10 '---START LOOP 1 THRU 10---
Pin(i%).Up = 1 'SET THIS PIN TO STANDING
NEXT i% '------END LOOP AT 10------
END SUB
SUB RollBall
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Roll ball down the lane, see what pins are hit, and determine scoring.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
FOR y% = 190 TO -5 STEP -1 '---START LOOP BALL AT BOTTOM---
CIRCLE (Ball.x, y%), 10, Ball.c 'DRAW BALL IN PICKED COLOR
Speed HSS.S4 'PAUSE A BRIEF MOMENT
CIRCLE (Ball.x, y%), 10, 0 'COVER BALL WITH BLACK CIRCLE
NEXT y% '---END LOOP WHEN BALL AT TOP---
adjScore% = 0 'AMOUNT OF POINTS FOR THIS ROLL
SELECT CASE Ball.x '\
CASE 70: HitPin 1 ' \
CASE 90: HitPin 5 ' ` DEPENDING ON BALL'S LANE
CASE 110: HitPin 8 ' | DETERMINE WHICH PIN WAS
CASE 130: HitPin 10 ' > STRUCK FIRST. PASS THIS
CASE 150: HitPin 9 ' | PIN # TO THE HitPin SUB
CASE 170: HitPin 7 ' ' WHICH WILL SET adjScore%
CASE 190: HitPin 4 ' /
END SELECT '/
Score% = Score% + adjScore% 'ADD ROLL SCORE TO TOTAL SCORE
END SUB
SUB Speed (c%)
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Speed of c% means pause for (OneSecond& / c%) loops.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
DEF SEG = 0
k = PEEK(&H417)
IF (k AND 4) THEN c% = c% - 1
IF (k AND 8) THEN c% = c% + 1
IF c% < 1 THEN c% = 1
t& = OneSecond& / c%
FOR Counter& = 1 TO t& '---START LOOP AT 1---
NEXT Counter& '---END LOOP AT t&----
END SUB
SUB StrikeOrSpare
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'User has bowled a strike or a spare. Show them a framed message.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
CLS 'CLEAR THE SCREEN
COLOR 7 'SET COLOR: GREY
LOCATE 5, 13: PRINT "+------------+" 'TOP OF FRAME
LOCATE 6, 13
IF Roll% = 1 THEN 'CHECK WHICH ROLL IT IS...
PRINT "| STRIKE! |" ' ..FIRST ROLL, SO STRIKE
ELSE
PRINT "| SPARE! |" ' ..SECOND ROLL, SO SPARE
END IF
LOCATE 7, 13: PRINT "+------------+" 'BOTTOM OF FRAME
LOCATE 9, 13: PRINT " PRESS SPACE" 'SHOW EXIT CONDITION
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
'Highlight the frame with moving yellow stars until they hit spacebar.
'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
FlashHi% = 13 'TOP STAR
FlashLo% = 25 'BOTTOM STAR
DO '--------START LOOP--------
FlashHi% = FlashHi% + 1 'MOVE TOP STAR RIGHT
FlashLo% = FlashLo% - 1 'MOVE BOTTOM STAR LEFT
IF FlashHi% = 25 THEN FlashHi% = 14 'RESET TOP STAR
IF FlashLo% = 13 THEN FlashLo% = 24 'RESET BOTTOM STAR
COLOR 14 'SET COLOR: YELLOW
LOCATE 5, FlashHi%: PRINT "-*" 'DRAW TOP STAR
LOCATE 7, FlashLo%: PRINT "*-" 'DROP BOTTOM STAR
Speed HSS.S5 'PAUSE BRIEF MOMENT
COLOR 7 'SET COLOR: GREY
LOCATE 5, FlashHi%: PRINT "--" 'REDRAW TOP FRAME
LOCATE 7, FlashLo%: PRINT "--" 'REDRAW BOTTOM FRAME
LOOP UNTIL INKEY$ = " " '---END LOOP UPON SPACE----
END SUB
Posts: 480
Threads: 24
Joined: Mar 2003
Okay, we get it. If you try really hard you can come up with a programming example where a GOTO statement can save you a few comparisons. This has been covered many times, and the same example is always used (it's already been given once in this thread alone). I personally have never written code that involved more than.. I don't know.. three? four? nested FORs, and in those you can typically combine your NEXT statements and still use an EXIT FOR to kick out of multiple loops (see my example above, in this same thread).
I'm sorry for coming across as bitchy. I get tired of hearing the same arguments over and over. Can't we all agree that GOTO can be used in rare circumstances by careful coders to make code more efficient, but is unnecessary in most programs?
This thread is about a bowling program that had lots of problems. Use of GOTO was just one of them.
*peace*
Meg.
edit: MAC, I like that we're working on the same code. I actually *added* the 2nd file access, just to remove two variables used in the program (high score+high score name). I like the idea of being able to adjust the speed, since my code to test system speed was really only an approximation. There's prolly an easier way to do it (like adjusting the value of OneSecond&, or the divisor passed to the Pause() routine).
This is being nitpicky, but we should prolly try to keep the entirety of the code out of the forum posts. I try to post links to long code, instead of including the entire code in my post.
Posts: 6,419
Threads: 74
Joined: Mar 2002
Exactly. But the sentence "GOTO is evil and should be avoided" is not complete.
The complete sentence should be "GOTO is dangerous and should be avoided if there's a better solution".
I know that I always post the same example, but it's 'cause it's _the_ example. The linux kernel is full of stuff like that, full of GOTOs. It can save you a lot of code if used correctly, and a lot of logic and time as well.
And you mention EXIT FOR... Note that EXIT FOR is just a GOTO with a different look.
To me it's the same
Code: FOR i% = 1 TO 10000
IF blah% THEN GOTO outside
NEXT i%
outside:
Code: FOR i% = 1 TO 10000
IF blah% THEN EXIT FOR
NEXT i%
If GOTO means spaghetti, EXIT FOR is the same. As BASIC doesn't allow to add a conditional expression in the FOR, the non-spaghetti, structured code would be:
Code: i% = 1
DO
...
i% = i% + 1
LOOP WHILE i% <= 10000 AND NOT blah%
Exitting a loop with a GOTO is the same as exitting it with a EXIT FOR. Think about it. So if you call using GOTO "spaghetti code", yours is as well, as you are using EXIT FOR.
The EXIT FOR way may look cleaner, as you don't use a label, but it gets translated to the same assembly code. The collateral effects can be the same. The speed is the same. It just looks different.
|