Aachen University physicist Jörg Pretz has devised a binary clock in the shape of a triangular array of 15 lamps.

driehoekige klok
Design of a triangular clock by German physicist Jörg Pretz.

Here's how to read it:

So the clock above shows the following time: \[ 6\ \textrm{hours} + (2 \times 2\ \textrm{hours}) + (2 \times 30\ \textrm{minutes}) + (3 \times 1\ \textrm{minute}) = 11\!:\!03 \] The fact that the lamps have a red color shows that it's afternoon, or 23:03 on a 24-hour clock. The same array of lamps would be displayed in green at 11:03 in the morning. Here are some more examples:

08:05 10:59 18:35 23:59

The time value assigned to each lamp is the total time value of the row below if that row contained one additional lamp. On each row the lamps light up from left to right, so a row with $$n$$ lamps can display $$n + 1$$ states (all lamps off to all lamps on). So for a triangular array with $$n$$ lamps on the bottom row, the total number of states is \[ (n + 1) \times ((n - 1) + 1) \times ((n - 2) + 1) \times \cdots \times (1 + 1) = (n + 1)! \] That is, it's a factorial of a natural number. And by a happy coincidence, the total number of minutes in 12 hours is such a factorial ($$12 \times 60 = 720 = 6!$$). Jörg Pretz's article mentions the following:

Thus the whole concept works because our system of time divisions is based on a sexagesimal system dating back to the Babylonians, rather than a decimal system as proposed during the French Revolution.

However, the clock has a small design error: with all lamps turned off it doesn't tell whether it's midnight (00:00) or noon (12:00). Technically speaking we consider 00:00 to be the first minute of the morning (zero green lamps lit on each row) and 12:00 to be the first minute of the afternoon (zero red lamps lit on each row).

Assignment

Define a class Clock that implements triangular clocks in Python. This class must support at least the following methods:

Example

>>> clock = Clock(11, 3)
>>> clock.lamps()
((1, 2, 2, 0, 3), 'G')
>>> clock
Clock(11, 3)
>>> print(clock)
    G
   G G
  G G .
 . . . .
G G G . .
>>> clock.updateHours()
Clock(12, 3)
>>> clock.lamps()
((0, 0, 0, 0, 3), 'R')
>>> clock.updateHours(11)
Clock(23, 3)
>>> clock.lamps()
((1, 2, 2, 0, 3), 'R')
>>> print(clock)
    R
   R R
  R R .
 . . . .
R R R . .
>>> clock.updateMinutes()
Clock(23, 4)
>>> clock.lamps()
((1, 2, 2, 0, 4), 'R')
>>> clock.updateMinutes(42)
Clock(23, 46)
>>> clock.lamps()
((1, 2, 3, 2, 4), 'R')
>>> print(clock)
    R
   R R
  R R R
 R R . .
R R R R .
>>> clock.updateMinutes(13)
Clock(23, 59)
>>> clock.lamps()
((1, 2, 3, 4, 5), 'R')
>>> print(clock)
    R
   R R
  R R R
 R R R R
R R R R R
>>> clock.updateMinutes()
Clock(0, 0)
>>> clock.lamps()
((0, 0, 0, 0, 0), 'G')
>>> print(clock)
    .
   . .
  . . .
 . . . .
. . . . .
>>> clock.updateHours(10).updateMinutes(17)
Clock(10, 17)
>>> clock.lamps()
((1, 2, 0, 2, 5), 'G')
>>> print(clock)
    G
   G G
  . . .
 G G . .
G G G G G

>>> Clock(42, 42)
Traceback (most recent call last):
AssertionError: invalid time

Epilogue

Feel free to play around with this interactive triangular clock.

Resources