code / art / projects

Code Jam 2010: Incrementing a Binary Counter

The Problem

Problem A in the qualifying round of this year’s Google CodeJam contest was really clever. The problem used a classic made-for-TV gadget from the 80s: The Clapperâ„¢ (“snapper” in google’s version) and went like this:

The Snapper is a clever little device that, on one side, plugs its input plug into an output socket, and, on the other side, exposes an output socket for plugging in a light or other device.

When a Snapper is in the ON state and is receiving power from its input plug, then the device connected to its output socket is receiving power as well. When you snap your fingers – making a clicking sound – any Snapper receiving power at the time of the snap toggles between the ON and OFF states.

In hopes of destroying the universe by means of a singularity, I have purchased N Snapper devices and chained them together by plugging the first one into a power socket, the second one into the first one, and so on. The light is plugged into the Nth Snapper.

Initially, all the Snappers are in the OFF state, so only the first one is receiving power from the socket, and the light is off. I snap my fingers once, which toggles the first Snapper into the ON state and gives power to the second one. I snap my fingers again, which toggles both Snappers and then promptly cuts power off from the second one, leaving it in the ON state, but with no power. I snap my fingers the third time, which toggles the first Snapper again and gives power to the second one. Now both Snappers are in the ON state, and if my light is plugged into the second Snapper it will be on.

I keep doing this for hours. Will the light be on or off after I have snapped my fingers K times? The light is on if and only if it’s receiving power from the Snapper it’s plugged into.

It’s a great problem because we have a situation that is easily modeled with a computer program, and yet a naive solution will be far too inefficient to process the inputs that google provides (e.g. 108 claps).

Here is a direct-to-code translation of the functioning of a “chain of snappers” implemented in (very verbose) Haskell:

module Main

type ClapperChain = [Bool]

clapOnOff :: ClapperChain -> ClapperChain
clapOnOff [] = []
clapOnOff (c:cs) =
    if isPowered cs
        then toggleState c : clapOnOff cs
        else c : clapOnOff cs

isPowered :: ClapperChain -> Bool
isPowered []     = True -- at the outlet
isPowered (c:cs) = inOnState c && isPowered cs

inOnState = id
toggleState = not

We can then look at a few iterations (snaps) and see how the chain changes. True is a “snapper” in the ON state:

*Main> take 4 $ iterate clapOnOff [False,False,False]

A Solution

After working out a few iterations on paper I realized that the snappers follow the pattern of an ascending binary number count: 000, 001, 010, 011...

The lamp will be on when all of the snappers are 1s (i.e. in the ON state) which will occur every (2number_of_snappers) snaps. Thus my solution was simply the following:

caseAlgorithm (n,k) =
    if (((k+1) `mod` 2^n) == 0)
        then ON
        else OFF

More Code and Thoughts

Here is a more terse and better version of the Snapper simulation code I posted above, now simply called increment for incrementing a binary number:

increment :: ClapperChain -> ClapperChain
increment [] = [] -- [] is the outlet
increment chain@(c:cs)
    | and cs = map not chain
    | otherwise = c : increment cs

We can convert our lists into pretty strings with…

showBinary :: ClapperChain -> String
showBinary = map (\b-> if b then '1' else '0')

And play with it like so:

*Main> map showBinary $ take 9 $ iterate increment  [False,False,False]

I liked realizing that a binary count could be represented recursively and mechanically. It led me to look into how binary counter circuits are implemented in electronics (it turns out The Clapperâ„¢ is not generally involved), and got me thinking about cellular automata.

A binary counter could be implemented as Cellular Automata in which each bit is an Automaton with two states: an ON/OFF state and a POWERED/UNPOWERED state.

…although I think POWERED or UNPOWERED would have to be evaluated lazily, which might not fit the model.

Oh well, good luck to everyone doing the competition this year!