DEV Community

Derp
Derp

Posted on

Advent of code 2021 - day 4

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[])
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

Note the 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

Oldest comments (0)