Bowling Kata Golf in Perl and Haskell

In November I got together with Tom Moertel and Chris Winters at a coffee shop in Mt. Lebanon (Aldo, sorry, you were closed). The premise was to solve the Bowling Game Kata in Haskell. Tom has already completed this on his own, but we sat down to give it a shot together. Our attempt together follows:

module Bowling where

type FrameScore  = Int
type FrameRolls  = [Int]
type FrameNumber = Int

data FrameType = Strike | Spare | Normal | Ten
deriving (Show, Eq)

data FrameInfo = Frame FrameScore FrameRolls FrameNumber FrameType
deriving (Show)

score :: [Int] -> Int
score = scoreFrames . parseFrames 1

parseFrames :: Int -> [Int] -> [FrameInfo]
parseFrames n (x:y:zs)
| n == 10       = Frame (sum (x:y:zs)) (x:y:zs) n Ten : []
| x == 10       = Frame 10 (x:[]) n Strike      : parseFrames (n + 1) (y:zs)
| (x+y) == 10   = Frame 10 (x:y:[]) n Spare     : parseFrames (n + 1) zs
| otherwise     = Frame (x+y) (x:y:[]) n Normal : parseFrames (n + 1) zs

getTwo :: [FrameInfo] -> [Int]
getTwo = take 2 . unrollFrames

getOne :: [FrameInfo] -> [Int]
getOne = take 1 . unrollFrames

unrollFrames :: [FrameInfo] -> [Int]
unrollFrames [] = []
unrollFrames ((Frame _ (xs) _ _) : ys) = xs ++ unrollFrames ys

scoreFrames :: [FrameInfo] -> Int
scoreFrames ((Frame s _ n t) : xs)
| n == 10       = s
| t == Strike   = sum (s : getTwo xs ++ scoreFrames xs : [])
| t == Spare    = sum (s : getOne xs ++ scoreFrames xs : [])
| otherwise     = sum (s : scoreFrames xs : [])

That’s rather long winded, especially compared to Tom’s version which is short and elegant. I went home that night and created an alternate short and elegant version:

module TinyBowling where
score           = c 1
a n  rs         = sum $ take n rs
c 10 rs         = a 3 rs
c f  rs         = s (f+1) rs
s f  (10:rs)                = a 3 rs + c f rs
s f  (x:y:rs)   | (x+y)==10 = a 3 rs + c f rs
| otherwise = a 2 rs + c f rs

I was reviewing this code tonight and discovered that I’d really like to create a short and elegant Perl version. I gave it a shot but I’m not pleased at all. In this round of Golf I think Haskell wins on elegance, hands down:

package Bowling;
sub score { c(1, 0, @_) }
sub c {
my ($f, $s, @rs) = @_;
my ($x, $y, @zs) = @rs;

return $s                            if $f > 10;
return _c($f, $s, 2, \@rs, [@zs]   ) if !($x && $y);
return _c($f, $s, 3, \@rs, [$y,@zs]) if $x == 10;
return _c($f, $s, 3, \@rs, [\@zs]  ) if $x + $y == 10;
}
sub _c {
my ($f, $s, $n, $rs, $zs) = @_;
c($f+1, eval(join '+',$s,map $_||0, @{$rs}[0..$n-1]), @{$zs});
}

3 Responses to “Bowling Kata Golf in Perl and Haskell”

  1. Gravatarrich said:

    Yeah, we close earlier in the winter. Too bad we missed you, as I (Rich) have been reading Ross’s blog for a couple of years now - what a freaking amazing guy with vision.

    Now if he’d only invest a bit in Lithuania (half Lit here) instead of Estonia ;-)

    at 10:27 am on December 20th, 2006
  2. GravatarCasey West said:

    Small World, Rich. Sometime in 2007 - before the new school year - I’ll be executing Socialtext vision from your place a few times a month.

    I think we’ve actually considered hiring some European support folks out of Lithuania. I’m not sure what the status is, but we aren’t ruling out Lithuania.

    Maybe you know somebody that should be working for us. :-)
    That reminds me, I should put up a flier in the coffee shop…

    at 10:46 am on December 20th, 2006
  3. GravatarRoss Mayfield said:

    labis labis

    at 2:35 pm on December 20th, 2006

Leave a Reply

About You