Lab 3 - Another Trial (Word Guessing Game)

Introduction

This project is an attempt to build a word guessing game in 6502 Assembly. Unlike the previous completed version, this iteration is somewhat unfinished and does not fully adhere to the intended game mechanics. However, the process led to some interesting findings, and I believe the results are still worth sharing.


Overview

This project is a simple word guessing game written in 6502 Assembly, inspired by classic word games like Hangman. The player is given a fixed word to guess and has eight attempts to correctly guess the letters. If the player completes the word before running out of attempts, they win. Otherwise, they lose, and the correct word is revealed.

**Building a Simple Word Guessing Game in 6502 Assembly**


How It Works

- The game starts by displaying a short introduction and setting up the word to guess ("seneca").

- The guessed word is initially displayed as underscores (e.g., `_ e _ e _ a`).

- The player inputs a lowercase letter, which is checked against the word.

- If the letter is in the word, it is revealed in the correct position(s).

- If the letter is incorrect, the number of remaining attempts decreases.

- The game continues until the word is fully guessed or the player runs out of attempts.

- Upon completion, a win or loss message is displayed.












Code

; ROM routine entry points

define SCINIT $ff81  ; Clear screen

define CHRIN  $ffcf  ; Get character input

define CHROUT $ffd2  ; Print character to screen


; Game Variables

define word_to_guess  $0082  ; Word "seneca" storage

define guessed_letters $0088 ; Stores guessed letters (_ e _ e _ a)

define remaining_attempts $0081 ; Number of attempts left

define user_guess $23  ; Stores user's input


define WORD_LENGTH 6  ; Length of word


define PRINT_PTR $00  ; Print function variables

define PRINT_PTR_H $01


; Game Title

jsr PRINT

dcb "W","o","r","d",32,"G","u","e","s","s","i","n","g",32,"G","a","m","e",$0d,00

jsr PRINT

dcb "G","u","e","s","s",32,"t","h","e",32,"s","e","c","r","e","t",32,"w","o","r","d","!",$0d,00

jsr PRINT

dcb "Y","o","u",32,"h","a","v","e",32,"e","i","g","h","t",32,"c","h","a","n","c","e","s",$0d,00


START:

    LDX #0

INIT_WORD:

    LDA word_data, X

    STA word_to_guess, X

    INX

    CPX #WORD_LENGTH

    BNE INIT_WORD


    LDX #0

INIT_GUESS:

    LDA #$5F  ; '_'

    STA guessed_letters, X

    INX

    CPX #WORD_LENGTH

    BNE INIT_GUESS


    LDA #$08  ; Set initial attempts

    STA remaining_attempts


GAME_LOOP:

    jsr PRINT

dcb $0d,"W","o","r","d",32,":",32,00

    LDX #0

SHOW_PROGRESS:

    LDA guessed_letters, X

    JSR CHROUT

    LDA #32

    JSR CHROUT

    INX

    CPX #WORD_LENGTH

    BNE SHOW_PROGRESS


    jsr PRINT

dcb $0d,"G","u","e","s","s",32,"a",32,"l","o","w","e","r","c","a","s","e",32,"l","e","t","t","e","r",32,"(" ,"a","-","z",")",":",32,00


GET_CHAR:

    JSR CHRIN

    JSR CHROUT

    CMP #$61  ; 'a'

    BCC GET_CHAR

    CMP #$7A  ; 'z'

    BCS GET_CHAR

    STA user_guess


    LDX #0

    LDA #0

    STA $00  ; Match flag

CHECK_LETTER:

    LDA word_to_guess, X

    CMP user_guess

    BNE NEXT_LETTER

    STA guessed_letters, X

    LDA #1

    STA $00  ; Match found

NEXT_LETTER:

    INX

    CPX #WORD_LENGTH

    BNE CHECK_LETTER


    LDA $00

    BNE CHECK_COMPLETE

    DEC remaining_attempts

    BEQ END_GAME

    jsr PRINT

dcb $0d,"W","r","o","n","g","!",32,"T","r","y",32,"a","g","a","i","n",".",$0d,00

    JMP GAME_LOOP


CHECK_COMPLETE:

    LDX #0

CHECK_LOOP:

    LDA guessed_letters, X

    CMP #$5F

    BEQ SHORT_JUMP

    INX

    CPX #WORD_LENGTH

    BNE CHECK_LOOP

    JMP CORRECT


SHORT_JUMP:

    JMP GAME_LOOP


CORRECT:

    jsr PRINT

dcb $0d,"C","o","n","g","r","a","t","s","!",32,"Y","o","u",32,"g","u","e","s","s","e","d",32,"t","h","e",32,"w","o","r","d","!",$0d,00

    JMP EXIT_GAME


END_GAME:

    jsr PRINT

dcb $0d,"G","a","m","e",32,"O","v","e","r",".",32,"T","h","e",32,"w","o","r","d",32,"w","a","s",32,00

    LDX #0

PRINT_ANSWER:

    LDA word_to_guess, X

    JSR CHROUT

    INX

    CPX #WORD_LENGTH

    BNE PRINT_ANSWER

    jsr PRINT

dcb $0d,00  


EXIT_GAME:

    RTS


word_data:

dcb $73, $65, $6E, $65, $63, $61  ; "seneca"


PRINT:

    pla

    clc

    adc #$01

    sta PRINT_PTR

    pla

    sta PRINT_PTR_H

    tya

    pha

    ldy #$00

print_next:

    lda (PRINT_PTR),y

    beq print_done

    jsr CHROUT

    iny

    jmp print_next

print_done:

    tya

    clc

    adc PRINT_PTR

    sta PRINT_PTR

    lda PRINT_PTR_H

    adc #$00

    sta PRINT_PTR_H

    pla

    tay

    lda PRINT_PTR_H

    pha

    lda PRINT_PTR

    pha

    rts


Things That Could Be Improved

While the game works as expected, there are some areas that could be improved:


1. Fixed Word Instead of Random Generation

   Currently, the word to guess is hardcoded as "seneca". A better approach would be to implement random word selection from a predefined list.


2. No Hangman-Style Graphics

   A true Hangman game includes a visual representation of a hanging figure that progresses with each incorrect guess. Unfortunately, implementing graphics in 6502 Assembly is quite challenging, so this feature was left out.


3. Unnecessary Blank Output

   The program sometimes outputs unnecessary blank lines, especially when the player does not immediately input a letter. This is likely due to how text output is handled in the game loop. It doesn’t break the game, but it makes the output look messy.


4. Only Handles Lowercase Input 

   Currently, the game only accepts lowercase letters as input. Adding support for uppercase input and properly handling case conversion would improve usability and make the game more user-friendly.


Future Improvements

If I get more time, I’d like to revisit this project and:

- Implement a simple way to randomly select words.

- Improve the text rendering to prevent unwanted blank outputs.

- Attempt a basic Hangman graphic using ASCII characters or simple screen effects.

- Add support for uppercase input to enhance user experience.


Overall, this was a fun and educational project that helped me get more comfortable with 6502 Assembly. 


Comments

Popular posts from this blog

SPO600 2025 Winter Project - Stage 1: Create a Basic GCC Pass (part1)

SPO600 2025 Winter Project - Stage 2: GIMPLE Level Clone Analysis and Pruning (part4)

Lab 1 - 6502 Assembly Language