Advent of code 2021 - day 4
Tags: adventofcode, functional, typescript
Published: 2021-12-29 04:15:59

Part 1:

We are playing simultaneous bingo where we have an array of numbers being called out as well as several matricies of bingo cards. We then need to identify which matrix has the bingo and sum up the remaining uncalled numbers.

So whenever a new number is called out, for each board, we Either get a Incomplete board or a Bingo Board. This translates to a function signature of `number -> Incomplete Board ->  Either (Bingo Board) (Incomplete Board)`. Using `sequence` we can turn our array of Eithers into Either a Bingo Board or an array of Incomplete Board. `sequeunce:: Monad m => [m a] -> m [a]`

There were two things that tripped me up in part 1 of this challenge though, the first was the parsing of the input. In previous challenges, I did it manually via search/replace and regex to turn it into arrays or what not. With this challenge, i accidentally chopped off a few digits in my example array causing the wrong answer to show up. Thankfully, I created a `show` function for debugging which enabled me to pick this error up quickly.

The second thing which tripped me up was the signature of fold
`export declare const fold: <E, A, B>(onLeft: (e: E) => B, onRight: (a: A) => B) => (ma: Either<E, A>) => B`. I had previously used `identity` as the onLeft function, however that sets the return type `B` and this caused a type error when i returned an Either for my onRight function. After realising my error, I returned an Either for my onLeft function.

`E.fold(
    (complete) => E.left(complete),
    (incompletes) => play(rest)(incompletes)
  )
`

-- Part 2
Instead of returning the first bingo board, we want to return the _last_ bingo board. We used `sequence` in part one which eagerly evaluates the first Left. Now in Part 1, `sequence` works because we stop immediately when we have found our winning bingo game so the return type of Either Complete Incomplete [] makes sense. However in part 2, it is not one or the other, we need both until we finish going through all the bingo numbers to find the _last_ winning bingo board. Hence we need a return type of (Option<(number, Complete)>, Incomplete[]) representing the last winning bingo number and bingo board and the remaining list of incomplete boards. (This thought occurred to me several days later).

My strategy is to create a playLast function with the signature
```
  playLast:: number -> Incomplete[] -> (Option<(number,Complete)>, Incomplete[])
```
playLast also has the interesting situation where you might have several winning bingo games at the same time. To tackle this, I partitioned the `partitionMap` function which has as similar signature to `partitionEithers:: [Either a b] -> ([a], [b])`. I then return the head of the Completed games.

When reducing over my bingo numbers, I needed to figure out a way of joining my two Option<(number,Complete)> together such that the last Some `won`. To do this, I created a Monoid over Options
```
const getLastSome = O.getMonoid<any>(S.last());
```
Note the <any> required to make it work as without it as without it, typescript substitutes `never` into there and it won't work with any Options. 


Also sometimes the typescript compiler complains unless you use `pipe`.



https://codesandbox.io/s/jolly-flower-5o78i?file=/src/index.ts