9/05/2010
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.
Read the rest of this article »
22/08/2009
I put together a skeleton module which should be usable for any of the problems in this year’s Google CodeJam Programming Contest (as long as they don’t adopt a new format/pattern for the problems this year). The module includes some useful parsing functions which should in the worst case be useful as a cheatsheet for those not too experienced with Parsec (*cough me). I hope it will encourage people to sign up and use Haskell in the contest!
To adapt the module to a problem, one defines the following:
- a type
Case into which we will parse a test case (i.e. problem)
- a type
SolvedCase, representing a solution to a test case
- our
algorithm :: Case -> SolvedCase
- a Parser
caseParser which can parse a single test case (n.b. not the whole file) into the Case type
- a function
formatCase :: SolvedCase -> String which brings the solution to the state where it can be prepended with the standard “Case #1: ” string
Here is the module, filled in to solve the Minimum Scalar Product practice problem. You can download the code here:
module Main
where
import Text.ParserCombinators.Parsec
import IO hiding (try)
import System.Environment
import Data.List (sort)
import Control.Arrow
type Input = [Case]
type Solution = [SolvedCase]
type Output = [String]
type Case =
([Int],[Int])
type SolvedCase =
Int
algorithm :: Case -> SolvedCase
algorithm =
sum . uncurry (zipWith (*)) . (reverse . sort *** sort)
caseParser :: Parser Case
caseParser = do
w <- word
let n = read w
as <- count n word
bs <- count n word
return (map read as, map read bs)
formatCase :: SolvedCase -> String
formatCase sol =
show sol
main = do
(f:_) <- getArgs
file <- readFile f
let inp = parseWith mainParser file
solution = map algorithm inp
solutionStrings = map formatCase solution
outp = zipWith (++) prefixes solutionStrings
putStr $ unlines outp
parseWith p = either (error . show) id . parse p ""
mainParser :: Parser Input
mainParser = do
n <- word
ms <- count (read n) caseParser
return ms
<?> "mainParser"
prefixes = [ "Case #" ++ show n ++ ": " | n <- [1..]]
wholeLine :: Parser String
wholeLine = manyTill anyChar (try newline) <?> "wholeLine"
whiteSepLine = manyTill spaceSepWord newline <?> "whiteSepLine"
word = do
w <- many1 nonWhite
spaces
return w
<?> "word"
spaceSepWord = do
w <- many1 nonWhite
many (char ' ')
return w
<?> "spaceSepWord"
twoWordsSepBy c = do
x <- manyTill nonWhite (try$ char c)
y <- many1 nonWhite
many (char ' ')
return (x,y)
<?> "twoWordsSepBy"
nonWhite = noneOf " \v\f\t\r\n" <?> "nonWhite"