When the Board Became a Coordinate System
Situation
Tianjing had been building her Chinese chess board in UIKit for days.
At first, the board was mostly about drawing: lines, pieces, margins, cell sizes, and pixels.
Then she made an important step forward.
Instead of thinking in screen pixels, she created a little helper:
func drawLine(
fromCol: Int,
fromRow: Int,
toCol: Int,
toRow: Int
) {
let p = UIBezierPath()
p.move(to: CGPoint(
x: marginX + CGFloat(fromCol) * cellSide,
y: marginY + CGFloat(fromRow) * cellSide
))
p.addLine(to: CGPoint(
x: marginX + CGFloat(toCol) * cellSide,
y: marginY + CGFloat(toRow) * cellSide
))
p.stroke()
}
Now she could say:
drawLine(fromCol: 0, fromRow: 0, toCol: 8, toRow: 0)
The board had become a coordinate system.
Instead of thinking about pixels, Tianjing could think about rows and columns.
That sounds simple.
For a beginner, it is huge.
The Int and CGFloat surprise
There was another little lesson hiding inside drawLine().
When Tianjing first created the function, the compiler complained about the number types. We changed some Ints to CGFloats without making much fuss.
Everything worked.
Until Tianjing confidently tried to use her new tool inside a loop:
for i in 0..<10 {
drawLine(
fromCol: 0,
fromRow: i,
toCol: 8,
toRow: i
)
}
The compiler stopped her.
Why?
Because i was an Int, while the function was expecting CGFloat.
Tianjing had actually understood something important: of course drawLine() should work inside a loop.
The problem was the type.
So we stepped back.
Columns and rows are logical, discrete positions.
They should be Int.
The conversion to CGFloat belongs inside the function, when logical coordinates finally become physical screen positions.
And then—
everything worked.
A tiny compiler complaint had quietly taught her about the boundary between the logical world and the screen world.
Then came the numbers 0...6
During another refactoring, Tianjing was still using integers to represent chess-piece ranks.
0, 1, 2...
all the way to 6.
And, predictably, the mysterious integers eventually caused trouble.
A black pawn appeared in the position where the black knight should have been.
Before Tianjing tried to fix it, I stopped her.
“Wait a minute. Leave it there. I'll introduce a much better way to represent our ranks than using 0~6. Then it'll be much easier to figure out why this brave pawn takes the seat of knight.”
So we moved on.
She replaced those mysterious numbers with an enum:
enum Rank {
case che
case ma
case xiang
case shi
case jiang
case pao
case zhu
}
For the first time, Tianjing experienced what an enum could do.
The code no longer said:
“This piece has rank 6.”
It could say:
.zhu
The piece had acquired a name.
And then we completely forgot about the black pawn. 😂
“Look at the black pawn!”
We celebrated the enum breakthrough.
Then, suddenly, I remembered.
That black pawn was still sitting in the knight's seat.
I shouted:
“Look at the black pawn!”
And this time something beautiful happened.
Tianjing didn't have to hunt through mysterious integers.
She simply followed the code related to:
.zhu
The pawn.
She found the problem.
And fixed it.
Instantly.
The prediction had worked.
The new representation had already changed the way she debugged.
Learning
Tianjing didn't merely learn how to draw a Chinese chess board.
She learned that the way we represent something changes how we think about it.
Pixels became logical coordinates.
CGFloat and Int found their proper places.
0...6 became Rank.
And finally, debugging changed from searching through numbers to searching through meaning.
A better representation doesn't just make code easier to read.
It makes mistakes easier to see.
The Bigger Picture
There was another small discovery waiting in the code.
The piece color was still represented as:
0 = black
1 = red
Tianjing looked at it and said:
“It's easy to remember 0 is black and 1 is red.”
So we left it alone.
For now.
Perhaps one day she will look at that code and ask the same question she asked about Rank.
And when that happens, there will be another door.
Theme
Good programming is not only about making things work.
It is about finding representations that make the thing itself easier to understand.
Sometimes a student learns that lesson because the compiler complains.
Sometimes because a black pawn sits in the wrong chair.
And sometimes because, after days of using numbers, a little enum finally makes everything click.
What Is Possible
A beginner can move from pixels to logical coordinates, from numbers to named concepts, and gradually make a program resemble the world it is modeling.
How Does It Happen
Build something real. Live with an imperfect representation long enough to feel its limitations. Then change the representation when the student is ready to understand why.
Why Does It Matter
The best abstraction is not merely elegant code.
It gives the learner a better way to see the problem.