The First Piece
Situation
Tianjing had been coding for only about seven weeks when we began moving her Chinese chess project from the world of drawing into the world of software design.
She already knew how to make a board appear on the screen. UIKit could draw the lines. Pieces could be rendered. The visual side of the project was becoming familiar.
But a playable Chinese chess game needs something underneath the picture.
Where are the pieces?
What is their position?
What is the state of the game?
And what happens when a piece moves?
Those questions led us into CChessGame.
The class already had the beginnings of a model:
struct CChessGame: CustomStringConvertible {
var pieces: [Piece] = []
init() {
deploy()
}
}
Thirty-two pieces could be deployed into the game. But the board printed by the test was still mostly an arrangement of dots.
We had been building the board string inside the test itself. Then came the next step: move that responsibility into the model.
βThis is the real thing now.β
Turning Point
The first challenge sounded almost ridiculously small:
Can you get the first piece out of the box?
Tianjing wrote:
pieces[0]
Then:
Put it in a name.
She wrote:
let p = pieces[0]
And the program crashed.
The board was empty.
We had forgotten to deploy the pieces.
That led to another tiny but important correction:
init() {
deploy()
}
Now the first piece really existed.
The first piece was a rook, represented by the letter c.
But then another problem appeared.
How do we put that one c onto the board?
Tianjing tried putting it into a for loop. Then into another loop.
The loops produced many cs.
We already knew that wasn't what we wanted.
The lesson was hiding in plain sight: a loop is powerful precisely because it repeats something. If we need one thing, a loop may be the wrong abstraction.
Eventually, we took the first row out of the loop and composed it directly:
0 c . . . . . . . .
And suddenly something important had happened.
The c was no longer merely a character in a test.
It was a piece from CChessGame, appearing at a particular logical position on the board.
Emergence
Earlier, Tianjing had encountered another deceptively simple problem while reconstructing the board string.
She began counting the corners of the squares in the first row:
1, 2, 3, ... 8, 9
Something felt wrong.
She had to discover for herself that Chinese chess does not have eight playable squares across the board. It has nine logical positions across, because the pieces stand on intersections of lines rather than inside squares.
That distinction was more important than the numbers.
A logical board position is not the same thing as its visual geometry.
On the screen, we might draw a piece inside a square.
In another implementation, we might draw it on a crossing of lines.
The picture can change completely while the game model remains the same.
That is the abstraction we were looking for.
The c in
0 c . . . . . . . .
is therefore not really about drawing.
It represents a piece occupying one position in the game.
And that position can eventually change.
Today it is here.
Tomorrow:
0 . . . c . . . . .
The visual board will show the change.
But the deeper operation is happening in the model:
game state β move β new game state
That is the beginning of a real game engine.
Learning
Tianjing learned several things in one evening without being handed a recipe for any of them.
She reconstructed a string-building exercise from memory after its code had been completely erased.
She discovered that a seemingly convenient simplification can destroy useful structure.
She confronted the difference between chessboard squares and Xiangqi positions.
She learned that CChessGame should own its state rather than having the test pretend to be the game.
She independently searched the internet when she forgot how CustomStringConvertible works.
She discovered that print(game) and game.description are not necessarily the same debugging experience she expected.
She learned that an empty array can make pieces[0] crash.
And finally, she put the first actual game piece into the model's board representation.
None of these achievements looked spectacular in isolation.
Together, they marked a change in the way she was programming.
She was no longer simply telling the computer what to draw.
She was beginning to ask:
What is the thing I am building?
Theme
Abstraction
What Is Possible
A board can become a game.
A piece can have a logical position independent of how that position is drawn. A move can eventually transform one game state into another.
How Does It Happen
Start with the smallest real object.
One game.
One array of pieces.
One piece.
One position.
One change of state.
Then let the structure grow.
Why Does It Matter
A visual board is only one way to represent a game.
Once the model becomes independent of the picture, the same game can potentially be displayed by UIKit, p5.js, or something entirely different.
The board is not the game.
The first piece is where the model begins to come alive.