# Bowling kata as a zipper

Gautier DI FOLCO September 17, 2024 [Code practice] #haskell #code kata #coding dojoA few days ago I have practiced the bowling kata with one of the members of the Software Crafters Lyon.

It's a kata I've only tried two times before that (and I've never played a real world bowling game, though, there is a bowling 10 minutes away from my home).

Let's dive in with some basic tests:

```
it "A game with no pins down should be 0" $
bowlingScore (replicate 20 0) `shouldBe` 0
it "A game with two pins down on each try should be 40" $
bowlingScore (replicate 20 2) `shouldBe` 40
```

Note: I have choosen to represent tries and not frames for simplicity, which is not a safe representation, but we aim to trust our inputs.

A trivial implementation is to simply sum tries:

```
= sum
bowlingScore
```

Then, we should handle spares (when it takes two tries to knock them all down):

```
it "A game with all 5-spares frames should be 150" $
bowlingScore (replicate 21 5) `shouldBe` 150
```

In order to do that show somehow model the frame.

An easy way to have arbitrary list traversal is to use `unfoldr`

which iterate
while having a valid output:

```
= sum . take 10 . unfoldr go
where
go =
\case
(x : y : z : nexts)
| x + y == 10 -> Just (10 + z, z : nexts)
| otherwise -> Just (x + y, z : nexts)
(x : y : nexts) -> Just (x + y, nexts)
[] -> Nothing
bowlingScore
```

There is a design tension here:

`go`

is partial (i.e. we do not handle 1-element list`[_]`

), in production code, warning would make it fail`take 10`

emphasis the number of frames

Finally we have to handle strikes (10 pins down in one try):

```
it "A game with all strike frames should be 300" $
bowlingScore (replicate 12 10) `shouldBe` 300
```

All we have to do it add one line for this case:

```
= sum . take 10 . unfoldr go
where
go =
\case
(x : y : z : nexts)
| x == 10 -> Just (10 + y + z, y : z : nexts)
| x + y == 10 -> Just (10 + z, z : nexts)
| otherwise -> Just (x + y, z : nexts)
(x : y : nexts) -> Just (x + y, nexts)
[] -> Nothing
bowlingScore
```

There is something quite annoying: in each of our cases we look for two or three elements which looks like a good use case for a Zipper.

It could be as simple as:

```
data BowlingZipper a = Z a a [a]
```

We can rewrite our function adding a local smart constructor:

```
= sum . take 10 . unfoldr go . toBowlingZipper
where
go =
\case
Z x y (z : nexts)
| x == 10 -> Just (10 + y + z, Z y z nexts)
| x + y == 10 -> Just (10 + z, toBowlingZipper (z : nexts))
| otherwise -> Just (x + y, toBowlingZipper (z : nexts))
Z x y nexts -> Just (x + y, toBowlingZipper nexts)
toBowlingZipper (x : y : nexts) = Z x y nexts
bowlingScore
```

`go`

is now a total function (i.e. all branches are covered), only
`toBowlingZipper`

(the smart constructor) is partial, which is better, we could
push it to the boundaries in more complex project, letting our core domain work
only with sound values.