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>
7.7

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))