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

Game End Detection

Board full? Someone wins. Compare scores, declare the victor, restart on keypress.

5% of Ink War

The game has been running forever. Players can claim cells until… when? There’s no ending.

This unit adds proper game end detection. When all 64 cells are claimed, the game determines the winner, displays a victory message, celebrates with a flashing border, then waits for a keypress to restart. A complete game loop.

Run It

pasmonext --sna inkwar.asm inkwar.sna

Unit 6 Screenshot

Play a full game - claim all 64 cells between two players. When the last cell is taken, you’ll see “P1 WINS!”, “P2 WINS!”, or “DRAW!” appear. The border flashes in the winner’s colour. Press any key to play again.

Detecting Game Over

The simplest check: is the board full?

We already have p1_count and p2_count from the score display. If their sum equals 64, every cell is claimed. The game is over.

This approach reuses existing data. No need for a separate move counter - we derive the answer from state we already track.

Determining the Winner

Three possible outcomes: P1 wins, P2 wins, or draw:

The Z80’s CP instruction compares by subtraction. After cp b:

  • Carry set means A < B (p2_count < p1_count → P1 wins)
  • Zero set means A = B (draw)
  • Neither means A > B (P2 wins)

Each outcome displays a different message in the appropriate colour.

Printing Messages

We need to print null-terminated strings. The print_message routine:

print_message:
            ; HL = string, B = row, C = column, E = attribute
.pm_loop:
            ld      a, (hl)         ; Get character
            or      a               ; Check for null terminator
            jr      z, .pm_done
            call    print_char
            inc     hl
            inc     c               ; Next column
            jr      .pm_loop
.pm_done:
            ; Set attributes for the message area
            ; ...

The strings are stored in memory:

msg_p1_wins:    defb    "P1 WINS!", 0
msg_p2_wins:    defb    "P2 WINS!", 0
msg_draw:       defb    "DRAW!", 0

The trailing 0 marks the end of each string.

Victory Celebration

Winners deserve fanfare:

The border flashes in the winner’s colour - red for P1, blue for P2, white for a draw. Five quick flashes with black gaps between them. Simple but effective.

Waiting for Input

After showing results, wait for any key:

Two phases:

  1. Wait for release - If a key is already held from claiming the last cell, wait until it’s released
  2. Wait for press - Then wait for a new keypress

The CPL instruction inverts A. Keyboard bits are active-low (0 = pressed), so we invert to make pressed keys show as 1s. The HALT saves power while waiting.

Restarting the Game

After wait_for_key, we jump back to start:

            jp      start           ; Restart game

This reinitialises everything: clears the board, resets scores, redraws the screen. A fresh game ready to play.

The Game Loop is Complete

The flow is now:

  1. Start → Initialise and draw
  2. Play → Input, validate, claim, update, check end
  3. End → Show results, celebrate, wait for key
  4. Restart → Jump to Start

Every game has this structure. What you’ve built is the skeleton that every game builds upon.

The Complete Code

Try This: Different Victory Messages

msg_p1_wins:    defb    "RED WINS!", 0
msg_p2_wins:    defb    "BLUE WINS!", 0
msg_draw:       defb    "TIE GAME!", 0

Try This: Longer Celebration

.vc_flash:
            ld      b, 10           ; 10 flashes instead of 5

What You’ve Learnt

  • End condition detection - Check when game state reaches a terminal condition
  • Score comparison - Use CP and flags to determine greater/less/equal
  • Null-terminated strings - Standard way to store variable-length text
  • Key debouncing - Wait for release before waiting for press
  • Game loop structure - Start → Play → End → Restart

What’s Next

In Unit 7, we’ll add a title screen. The game will start with “INK WAR” and “PRESS ANY KEY”, making it feel like a proper product rather than a demo.

What Changed

Unit 5 → Unit 6