Lucky Digits: An Infinite Guessing Game with Color

Published on: Februrary 17, 2025

Introduction

Initially, I planned to build a Snake game, but after facing challenges with movement, I switched to a simpler guessing game called Lucky Digits. This project was exciting and challenging as I explored low-level programming, ROM routines, and memory manipulation.

How the Game Works

Code Walkthrough

Initialization

START:
    LDA $FE        ; Load random value from memory
    AND #$07       ; Mask out upper bits, keeping values 1-5
    CLC
    ADC #$01       ; Ensure within range 1-5
    STA random_number
      

User Input Handler

GET_NUMBER:
    LDA #$00        ; Clear value
    STA value
    JSR CHRIN       ; Get input character
    CMP #$30        ; Ensure valid digit ('0')
    BCC GET_NUMBER
    CMP #$36        ; Ensure valid digit ('5')
    BCS GET_NUMBER
    SEC
    SBC #$30        ; Convert ASCII to binary
    STA value
    JSR CHROUT
      

Screen Color Change

CORRECT:
    LDA #$05      ; Green color
    JSR SET_COLOR
    JMP END_GAME  
INCORRECT:
    LDA #$02      ; Red color
    JSR SET_COLOR
    JMP GUESSNUMBERS  
      

Color Fill Routine

SET_COLOR:
    LDY #$00
    STY SCRN_PTR
    LDX #$02
    STX SCRN_PTR_H
    LDX #$04   ; Pages to fill
fill_screen:
    STA (SCRN_PTR),Y
    INY
    BNE fill_screen
    INC SCRN_PTR_H
    DEX
    BNE fill_screen
    RTS
      

Challenges and Learning

Working with assembly requires a deep understanding of memory operations. Debugging was particularly difficult as there were no built-in debugging tools. Managing screen color changes required careful memory handling. I experimented with ROM routines before implementing this lab.

References and Inspirations

Conclusion

Building Lucky Digits was a fascinating experience in low-level programming. I plan to improve this game with animations and remain enthusiastic about eventually implementing a Snake game.

Full Assembly Code

; Lucky Digits - Infinite Guessing Game with Color Change
; If correct, screen turns GREEN
; If incorrect, screen turns RED

; ROM routine entry points
define      SCINIT      $ff81 ; initialize/clear screen
define      CHRIN       $ffcf ; input character from keyboard
define      CHROUT      $ffd2 ; output character to screen
define      SCREEN      $ffed ; get screen size
define      PLOT        $fff0 ; get/set cursor coordinates

; Constants
define      random_number $0082; Define random variable
define      value        $23    ; Temporary storage for user input
define      color        $24    ; Color variable

; Zero-page variables
define        PRINT_PTR    $00
define        PRINT_PTR_H    $01
define        SCRN_PTR    $03
define        SCRN_PTR_H  $04

; Start of program
    jsr PRINT           ; Print title
    dcb "L","u","c","k","y",32,"D","i","g","i","t","s",00

START:
    LDA $FE        ; Load random value from memory
    AND #$07       ; Mask out upper bits, keeping only values 1-5
    CLC
    ADC #$01       ; Ensure it's within 1-5
    STA random_number  ; Store valid random number

    LDA #$02
    STA color  

; Main game loop
GUESSNUMBERS:
    jsr PRINT
    dcb $0d,"C","a","n",32,"y","o","u",32,"c","r","a","c","k",32,"t","h","e",32,"c","o","d","e","?",$0d
    dcb "P","i","c","k",32,"a",32,"l","u","c","k","y",32,"n","u","m","b","e","r","!",$0d
    dcb "E","n","t","e","r",32,"a",32,"n","u","m","b","e","r",32,"b","e","t","w","e","e","n",32,"0","-","5",":",32,32,00

GET_NUMBER:
    LDA #$00        ; Clear value
    STA value
    JSR CHRIN       ; Get input character
    CMP #$30        ; Ensure valid digit ('0')
    BCC GET_NUMBER
    CMP #$36        ; Ensure valid digit ('5')
    BCS GET_NUMBER

    SEC
    SBC #$30        ; Convert ASCII to binary
    STA value       ; Store input
    jsr CHROUT

    lda random_number
    cmp value
    beq CORRECT   ; Correct guess
    jmp INCORRECT

; Correct guess - Turn screen GREEN
CORRECT:
    jsr PRINT
    dcb $0d,"B","r","a","v","o","!",32,"Y","o","u",32,"f","o","u","n","d",32,"t","h","e",32,"l","u","c","k","y",32,"d","i","g","i","t","!",00
    lda #$05      ; Green color
    jsr SET_COLOR 
    jmp END_GAME  

; Incorrect guess - Turn screen RED, game continues
INCORRECT:
    jsr PRINT
    dcb $0d,"N","o","t",32,"q","u","i","t","e","!",32,"T","r","y",32,"a","g","a","i","n",46,46,46,00
    lda #$02      ; Red color
    jsr SET_COLOR
    jmp GUESSNUMBERS  ; Loop back to guessing

END_GAME:
    jsr PRINT
    dcb $0d,"W","e","l","l",32,"p","l","a","y","e","d","!",32,"T","h","a","n","k","s",32,"f","o","r",32,"p","l","a","y","i","n","g",32,"L","u","c","k","y",32,"D","i","g","i","t","s","!",00
    RTS

; Color Fill Routine
SET_COLOR:
    ldy #$00
    sty SCRN_PTR
    ldx #$02
    stx SCRN_PTR_H
    ldx #$04   ; Pages to fill
fill_screen:
    sta (SCRN_PTR),y
    iny
    bne fill_screen
    inc SCRN_PTR_H
    dex
    bne fill_screen
    rts

; Print Routine
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