Advent of Code 2022
/ 5 min read
Table of Contents
This year I decided to solve Advent of Code in Racket. I’ve seen lots of people gush over how much they love Lisp, so I want to see what it’s all about. The functional paradigm isn’t completely foreign to me as I’ve written a few web apps in Elm and I’ve messed around with Haskell, but I’ve never used a Lisp for anything complex.
Day 1 - Calorie Counting
Part 1
; Sum integers from stdin until a blank line (or EOF) is encountered(define (sum-input-integers-until-break line) (cond [(non-empty-string? line) (+ (string->number line) (sum-input-integers-until-break (read-line)))] [else 0]))
; Get a list of calories from stdin, stopping when EOF is encountered(define (get-calorie-list) (let ([line (read-line)]) (cond [(eof-object? line) '()] [else (cons (sum-input-integers-until-break line) (get-calorie-list))])))
; Get the maximum calories(apply max (get-calorie-list))
Part 2
Part 2 is almost identical. The only difference is that we sum the top three calorie counts instead of just taking the maximum.
; Sum integers from stdin until a blank line (or EOF) is encountered(define (sum-input-integers-until-break line) (cond [(non-empty-string? line) (+ (string->number line) (sum-input-integers-until-break (read-line)))] [else 0]))
; Get a list of calories from stdin, stopping when EOF is encountered(define (get-calorie-list) (let ([line (read-line)]) (cond [(eof-object? line) '()] [else (cons (sum-input-integers-until-break line) (get-calorie-list))])))
; Sum a list of numbers(define (sum nums) (apply + nums))
; Get the top N largest numbers(define (largest-nums nums n) (take (sort nums >) n))
; Sum the top three largest calorie counts(sum (largest-nums (get-calorie-list) 3))
Day 2 - Rock Paper Scissors
Part 1
(require racket/string)
;; PARSING
(define (parse-choice c) (cond [(or (equal? c "A") (equal? c "X")) 0] ; Rock -> 0 [(or (equal? c "B") (equal? c "Y")) 1] ; Paper -> 1 [(or (equal? c "C") (equal? c "Z")) 2] ; Scissors -> 2 [else -1]))
; Example: "B X" -> '(1 0)(define (parse-strategy-line line) (map parse-choice (string-split line)))
;; IO
(define (read-all-lines) (let ([line (read-line)]) (if (string? line) (cons line (read-all-lines)) '())))
(define (read-strategies) (map parse-strategy-line (read-all-lines)))
;; SCORING
; The winning choice can be calculated by just adding 1 and modulo'ing by 3; 0 (Rock) is beat by 1 (Paper); 1 (Paper) is beat by 2 (Scissors); 2 (Scissors) is beat by 0 (Rock)(define (winning-choice n) (modulo (+ n 1) 3))
; Since rock gets 1 point, paper gets 2, and scissors gets 3, we can just; add one to our numeric representation of the choices(define (score-choice n) (+ n 1))
(define (score-outcome other you) (cond ((= you (winning-choice other)) 6) ; 6 points for winning ((= you other) 3) ; 3 points for drawing (else 0))) ; No points for losing
(define (score-round other you) (+ (score-choice you) (score-outcome other you)))
(define (score-rounds rounds) (map (lambda (r) (apply score-round r)) rounds))
;; MAIN
(define (sum nums) (apply + nums))
(sum (score-rounds (read-strategies)))
Part 2
(require racket/string)
;; LOGIC
; The winning choice can be calculated by just adding 1 and modulo'ing by 3; 0 (Rock) is beat by 1 (Paper); 1 (Paper) is beat by 2 (Scissors); 2 (Scissors) is beat by 0 (Rock)(define (winning-choice n) (modulo (+ n 1) 3))
; Likewise, the losing choice can be calculated by adding 2 and modulo'ing by 3; 0 (Rock) beats 2 (Scissors); 1 (Paper) beats 0 (Rock); 2 (Scissors) beats 1 (Paper)(define (losing-choice n) (modulo (+ n 2) 3))
;; PARSING
(define (parse-choice c) (cond [(equal? c "A") 0] ; Rock -> 0 [(equal? c "B") 1] ; Paper -> 1 [(equal? c "C") 2] ; Scissors -> 2 [else -1]))
(define (parse-outcome other outcome) (list other (cond [(equal? outcome "X") (losing-choice other)] ; Lose [(equal? outcome "Y") other] ; Draw [(equal? outcome "Z") (winning-choice other)] ; Win [else -1])))
(define (parse-strategy-line line) (let ([fields (string-split line)]) (parse-outcome (parse-choice (list-ref fields 0)) (list-ref fields 1))))
;; IO
(define (read-all-lines) (let ([line (read-line)]) (if (string? line) (cons line (read-all-lines)) '())))
(define (read-strategies) (map parse-strategy-line (read-all-lines)))
; Since rock gets 1 point, paper gets 2, and scissors gets 3, we can just; add one to our numeric representation of the choices(define (score-choice n) (+ n 1))
(define (score-outcome other you) (cond ((= you (winning-choice other)) 6) ; 6 points for winning ((= you other) 3) ; 3 points for drawing (else 0))) ; No points for losing
(define (score-round other you) (+ (score-choice you) (score-outcome other you)))
(define (score-rounds rounds) (map (lambda (r) (apply score-round r)) rounds))
;; MAIN
(define (sum nums) (apply + nums))
(sum (score-rounds (read-strategies)))
Day 3 - Get Organized
Part 1
(require racket/set)
;; IO(define (get-input-lines) (let ([line (read-line)]) (if (string? line) (cons line (get-input-lines)) '())))
;; DUPLICATE FINDING(define (split-string-in-half s) (let ([half-index (/ (string-length s) 2)]) (list (substring s 0 half-index) (substring s half-index))))
(define (chars-in-both-strings a b) (set-intersect (string->list a) (string->list b)))
(define (find-duplicate-in-rucksack s) (apply chars-in-both-strings (split-string-in-half s)))
;; PRIORITY(define (item-priority c) (let ([i (char->integer c)]) (if (< i (char->integer #\a)) (+ (- i (char->integer #\A)) 27) (+ (- i (char->integer #\a)) 1))))
(define (rucksack-priority s) (item-priority (car (find-duplicate-in-rucksack s))))
;; MAIN(apply + (map rucksack-priority (get-input-lines)))
Part 2
(require racket/set)
;; IO(define (get-input-lines) (let ([line (read-line)]) (if (string? line) (cons line (get-input-lines)) '())))
;; GROUPING(define (into-groups elves) (if (not (empty? elves)) (cons (take elves 3) (into-groups (drop elves 3))) '()))
(define (duplicate-char-in-strings strs) (car (apply set-intersect (map string->list strs))))
;; PRIORITY(define (item-priority c) (let ([i (char->integer c)]) (if (< i (char->integer #\a)) (+ (- i (char->integer #\A)) 27) (+ (- i (char->integer #\a)) 1))))
(define (group-priority g) (item-priority (duplicate-char-in-strings g)))
;; MAIN(apply + (map group-priority (into-groups (get-input-lines))))