Now I put the library of Assembly routines to work. I created a small game which is an implementation of “Guess My Number”. Hey, you gotta start somewhere. In the previous post I detailed the library, so I’ll jump right into the game.
The game is simple.
- A random number is generated between 1 and 100.
- The current guess number is displayed, and the user is asked to make a guess.
- If the guess is too high, a “too high” message is printed, the guess number is incremented, and step 2 is repeated.
- If the guess is too low, a “too low” message is printed, the guess number is incremented, and step 2 is repeated.
- If the guess is the random number, a “got it” message is printed followed by a “thanks” message and the game exits.
Instructions
New instructions introduced here.
- CLD – CLear Decimal flag. Instructs the 6502 that plain binary numbers should be used rather than binary coded decimal (BCD).
- AND – logical AND. Performs AND on the accumulator contents with the contents of the specified value or location with the result stored in the accumulator.
- BCC – Branch if Carry Clear. Branches to specified location if the Carry flag is clear. Can only be +127 or -128 bytes of branch address.
Assembly Source
This is the Mac/65 Assembly source code. The source may work with other macro capable assemblers with or without slight modifications.
01 ; ------------------------------ 02 ; App.: GUESSNUM.M65 03 ; Desc: Guess My Number 04 ; ------------------------------ 10 .TITLE "Guess Number, Version 1.0" 15 .OPT OBJ,NO EJECT 20 *= $3600 25 .INCLUDE #D2:A8DEFS.LIB 30 .INCLUDE #D2:A8STRMAC.LIB 0300 ; ------------------------------ 0301 ; Setup Game 0302 ; ------------------------------ 0304 GAMEST 0306 CLD 0310 ; Set Margin 0312 LDA #0 0314 STA LMARG 0320 ; Position 0,0 0322 LDX #0 0324 LDY #0 0326 JSR CURXY 0330 ; Print Title 0332 LDA #STITLE/256 0334 LDY #STITLE&255 0336 JSR PRTLN 0340 ; Position 0,2 0342 LDX #0 0344 LDY #2 0346 JSR CURXY 0350 ; Print statement 0352 LDA #SMYNUM/256 0354 LDY #SMYNUM&255 0356 JSR PRTLN 0359 ; Print What question 0360 LDA #SQWHAT/256 0362 LDY #SQWHAT&255 0364 JSR PRTLN 0370 ; Init Vars 0372 LDX #1 0374 STX VGCNT 0376 LDX #0 0378 STX VGCNT+1 0400 ; Get Random Number 0402 LDA RANDM 0404 AND #100 ; Ensure < 100 0406 STA VMYNUM ; Store it 0408 LDA #0 0410 STA VMYNUM+1 0500 ; ------------------------------ 0501 ; Guess Loop 0502 ; ------------------------------ 0510 GSLOOP 0519 ; Print Guess # 0520 LDA #SGUESS/256 0522 LDX #SGUESS&255 0524 JSR PRTCH 0529 ; Convert Int to String 0530 INT2STR VGCNT,SVGCNT 0534 ; Print it and ? 0535 LDA #SVGCNT/256 0540 LDX #SVGCNT&255 0550 JSR PRTCH 0600 LDA #SQMARK/256 0602 LDX #SQMARK&255 0604 JSR PRTCH 0700 ; Get Users Guess 0710 LDA #VUSNUM/256 0712 LDX #VUSNUM&255 0714 LDY #EOL 0716 JSR INPSTR 0720 ; Convert Str to Int 0725 STR2INT VUSNUM,IUSNUM 0730 LDA IUSNUM 0800 ; Compare guess to num 0802 ; Equal ? 0810 CMP VMYNUM 0812 BCC RTOLOW ; HB < 0814 BNE RTOHI ; HB > 0820 LDA IUSNUM+1 0822 CMP VMYNUM+1 0824 BCC RTOLOW ; LB < 0826 BNE RTOHI ; LB > 0828 BEQ RGOTIT ; LB = 0830 GSFINI ; Guess finish 0840 ; Inc guess # 0845 INC VGCNT 0850 ; Guess max reached? 0860 ; Loop for next guess 0865 JMP GSLOOP 1000 ; ------------------------------ 1001 ; Guess too low 1002 ; ------------------------------ 1010 RTOLOW 1020 LDA #STOLOW/256 1022 LDY #STOLOW&255 1024 JSR PRTLN 1030 JMP GSFINI 1100 ; ------------------------------ 1101 ; Guess too high 1102 ; ------------------------------ 1110 RTOHI 1120 LDA #STOHI/256 1122 LDY #STOHI&255 1124 JSR PRTLN 1130 JMP GSFINI 1200 ; ------------------------------ 1201 ; Guessed it! 1202 ; ------------------------------ 1210 RGOTIT 1220 LDA #SGOTIT/256 1222 LDY #SGOTIT&255 1224 JSR PRTLN 1900 ; ------------------------------ 1901 ; End of program 1902 ; ------------------------------ 1910 GMOVER 1915 LDA #STHX/256 1920 LDY #STHX&255 1925 JSR PRTLN 1995 RTS 30000 ; ----- String Data ----- 30002 STITLE .BYTE CLS,"-[Number Guess]------------------------",EOL 30005 SMYNUM .BYTE "My number is between 1 and 100.",EOL 30010 SQWHAT .BYTE "What is it?",EOL 30015 SGUESS .BYTE "Guess #",EOS 30020 SQMARK .BYTE "? ",EOS 30025 STOHI .BYTE "Sorry, too high!",EOL 30030 STOLOW .BYTE "Sorry, too low!",EOL 30035 SGOTIT .BYTE "You guessed it!",EOL 30040 STHX .BYTE "Thanks for playing.",EOL 30050 SSORRY .BYTE "Sorry, my number was ",EOS 31000 ; ----- Game Vars ----- 31005 VGCNT .BYTE 0,0 31006 SVGCNT .BYTE "00000",EOL 31010 VMYNUM .BYTE 0,0 31020 VUSNUM .BYTE " ",EOL 31025 IUSNUM .BYTE 0,0 50000 ; ----- Function Includes ----- 50010 .INCLUDE #D2:A8FUNCS.LIB 50020 .INCLUDE #D2:A8STRFNC.LIB 64000 ; ---------- E N D ---------- 64001 .END
Breakdown
This is what each line is doing:
- 10 to 15: Assembler directives use to control object output and printing.
- 20: Load address, where the program will reside in memory
- 25 to 30: Include the source for the A8 library definitions file, and the A8 library string macros.
- 304: Label for game start (GAMEST)
- 306: Clear the decimal flag since we need plain binary numbers, not binary coded decimal.
- 310 to 314: Set the left margin to column 0.
- 320 to 326: Position cursor at 0,0 (top left)
- 330 to 336: Print the title string
- 340 to 346: Position cursor at 0,2 (column 0, row 2)
- 350 to 356: Print the statement about the number range.
- 359 to 364: Print the question “What is it?”
- 372 to 378: Set the guess count to 1
- 402: Get a random number and store it in the accumulator
- 404: Ensure number in accumulator is less than 100
- 406 to 410: Store the number into VMYNUM.
- 510: Label for start of the guess loop (GSLOOP)
- 520 to 524: Print the guess number prompt “Guess #”
- 530: Convert the integer guess counter (VGCNT) to a string (SVGCNT)
- 535 to 550: Print the string version (SVGCNT) of the guess counter
- 600 t 604: Print the “?” portion of the prompt
- 710 to 716: Get the users input as an EOL terminated string into location VUSNUM
- 725: Convert the user string VUSNUM to an integer in location IUSNUM
- 730: Load the low byte of the integer version of users guess into the accumulator
- 810: Compare the value in the accumulator (users guess) with secret number (VMYNUM) low byte
- 812: Branch to RTOLOW if the accumulator is less than VMYNUM
- 814: Branch to RTOHI if the accumulator is more than VMYNUM
- 820: Load the high byte of the integer version of users guess into the accumulator
- 822: Compare the value in the accumulator with the secret number (VMYNUM) high byte
- 824: Branch to RTOLOW if the accumulator is less then VMYNUM
- 826: Branch to RTOHI if the accumulator is more than VMYNUM
- 828: Branch to RGOTIT if the accumulator is equal to VMYNUM (both high and low bytes matched)
- 830: Label for guess loop finish (GSFINI)
- 845: Increment the guess count
- 865: Jump to the start of the guess loop (GSLOOP)
- 1010: Label to start of RTOLOW subroutine
- 1020 to 1024: Print the too low message
- 1030: Jump to guess finish label (GSFINI)
- 1110: Label to start of RTOHI subroutine
- 1120 to 1124: Print the too high message
- 1130: Jump to guess finish label (GSFINI)
- 1210: Label to start of RGOTIT subroutine
- 1220 to 1224: Print the you guessed it message
- 1910: Label to game over (GMOVER)
- 1915 to 1925: Print the thanks for playing message
- 1995: Return from game (exit)
- 30002 to 30050: String definitions for screen messages
- 31005: Reserve 2 bytes for VGCNT and initialize to 0
- 31006: Reserve 6 bytes for SVGCNT and initialize to “00000{EOL}”
- 31010: Reserve 2 bytes for VMYNUM and initialize to 0
- 31020: Reserve 2 bytes for VUSNUM and initialize to ” {EOL}”
- 31025: Reserve 2 bytes for IUSNUM and initialize to 0
- 50010 to 50020: Include the source the A8 library functions and A8 library string functions
- 64001: Assembler directive to mark end of source
Results
Here is a screenshot of the program being executed from DOS: