30 Edges, 33 Lines
Albert is a math lover who has just finished Grade 10. He was working on a P5.js subproject: drawing an icosahedron.
At one point, I noticed him writing:
12 * 5 / 2
I smiled quietly.
He was already thinking mathematically. An icosahedron has 12 vertices, each vertex connects to 5 others, and every edge is counted twice:
12 × 5 / 2 = 30 edges.
So connecting the 12 vertices should not be a big deal.
Or so it seemed.
Albert was writing lines such as:
line(-m, 0, s, -s, -m, 0);
line(-m, 0, s, 0, s, m);
line(-m, 0, s, 0, -s, m);
line(-m, 0, s, -m, 0, -s);
Thirty perfect edges.
Yet somehow he couldn't find why there were 33 lines of code.
Albert started scrolling up and down through his definition of the 12 points:
points = [
[m,0,s], [-m,0,s], [-m,0,-s], [m,0,-s],
[s,m,0], [s,-m,0], [-s,m,0], [-s,-m,0],
[0,s,m], [0,s,-m], [0,-s,m], [0,-s,-m]
];
He looked like a lost detective examining mysterious triples of coordinates.
Ten minutes passed.
Then twenty.
Half an hour passed.
He was still investigating.
Suddenly I spotted the problem.
"Why don't we use your cool list of points? Rename it to p to save some typing first. We only need to handle 0 to 11, right?"
Then I thought:
"Wait. We should create a super convenient function."
We didn't want to keep writing line with six coordinates.
Let's use ln instead—sorry, a terrible name for "drawing line," not logarithm. 😂
And let the function take only two indices:
function ln(a,b) {
line(p[a][0],p[a][1],p[a][2],
p[b][0],p[b][1],p[b][2]);
}
Albert got it immediately.
The code suddenly became much easier to read:
function drawIcosahedron() {
for(let i=0;i<12;i++) {
push();
translate(p[i][0],p[i][1],p[i][2]);
sphere(5);
pop();
}
ln(0,3);
ln(0,4);
ln(0,5);
ln(0,8);
ln(0,10);
}
The mysterious coordinate triples had disappeared from the edge definitions.
An edge was now simply:
ln(0,3)
Two numbers.
Two vertices.
And suddenly Albert could check the mathematics directly.
Vertex 0 should have five neighbors.
Here they were:
3, 4, 5, 8, 10.
No need to inspect six coordinates every time.
The representation had changed, and with it, the problem became understandable.
Sometimes a programming problem is not difficult because the mathematics is difficult.
It is difficult because the representation hides the mathematics.
Albert already had the right mathematical idea:
12 × 5 / 2 = 30.
He already had the right data:
12 points.
What he was missing was a convenient bridge between the two.
The points list became that bridge.
A good abstraction doesn't merely make code shorter.
It makes the structure of the problem visible—and therefore easier to verify.
And perhaps the most satisfying part:
I didn't give Albert a new tool.
I rescued him with a tool he had already built himself.