|
|
|
#lang br/quicklang
|
|
|
|
|
|
|
|
(define (read-syntax path port)
|
|
|
|
(strip-bindings
|
|
|
|
#`(module mod "day04.rkt"
|
|
|
|
#,@(for*/list ([room-str (in-lines port)]
|
|
|
|
#:when (not (equal? "" room-str)))
|
|
|
|
`(room ,@(cdr (regexp-match #px"^(.*)-(\\d+)\\[(\\w+)\\]$" room-str)))))))
|
|
|
|
(module+ reader (provide read-syntax))
|
|
|
|
|
|
|
|
#|
|
|
|
|
Each room consists of an encrypted name (lowercase letters separated by dashes)
|
|
|
|
followed by a dash, a sector ID, and a checksum in square brackets.
|
|
|
|
|#
|
|
|
|
(struct $room (name sector checksum) #:transparent)
|
|
|
|
(define-macro (room NAME SECTOR CHECKSUM)
|
|
|
|
#'($room NAME (string->number SECTOR) CHECKSUM))
|
|
|
|
(provide room)
|
|
|
|
|
|
|
|
(define-macro (mb . ROOMS)
|
|
|
|
#'(#%module-begin
|
|
|
|
(define rooms (list . ROOMS))
|
|
|
|
(display "part a: ")
|
|
|
|
(displayln (for/sum ([room (in-list rooms)]
|
|
|
|
#:when (real-room? room))
|
|
|
|
($room-sector room)))
|
|
|
|
(display "part b: ")
|
|
|
|
(displayln
|
|
|
|
(for/first ([room (in-list rooms)]
|
|
|
|
#:when (equal? (shift-string ($room-name room) ($room-sector room))
|
|
|
|
"northpole object storage"))
|
|
|
|
($room-sector room)))))
|
|
|
|
(provide (rename-out [mb #%module-begin]))
|
|
|
|
|
|
|
|
#|
|
|
|
|
A room is real (not a decoy) if the checksum is
|
|
|
|
the five most common letters in the encrypted name, in order,
|
|
|
|
with ties broken by alphabetization.
|
|
|
|
|#
|
|
|
|
|
|
|
|
(require sugar/list)
|
|
|
|
(define (real-room? room)
|
|
|
|
(define room-chars (string->list (string-replace ($room-name room) "-" "")))
|
|
|
|
(define freqs (hash->list (frequency-hash room-chars)))
|
|
|
|
(define sorted-freqs (sort (sort freqs char<? #:key car) > #:key cdr))
|
|
|
|
(equal? ($room-checksum room) (list->string (map car (take sorted-freqs 5)))))
|
|
|
|
|
|
|
|
(define (shift-string str shift)
|
|
|
|
(list->string
|
|
|
|
(for/list ([c (in-string str)])
|
|
|
|
(cond
|
|
|
|
[(char=? c #\-) #\space]
|
|
|
|
[else
|
|
|
|
(define a-val (char->integer #\a))
|
|
|
|
(integer->char (+ (modulo (+ (char->integer c) (- a-val) shift) 26) a-val))]))))
|