SPO600 - Lab 3: Building a Number Guessing Game in 6502 Assembly

Table of Contents Introduction Game Overview Code Breakdown Initialization and Random Number Generation Text Output: Game Prompts Keyboard Input Handling Graphics Feedback Screenshots Attempt Tracking and Display Restart Mechanism Reflection Challenges Limitations Full Code Introduction This blog post is about my journey through Lab 3 of the SPO600 course, where I developed a Number Guessing Game using 6502 Assembly. The goal was to create a program that meets specific criteria: Outputting to both text and graphics screens Accepting keyboard input Using arithmetic operations Let's dive into how I tackled this challenge! Game Overview The game is simple but engaging: The program generates a random number between 1 and 99. The player guesses the number via keyboard input. After each guess, the game outputs ("Too High" or "Too Low") and changes the colour of the graphics screen (red for high, blue for low, green for a win). The player's number of attempts is tracked and displayed as A. Code Breakdown Initialization and Random Number Generation The game starts by initializing the text screen (SCINIT) and testing the graphics screen with a flash effect (TEST_GRAPHICS). A random number is generated using the pseudo-random byte at memory location $FE: LDA $FE ; Load random byte AND #$7F ; Ensure positivity (bitwise AND) CMP #100 ; Check if >=100 BCC SAVE_TARGET ; If

Apr 18, 2025 - 04:17
 0
SPO600 - Lab 3: Building a Number Guessing Game in 6502 Assembly

Table of Contents

  • Introduction
  • Game Overview
  • Code Breakdown
    • Initialization and Random Number Generation
    • Text Output: Game Prompts
    • Keyboard Input Handling
    • Graphics Feedback
    • Screenshots
    • Attempt Tracking and Display
    • Restart Mechanism
  • Reflection
    • Challenges
    • Limitations
  • Full Code

Introduction

This blog post is about my journey through Lab 3 of the SPO600 course, where I developed a Number Guessing Game using 6502 Assembly. The goal was to create a program that meets specific criteria:

  • Outputting to both text and graphics screens
  • Accepting keyboard input
  • Using arithmetic operations

Let's dive into how I tackled this challenge!

Game Overview

The game is simple but engaging:

  1. The program generates a random number between 1 and 99.
  2. The player guesses the number via keyboard input.
  3. After each guess, the game outputs ("Too High" or "Too Low") and changes the colour of the graphics screen (red for high, blue for low, green for a win).
  4. The player's number of attempts is tracked and displayed as A.

Code Breakdown

Initialization and Random Number Generation

The game starts by initializing the text screen (SCINIT) and testing the graphics screen with a flash effect (TEST_GRAPHICS). A random number is generated using the pseudo-random byte at memory location $FE:

LDA $FE      ; Load random byte
AND #$7F     ; Ensure positivity (bitwise AND)
CMP #100     ; Check if >=100
BCC SAVE_TARGET ; If <100, use it
LSR          ; Divide by 2 if out of range
SAVE_TARGET:
STA TARGET   ; Store as target number

This ensures the number stays within 1–99 using bitwise operations and comparisons.

Text Output: Game Prompts

The text screen displays instructions and feedback using the CHROUT ROM routine. For example, printing "GUESS" and handling newlines:

LDA #$47     ; 'G'
JSR CHROUT
LDA #$55     ; 'U'
JSR CHROUT
; ... repeats for remaining letters

Feedback like "HI" (too high) or "LO" (too low) is printed after each guess.

Keyboard Input Handling

The INPUT_GUESS subroutine reads digits from the keyboard using CHRIN and converts ASCII characters to numeric values. Two-digit inputs are handled by shifting the first digit into the tens place and adding the second:

; Convert first digit to tens place
LDA GUESS
ASL          ; ×2
STA TEMP2
ASL          ; ×4
ASL          ; ×8
CLC
ADC TEMP2    ; ×10 (8+2)
STA GUESS

; Add second digit
PLA
SEC
SBC #$30     ; ASCII to numeric
ADC GUESS
STA GUESS

This uses shifts (ASL) and arithmetic (ADC) to efficiently calculate the final guess.

Graphics Feedback

The graphics screen (memory starting at $0200) is filled with a color based on the guess using FILL_SCREEN:

FILL_SCREEN:
  LDX #0
  LDY #0
FILL_LOOP:
  STA $0200,X ; Fill pages $0200–$05FF
  STA $0300,X
  ; ... continues for all pages
  INX
  BNE FILL_LOOP
  RTS

Colors are set using values like $05 (green) or $02 (red), updating the entire screen instantly.

Screenshots

Image description

User guesses low number

Image description

User guesses high number

Image description

User guesses correct number (WINS) and asked if he wants to play another game

Attempt Tracking and Display

The ATTEMPTS(A) counter is incremented after each guess. For values ≥10, the number is split into tens and ones digits using a division loop:

DIVIDE_LOOP:
  CMP #10
  BCC DIGIT_READY ; Exit if <10
  SBC #10         ; Subtract 10
  INX             ; Count tens
  JMP DIVIDE_LOOP

This avoids complex division by repeatedly subtracting 10, demonstrating efficient arithmetic in assembly.

Restart Mechanism

After winning, the player can press 'Y' to restart. This resets the screen and jumps back to the start:

RESTART:
  JSR SCINIT      ; Reinitialize screen
  JMP $0600       ; Restart program

Reflection

Writing this game in 6502 Assembly was both frustrating and rewarding. Here are the major challenges I faced and the limitations the program has:

Challenges

Random Number Range: Ensuring the random number stayed within 1–99 required masking (AND #$7F) and conditional checks.

Two-Digit Input: Converting ASCII input to a numeric value involved bit shifts and arithmetic, avoiding slow multiplication.

Limitations

  • The random number generator isn't perfectly uniform due to reliance on $FE.
  • Input requires pressing Enter after each digit, which might feel unintuitive.

Full Code

Available here (paste into the 6502 Emulator to run).