Advent of Code 2022 - Day 3: Rucksack Reorganization

:: programming, puzzle, racket

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

Day 3 - Part 1

Rucksack Reorganization

We’re given some sample input:

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

The first half of each list contains items for one compartment of the backpack, and the second half contains items for the other compartment. Each backpack has, erroneously, one item in both compartments/halves.

Lower case items have priorities 1 to 26; upper case items 27 to 52.

Find the item type that appears in both compartments of each rucksack. What is the sum of the priorities of those item types?

1
(define in (parse-aoc 3 string->list))
----------------------------------------------------------------------------------------------------
day03.txt -> 9698 chars, 300 lines; first 3 lines; last 2 lines:
----------------------------------------------------------------------------------------------------
LLBPGtltrGPBMMsLcLMMVMpVRhhfCDTwRwRdTfwDllRRRDhC
gNFJHJFgtZFJjZJHNNFWZWZwwDjCwSDhfCDbdwjfwDTTDT
gmQNZnZNHWnqmQpLtVLMBsPpBqrL
...
hMhhDBwMhDDfCRRBjFDDTTWjdWmrmdWqjlmmmjJz
RSpSSBhppDhRncRLswZLGvtGvNcNtL
----------------------------------------------------------------------------------------------------
(parse 3) -> 300 entries:
----------------------------------------------------------------------------------------------------
((#\L #\L #\B #\P #\G #\t #\l #\t #\r #\G #\P #\B #\M #\M #\s #\L #\c # ...  #\R #\R #\R #\D #\h #\C)
(#\g #\N #\F #\J #\H #\J #\F #\g #\t #\Z #\F #\J #\j #\Z #\J #\H #\N # ...  #\w #\D #\T #\T #\D #\T)
...
(#\R #\S #\p #\S #\S #\B #\h #\p #\p #\D #\h #\R #\n #\c #\R #\L #\s # ...  #\v #\N #\c #\N #\t #\L))
----------------------------------------------------------------------------------------------------

Parsing gives us a list of characters for each backpack.

To compute the priority of an item, we’ll use point free programming to define a function that is a composition of two functions - the first function will get the index of an item in a string, and the second will add 1 to that value since priorities are 1-based.

To create the first function, we’ll partially apply the string-index-of function (which accepts 2 arguments - a string and a character) via curry; the resulting function will accept one parameter, the character representing the item:

1
2
3
4
5
(define priority
  (compose add1
           (curry string-index-of "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")))

(list (priority #\c) (priority #\B))

’(3 28)

The main part 1 function will split the backpack items into two equal sets, compute the set intersection to find the bogus item, and compute the priority of the item:

1
2
3
4
5
6
(define (part1 pack)
    (~> (apply set-intersect (split-2 pack))
        set-first
        priority))

(part1 (first in))

12

To solve part 1, we map the part1 function over the input, and sum the resulting values.

1
(list-sum (map part1 in))

7793

Part 2

We’re told the input has groups of elves, with 3 backpacks per elf. Our task is to find the item that all 3 elves in a group are carrying, compute the priority, and sum the results:

1
2
3
4
5
6
(define (part2 group)
  (~> (apply set-intersect group)
      set-first
      priority))

(part2 (list (first in) (second in) (third in)))

20

Now we just need to break the input into chunks of 3 lines, map part2 over the chunks, and sum the results:

1
2
3
(~> (chunk 3 in)
    (map part2 _)
    list-sum)

2499

Refactor

Let’s refactor using knowledge of both parts. The parts differ in how they transform the input before iterating over it:

  • Part 1 splits each line into 2 halves
  • Part 2 forms groups from successive groups of 3 lines of input

So, we’ll create a common solve function parameterized with the part logic:

1
2
3
4
5
(define (solve transform in)
  (for/sum ([ group (transform in) ])
    (~> (apply set-intersect group)
        set-first
        priority)))

Now we just need to invoke the solve function with the appropriate higher order function for each part:

1
(solve (curry map split-2) in) ; Part 1

7793

1
(solve (curry chunk 3) in)     ; Part 2

2499