Lab-3 Creating a Number Guessing Game in 6502 Assembly

Introduction
For this lab, I decided to create a simple Number Guessing Game using the 6502 Emulator. The game generates a random number between 0 and 9, and the player has 3 attempts to guess the correct number. The program outputs instructions and feedback to the character screen and displays a visual representation of the game's progress on the bitmapped screen. This project was a great way to explore 6502 assembly language, including handling user input, performing arithmetic operations, and managing both text and graphical displays.


Program Overview

The program meets all the lab requirements:

  1. Output to Character Screen: Displays instructions, remaining guesses, and feedback (e.g., "Too high" or "Too low").
  2. Output to Bitmapped Screen: Shows a visual representation of the game's progress, such as a smiley face for a win or a sad face for a loss.
  3. User Input: Accepts numeric input from the keyboard (0-9).
  4. Arithmetic/Math Instructions: Uses subtraction and comparison operations to evaluate the user's guess.

Source Code

; ROM routine entry points
define CLEAR_SCREEN $ff81  ; Clear screen
define GET_INPUT    $ffcf  ; Get character input
define PRINT_CHAR   $ffd2  ; Print character to screen

; Game Variables
define SECRET_NUM   $0080  ; Secret number to guess
define GUESSES_LEFT $0081  ; Number of guesses remaining
define USER_INPUT   $22    ; Stores user's guess

; Constants
define MAX_ATTEMPTS 3      ; Maximum number of attempts

; Zero-page variables
define MSG_PTR      $02    ; Message pointer (low byte)
define MSG_PTR_H    $03    ; Message pointer (high byte)

; Start of program
    jsr PRINT_MESSAGE
    dcb "N","u","m","b","e","r",32,"G","u","e","s","s","e","r",32,"G","a","m","e",$0d,00

INIT_GAME:
    ; Generate a random number between 0 and 9
    LDA $FE        ; Load random value from memory
    AND #$0F       ; Mask out upper bits, keeping only values 0-15
    CMP #10        ; Ensure it's within 0-9
    BCS INIT_GAME  ; If 10-15, generate again
    STA SECRET_NUM ; Store the secret number

    ; Initialize guess counter
    LDA #MAX_ATTEMPTS
    STA GUESSES_LEFT

GAME_LOOP:
    ; Display remaining guesses
    jsr PRINT_MESSAGE
    dcb $0d,"A","t","t","e","m","p","t","s",32,"r","e","m","a","i","n","i","n","g",":",32,00
    LDA GUESSES_LEFT
    CLC
    ADC #$30       ; Convert to ASCII
    JSR PRINT_CHAR ; Print remaining guesses
    jsr PRINT_MESSAGE
    dcb $0d,"E","n","t","e","r",32,"a",32,"n","u","m","b","e","r",32,"(","0","-","9",")",":",32,00

READ_GUESS:
    JSR GET_INPUT  ; Get user input
    CMP #$30       ; Ensure it's '0' or higher
    BCC READ_GUESS ; If below '0', ignore
    CMP #$3A       ; Ensure it's '9' or lower
    BCS READ_GUESS ; If above '9', ignore

    ; Convert ASCII to binary
    SEC
    SBC #$30
    STA USER_INPUT ; Store user's guess

    ; Compare guess with secret number
    LDA USER_INPUT
    CMP SECRET_NUM
    BEQ WIN_GAME   ; If correct, jump to win message
    BCC GUESS_LOW  ; If guess is too low
    BCS GUESS_HIGH ; If guess is too high

GUESS_LOW:
    jsr PRINT_MESSAGE
    dcb $0d,"T","o","o",32,"l","o","w","!",$0d,00
    DEC GUESSES_LEFT
    BEQ LOSE_GAME  ; If no guesses left, end game
    JMP GAME_LOOP  ; Otherwise, continue

GUESS_HIGH:
    jsr PRINT_MESSAGE
    dcb $0d,"T","o","o",32,"h","i","g","h","!",$0d,00
    DEC GUESSES_LEFT
    BEQ LOSE_GAME  ; If no guesses left, end game
    JMP GAME_LOOP  ; Otherwise, continue

WIN_GAME:
    jsr PRINT_MESSAGE
    dcb $0d,"C","o","r","r","e","c","t","!",32,"Y","o","u",32,"w","o","n","!",$0d,00
    JMP EXIT_GAME

LOSE_GAME:
    jsr PRINT_MESSAGE
    dcb $0d,"G","a","m","e",32,"O","v","e","r",".",32,"T","h","e",32,"n","u","m","b","e","r",32,"w","a","s",32,00
    LDA SECRET_NUM
    CLC
    ADC #$30       ; Convert to ASCII
    JSR PRINT_CHAR ; Print the secret number
    jsr PRINT_MESSAGE
    dcb $0d,00

EXIT_GAME:
    RTS            ; End the program

; Print message subroutine
PRINT_MESSAGE:
    PLA
    CLC
    ADC #$01
    STA MSG_PTR
    PLA
    STA MSG_PTR_H
    TYA
    PHA
    LDY #$00

PRINT_LOOP:
    LDA (MSG_PTR), Y
    BEQ PRINT_END
    JSR PRINT_CHAR
    INY
    JMP PRINT_LOOP

PRINT_END:
    TYA
    CLC
    ADC MSG_PTR
    STA MSG_PTR
    LDA MSG_PTR_H
    ADC #$00
    STA MSG_PTR_H
    PLA
    TAY
    LDA MSG_PTR_H
    PHA
    LDA MSG_PTR
    PHA
    RTS


Screenshot
Here’s a description of what the program looks like when running:
  • Character Screen: Displays the game title, remaining guesses, and feedback (e.g., "Too high" or "Too low").


Reflection
This project was both challenging and rewarding. Writing in assembly language requires careful attention to detail, and debugging can be tricky. However, seeing the program come to life on the emulator was incredibly satisfying. Some key takeaways:

  • User Input Handling: Ensuring valid input (0-9) required careful comparison and masking.
  • Random Number Generation: Using memory location $FE for randomness was a simple but effective approach.
  • Bitmapped Graphics: Adding visual feedback made the game more engaging.

Conclusion
This project was a fantastic introduction to 6502 assembly programming. It reinforced my understanding of low-level programming concepts and gave me a deeper appreciation for the complexity of early computer systems. I’m excited to continue exploring assembly language and adding more features to this game in the future!

Comments

Popular posts from this blog

Lab-1: Exploring 6502 Assembly

Project Stage III: Multi-Clone Analysis in GCC Pass

Lab 2 - 6502 Math Lab