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

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 <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
User guesses low number
User guesses high number
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).