Skip to content
Game 5 Unit 4 of 128 1 hr learning time

Score and Turn Display

Count cells, display scores, show whose turn it is. The game gets a proper UI.

3% of Ink War

Players need to know the score. They need to know whose turn it is.

This unit adds a proper user interface: score display showing how many cells each player owns, and a turn indicator that changes colour with each move. The game starts to feel complete.

Run It

pasmonext --sna inkwar.asm inkwar.sna

Unit 4 Screenshot

Above the board you’ll see:

  • P1:00 with a score (red background)
  • P2:00 with a score (blue background)
  • TURN indicator in the current player’s colour

Claim some cells. Watch the scores update. Watch the turn indicator change colour.

Counting Cells

To display scores, we first need to count them:

This iterates through all 64 cells of board_state, counting how many belong to each player. The djnz instruction (Decrement and Jump if Not Zero) is perfect for loops - it decrements B and jumps back if B isn’t zero yet.

We store the counts in p1_count and p2_count for display.

Printing Characters

Rather than wrestling with the ROM’s print routines (which need careful system variable setup), we write our own character printing routine. This gives us complete control and teaches more about how the Spectrum works.

The routine:

  1. Looks up the character’s pixel data in the ROM character set at $3C00
  2. Calculates where on screen to draw it using the Spectrum’s quirky display layout
  3. Copies 8 bytes (one per pixel row) to the display file

The Spectrum’s Screen Layout

The Spectrum’s display file at $4000 has a complex layout. For each character position at row R, column C:

; High byte = $40 + (row/8)*8 + pixel_line
; Low byte = (row%8)*32 + column

The screen is divided into thirds (rows 0-7, 8-15, 16-23), with each pixel row 256 bytes apart. Our print_char routine handles this complexity.

Converting Numbers to Text

Scores are numbers (0-64), but we print characters. To convert:

The conversion is simple: subtract 10 repeatedly to get the tens digit, then add ASCII ‘0’ (48 decimal) to convert digits to printable characters.

For example, the number 23:

  • Subtract 10 twice: 23 → 13 → 3 (tens = 2, remainder = 3)
  • Tens digit: 2 + ‘0’ = ‘2’ (ASCII 50)
  • Units digit: 3 + ‘0’ = ‘3’ (ASCII 51)

The Turn Indicator

A simple “TURN” label that changes colour based on whose turn it is:

We print the text first, then set the attributes afterwards. The text stays the same - only the background colour changes.

Setting Attribute Ranges

We colour the text by setting attributes for multiple consecutive cells:

set_attr_range:
            ; A = row, C = start column, B = count, E = attribute
            ; Calculate address, then write E to B consecutive bytes

This lets us create coloured “badges” for the score labels - red background for P1, blue for P2.

UI Layout Constants

The display positions are defined as constants at the top:

SCORE_ROW   equ     2               ; Score display row
P1_SCORE_COL equ    10              ; "P1: nn" column
P2_SCORE_COL equ    18              ; "P2: nn" column
TURN_ROW    equ     4               ; Turn indicator row
TURN_COL    equ     14              ; Turn indicator column

Changing these moves the entire UI. Want scores at the bottom? Change SCORE_ROW to 20.

Updating After Claims

When a cell is claimed, we update the display:

try_claim:
            ; ... claim the cell ...

            call    draw_ui         ; Update scores and turn indicator
            call    update_border
            call    draw_cursor

The draw_ui routine calls count_cells to recalculate, then redraws the score display and turn indicator. Every claim triggers an update.

The Complete Code

Try This: Move the UI

Change the position constants:

; Scores at the bottom
SCORE_ROW   equ     21

; Turn indicator on the left
TURN_ROW    equ     12
TURN_COL    equ     2

Try This: Different Colour Scheme

; Green for P1, Magenta for P2
P1_TEXT     equ     %01100111       ; Green paper, white ink
P2_TEXT     equ     %01011111       ; Magenta paper, white ink

What You’ve Learnt

  • Custom print routine - Direct screen memory access gives full control
  • ROM character set - Character data at $3C00, each character is 8 bytes
  • Display file layout - Screen memory has complex interleaved addressing
  • Number to ASCII - Add ‘0’ (48) to convert a digit to its character code
  • Cell counting - Iterate with DJNZ, compare and branch to count categories
  • Attribute ranges - Set consecutive attributes to create coloured text backgrounds

What’s Next

In Unit 5, we’ll add proper move validation with feedback - error sounds and visual cues when you try to claim an already-occupied cell.

What Changed

Unit 3 → Unit 4