Living Museum of Learning

Where real moments become exhibits
← Prev Next →
30 Edges, 33 Lines

30 Edges, 33 Lines

When an icosahedron becomes a detective story—and a list of points becomes the rescue

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.