On this page:
<day12>
12.1 What’s the sum of all the numbers in the document?
<day12-setup>
<day12-q1>
12.2 What’s the sum of all the numbers, if hash tables with value "red" are ignored?
<day12-q2>
12.3 Testing Day 12
<day12-test>
8.12

12 Day 12🔗ℹ

 (require aoc-racket/day12) package: aoc-racket

The puzzle. Our input is, unfortunately, a JSON file.

12.1 What’s the sum of all the numbers in the document?🔗ℹ

I’ve never liked JavaScript, and spending more time with Racket has only deepened my antipathy. So I apologize if this solution is terse.

We need to parse the JSON file, extract the numbers, and add them.

To parse the file we’ll use the read-json function from Racket’s json library. This function converts the JSON into a JS-expression (see jsexpr?), which is a recursively nested data structure. If we had a simple recursively nested list, we could just flatten it and filter for the numbers. We’ll do something similar here — recursively flatten the JS-expression and pull out the numbers.

If you’re new to Racket, notice the recursive descent pattern used in flatten-jsexpr — it’s a very common way of handling recursively structured data.

(require racket rackunit json)
(provide (all-defined-out))
 
(define (string->jsexpr str)
  (read-json (open-input-string str)))

(define (flatten-jsexpr jsexpr)
  (flatten
   (let loop ([x jsexpr])
     (cond
       [(list? x)
        (map loop x)]
       [(hash? x)
        (loop (flatten (hash->list x)))]
       [else x]))))
 
(define (q1 input-str)
  (define json-items (flatten-jsexpr (string->jsexpr input-str)))
  (apply + (filter number? json-items)))

12.2 What’s the sum of all the numbers, if hash tables with value "red" are ignored?🔗ℹ

We’ll just update our flattening function to skip over hash tables that have "red" among the values.

(define (flatten-jsexpr-2 jsexpr)
  (flatten
   (let loop ([x jsexpr])
     (cond
       [(list? x)
        (map loop x)]
       [(hash? x)
        (if (member "red" (hash-values x))
            empty
            (loop (flatten (hash->list x))))]
       [else x]))))
 
(define (q2 input-str)
  (define json-items (flatten-jsexpr-2 (string->jsexpr input-str)))
  (apply + (filter number? json-items)))

12.3 Testing Day 12🔗ℹ

(module+ test
  (define input-str (file->string "day12-input.txt"))
  (check-equal? (q1 input-str) 191164)
  (check-equal? (q2 input-str) 87842))