# Advent of Code 2023 - Day 2: Cube Conundrum

::

 ```1 2``` ```#lang iracket/lang #:require racket (require "../advent.rkt" threading) ```

Our data today is as follows:

``````Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green``````

For today’s task, I found it helpful to make use of the `parallel-combine` combinator from Hanson & Sussman’s “Software Design for Flexibility”. This combinator applies `f` and `g` to the input, in parallel, and combines their output using `h`. Pictorially, it looks like this:

``````                   ┌───────────────────┐
│ parallel-combine  │
└───────────────────┘
┌──────────────────────────────────────────┐
│                                          │
│         ┌───────┐                        │
│     n   │       │   1                    │
│  ┌─────▶│   f   │──────┐                 │
│  │      │       │      │      ┌───────┐  │
│  │      └───────┘      │      │       │  │
n  ───┼──┤                     ├─────▶│   h   │──┼───▶
│  │      ┌───────┐      │      │       │  │
│  │      │       │      │      └───────┘  │
│  └─────▶│   g   │──────┘                 │
│     n   │       │   1    ┌────────────┐  │
│         └───────┘        │ h o (f, g) │  │
│                          └────────────┘  │
└──────────────────────────────────────────┘``````

I added the following function to the `advent.rkt` support module:

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22``` ```;; (parallel-combine h f g) -> any ;; h : procedure? ;; f : procedure? ;; g : procedure? ;; ;; Functions f and g take the same number of arguments. The input to ;; parallel-combine is passed to both of them. Their outputs are ;; combined by the function h, of two arguments. ;; ;; For example: ;; ((parallel-combine cons car (compose1 (curry map add1) cdr)) '(1 2 3)) ;; -> '(1 3 4) ;; ;; A combinator from "Software Design for Flexibility" by Hanson & ;; Sussman (define (parallel-combine h f g) (define (the-combination . args) (h (apply f args) (apply g args))) the-combination) ((parallel-combine cons car (compose1 (curry map add1) cdr)) '(1 2 3)) ```

`’(1 3 4)`

As always, first we’ll parse the data:

 ```1 2 3 4``` ```(define in (map (parallel-combine cons cadr (compose1 (curry chunk 2) (curry (flip drop) 2))) (parse-aoc 2 atoms))) (car in) ```
``````----------------------------------------------------------------------------------------------------
day02.txt -> 10377 chars, 100 lines; first 3 lines; last 2 lines:
----------------------------------------------------------------------------------------------------
Game 1: 7 blue, 5 red; 10 red, 7 blue; 5 blue, 4 green, 15 red; 4 gree ... d; 5 red, 4 blue, 3 green
Game 2: 8 green, 3 red; 7 blue, 6 red, 8 green; 7 blue, 3 green, 6 red ... ; 6 blue, 3 green, 12 red
Game 3: 6 blue, 3 red, 7 green; 3 red, 3 green, 8 blue; 8 blue, 11 red ... n; 9 blue, 7 green, 1 red
...
Game 99: 6 blue, 11 red, 7 green; 9 red, 6 green, 1 blue; 9 red, 2 blue
Game 100: 1 red, 4 blue, 2 green; 6 red, 2 green, 11 blue; 1 red, 1 blue, 2 green; 1 red, 7 blue
----------------------------------------------------------------------------------------------------
(parse 2) -> 100 entries:
----------------------------------------------------------------------------------------------------
(("Game" 1 7 "blue" 5 "red" 10 "red" 7 "blue" 5 "blue" 4 "green" 15 "re ... "red" 4 "blue" 3 "green")
("Game" 2 8 "green" 3 "red" 7 "blue" 6 "red" 8 "green" 7 "blue" 3 "gre ... blue" 3 "green" 12 "red")
...
("Game" 100 1 "red" 4 "blue" 2 "green" 6 "red" 2 "green" 11 "blue" 1 " ... "green" 1 "red" 7 "blue"))
----------------------------------------------------------------------------------------------------``````

`’(1 (7 “blue”) (5 “red”) (10 “red”) (7 “blue”) (5 “blue”) (4 “green”) (15 “red”) (4 “green”) (6 “red”) (7 “blue”) (5 “green”) (8 “blue”) (4 “red”) (5 “red”) (4 “blue”) (3 “green”))`

As shown in that last line, we now have a list of lines where each line is of the form:

``(<id> (<n> <color) (<n> <color>) ...)``

We used `parallel-combine` there because we need to both retain the id, which we do with `cadr`:

 ```1 2``` ```(define f cadr) (f '("Game" 2 8 "green" 3 "red" 7 "blue" 6 "red")) ```

`2`

And we also need to create a list of pairs of numbers and colors. Which we do with:

``(compose1 (curry chunk 2) (curry (flip drop) 2))``

That’s a lot, so let’s break it down. First we just want to drop the first two items of the list, e.g.:

 `1` ```(drop '("Game" 2 8 "green" 3 "red" 7 "blue" 6 "red") 2) ```

`’(8 “green” 3 “red” 7 “blue” 6 “red”)`

Unfortunately, the parameter order for `drop` doesn’t lend itself to partial application, so we use `flip` to flip the parameter order to have the list come last:

 `1` ```((flip drop) 2 '("Game" 2 8 "green" 3 "red" 7 "blue" 6 "red")) ```

`’(8 “green” 3 “red” 7 “blue” 6 “red”)`

We then use `curry` to create a partially applied function so we can compose it:

 `1` ```((curry (flip drop) 2) '("Game" 2 8 "green" 3 "red" 7 "blue" 6 "red")) ```

`’(8 “green” 3 “red” 7 “blue” 6 “red”)`

That provides the list we want to group into chunks. Again, we’ll use `curry` to partially apply `chunk` with the argument 2:

 `1` ```((curry chunk 2) '(8 "green" 3 "red" 7 "blue" 6 "red")) ```

`’((8 “green”) (3 “red”) (7 “blue”) (6 “red”))`

Composing those two functions gives us the function with which we can `map` over the input:

 ```1 2``` ```(define g (compose1 (curry chunk 2) (curry (flip drop) 2))) (g '("Game" 2 8 "green" 3 "red" 7 "blue" 6 "red")) ```

`’((8 “green”) (3 “red”) (7 “blue”) (6 “red”))`

We now have our `f` and `g` functions as follows:

``````f = cadr
g = (compose1 (curry chunk 2) (curry (flip drop) 2))
``````

We’ll call `f` with the line, and we’ll call `g` with the line, and then combine those two results with `h`:

``````h = cons
``````

The resulting combinator is:

``````(parallel-combine cons
(compose1 (curry chunk 2) (curry (flip drop) 2)``````

And the end result will be single list where the first element is the `id` and the rest of the list is pairs of `(<n> <color>)`:

``'(1 (7 "blue") (5 "red") (10 "red") (7 "blue") ...)``

Our main function for today’s task is `max-pixel`. It will process a line, and return a 3-tuple of `(red green blue)` representing the maximum number for each of those colors:

 ```1 2 3 4 5 6 7 8 9``` ```(define (max-pixel lst [red 0] [green 0] [blue 0]) (if (null? lst) (list red green blue) (match (car lst) [ (list n "red") (max-pixel (cdr lst) (max n red) green blue) ] [ (list n "green") (max-pixel (cdr lst) red (max n green) blue) ] [ (list n "blue") (max-pixel (cdr lst) red green (max n blue)) ]))) (max-pixel '((7 "green") (3 "blue") (9 "red") (4 "blue") (1 "green") (10 "red"))) ```

`’(10 7 4)`

With the above in place, we can now solve both parts. Here’s the `part1` function:

``````(define (part1)
(define max-rgb '(12 13 14))
(~> (map (parallel-combine cons car (compose1 max-pixel cdr)) in)
(filter (compose1 (curry andmap >= max-rgb) cdr) _)
(map car _)
(list-sum _)))``````

Let’s break that down. We’ll make use of `parallel-combine` again, and convert the input lines into lines of the form `'(id red green blue)` where `red`, `green` and `blue` are the maximum values for those colors.

 ```1 2 3``` ```(define lst (map (parallel-combine cons car (compose1 max-pixel cdr)) in)) (take lst 10) ```

`’((1 15 5 8) (2 12 8 7) (3 11 7 9) (4 5 4 1) (5 17 8 10) (6 13 6 8) (7 6 14 5) (8 9 3 9) (9 8 9 8) (10 14 12 5))`

We then filter the list to retain only lines where the max color values don’t exceed the specified limits:

 ```1 2 3 4 5``` ```(define max-rgb '(12 13 14)) (define lst (filter (compose1 (curry andmap >= max-rgb) cdr) lst)) (take lst 3) ```

`’((2 12 8 7) (3 11 7 9) (4 5 4 1))`

Next, we extract the ids:

 ```1 2 3``` ```(define lst (map car lst)) (take lst 5) ```

`’(2 3 4 8 9)`

And sum them:

 `1` ```(list-sum lst) ```

`2528`

Part 2 is simpler, we just need to compute the max `(red green blue)` values for all of the lines, multiply those values together for each line, and sum all of those products:

 ```1 2 3 4 5 6``` ```(define (part2) (~> (map (compose1 max-pixel cdr) in) (map list-prod _) (list-sum))) (part2) ```

`67363`