diff --git a/lib.rkt b/lib.rkt index a0069f3..c9baad6 100644 --- a/lib.rkt +++ b/lib.rkt @@ -10,59 +10,11 @@ read-file)) (provide (all-from-out threading) - - problem-input - problem-input-all - problem-input-grouped - show-solution - - make-vector-grid - vector-grid-update - lists->vectors - vectors->lists - lists->hash - hash->vectors - show-list-grid - show-vector-grid - show-hash-grid - - ∘ ∂ ∂r $ % - uncurry - - string->number* - string->symbol* - - nchar=? - char-alphanumeric? - - sum - != - nzero? - negate - pos-or-zero - number->digits - number->digits-reverse - digits->number - string->binary - - snoc - scanl scanr - list-ref* - repeat - chunks-of - transpose - list->queue - - vector-first - vector-last - vector-ref* - vector-grid-ref* - vector-set!* - hash->vector - vector->hash) + (all-defined-out)) ;; Function helpers ;; + (define ∘ compose) (define ∂ curry) (define ∂r curryr) @@ -103,18 +55,35 @@ ;; Grid helpers ;; ;; A grid of values might be stored in three different ways: -;; - As a hashtable from positions (number . number) to values; or +;; - As a hashtable from coordinates (list x y) to values; or ;; - As a vector of vectors of values; or ;; - As a list of lists of values. +;; coord = (list? number? number?) +;; Coordinate axes point right (x-axis) and down (y-axis). ;; make-vector-grid : number -> number -> number -> vector-grid (define (make-vector-grid width height [default 0]) (build-vector height (λ (_) (make-vector width default)))) -;; vector-grid-update : vector-grid -> (number . number) -> a -> void +;; vector-grid-update : vector-grid -> coord -> a -> void ;; Set the vector grid to given value at position (row, col) -(define (vector-grid-update vector-grid pos value) - (vector-set! (vector-ref vector-grid (car pos)) (cdr pos) value)) +(define (vector-grid-update vector-grid coord value) + (vector-set! (vector-ref vector-grid (second coord)) (first coord) value)) + +;; vector-grid-ref* : (vectorof (vectorof any)) -> coord -> any -> any +;; Given coordinates (x, y), in the yth vector, find the xth element. +;; If either x or y are beyond the indices of the vectors, +;; return the default value provided. +(define (vector-grid-ref* grid coord failure-result) + (match-let ([(list x y) coord] + [y-len (vector-length grid)]) + (if (or (< y 0) (>= y y-len)) + failure-result + (let* ([row (vector-ref grid y)] + [x-len (vector-length row)]) + (if (or (< x 0) (>= x x-len)) + failure-result + (vector-ref row x)))))) ;; lists->vectors : list-grid -> vector-grid (define (lists->vectors list-grid) @@ -131,24 +100,24 @@ (for*/fold ([hash-grid (hash)]) ([x (in-range width)] [y (in-range length)]) - (hash-set hash-grid (cons x y) (list-ref (list-ref list-grid y) x))))) + (hash-set hash-grid (list x y) (list-ref (list-ref list-grid y) x))))) ;; hash->vectors : hash-grid -> number -> vector-grid -;; Where the position is not in the hash-grid, +;; When a coordinate is not in the hash-grid, ;; the vector-grid takes on the default value. (define (hash->vectors hash-grid [default 0]) (let* ([keys (hash-keys hash-grid)] - [xs (map car keys)] - [ys (map cdr keys)] + [xs (map first keys)] + [ys (map second keys)] [min-x (apply min xs)] [min-y (apply min ys)] [width (add1 (- (apply max xs) min-x))] [height (add1 (- (apply max ys) min-y))] [vector-grid (make-vector-grid width height default)]) (hash-for-each - hash-grid (λ (pos val) - (let ([x (- (car pos) min-x)] - [y (- (cdr pos) min-y)]) + hash-grid (λ (coord val) + (let ([x (- (first coord) min-x)] + [y (- (second coord) min-y)]) (vector-set! (vector-ref vector-grid y) x val)))) vector-grid)) @@ -169,7 +138,7 @@ (show-vector-grid char-hash (hash->vectors hash-grid default))) -;; Conversion helpers ;; +;; String helpers ;; ;; string->number* : (or/c string? #f) -> (or/c number? #f) (define (string->number* s) @@ -179,6 +148,23 @@ (define (string->symbol* s) (and (string? s) (string->symbol s))) +;; string->binary : string? -> number? +;; Given a string representation of a binary number, +;; convert it to the number it represents +(define (string->binary str) + (string->number (string-append "#b" str))) + +;; string-replaces : string? -> (listof (list? string? string?)) -> string +;; Perform string replacements in order, +;; so that later replacments may affect earlier ones +(define (string-replaces str replaces) + (if (empty? replaces) + str + (string-replaces (string-replace str + (caar replaces) + (cadar replaces)) + (rest replaces)))) + ;; Char helpers ;; @@ -236,12 +222,6 @@ (if (empty? ns) n (loop (+ (* n 10) (car ns)) (cdr ns))))) -;; string->binary : string -> number -;; Given a string representation of a binary number, -;; convert it to the number it represents -(define (string->binary str) - (string->number (string-append "#b" str))) - ;; List helpers ;; @@ -327,21 +307,6 @@ failure-result (vector-ref vec pos))) -;; vector-grid-ref* : (vectorof (vectorof any)) -> (list number number) -> any -> any -;; Given coordinates (x, y), in the yth vector, find the xth element. -;; If either x or y are beyond the indices of the vectors, -;; return the default value provided. -(define (vector-grid-ref* grid coord failure-result) - (match-let ([(list x y) coord] - [y-len (vector-length grid)]) - (if (or (< y 0) (>= y y-len)) - failure-result - (let* ([row (vector-ref grid y)] - [x-len (vector-length row)]) - (if (or (< x 0) (>= x x-len)) - failure-result - (vector-ref row x)))))) - ;; vector-set!* : (vectorof any) -> number -> any -> (vectorof any) ;; Set the value at given index in a new vector, then return that vector ;; If the index is beyond the indices of the vector, @@ -363,4 +328,4 @@ ;; Convert a vector into an immutable intmap (define (vector->hash vec) (let ([kvs (map cons (range (vector-length vec)) (vector->list vec))]) - (make-immutable-hash kvs))) \ No newline at end of file + (make-immutable-hash kvs))) diff --git a/src/11.rkt b/src/11.rkt index 6bf5d6e..877a1b3 100644 --- a/src/11.rkt +++ b/src/11.rkt @@ -1,7 +1,6 @@ #lang curly-fn racket -(require threading - "../lib.rkt") +(require "../lib.rkt") (define input (lists->vectors (map string->list (problem-input 11)))) (define width (vector-length (vector-ref input 0))) diff --git a/src/12.rkt b/src/12.rkt index 0f1825b..6617f97 100644 --- a/src/12.rkt +++ b/src/12.rkt @@ -21,21 +21,17 @@ [`(,_ 180) (values x y (- dx) (- dy))])) (define part1 - (match-let-values - ([(x y dx dy) - (for/fold ([x 0] [y 0] - [dx 1] [dy 0]) - ([instr input]) - (move instr 1 0 x y dx dy))]) - (+ (abs x) (abs y)))) + (for/fold ([x 0] [y 0] + [dx 1] [dy 0] + #:result (+ (abs x) (abs y))) + ([instr input]) + (move instr 1 0 x y dx dy))) (define part2 - (match-let-values - ([(x-ship y-ship x-wpt y-wpt) - (for/fold ([x-ship 0] [y-ship 0] - [x-wpt 10] [y-wpt -1]) - ([instr input]) - (move instr 0 1 x-ship y-ship x-wpt y-wpt))]) - (+ (abs x-ship) (abs y-ship)))) + (for/fold ([x-ship 0] [y-ship 0] + [x-wpt 10] [y-wpt -1] + #:result (+ (abs x-ship) (abs y-ship))) + ([instr input]) + (move instr 0 1 x-ship y-ship x-wpt y-wpt))) (show-solution part1 part2) diff --git a/src/14.rkt b/src/14.rkt index 4df423c..1bc7b15 100644 --- a/src/14.rkt +++ b/src/14.rkt @@ -17,9 +17,9 @@ (match instr [(regexp #px"^mask = (\\w+)$" (list _ mask)) (let* ([ormask (string->binary (string-replace mask "X" "0"))] - [andmask (string->binary (regexp-replaces mask '([#rx"0" "1"] [#rx"X" "0"])))] + [andmask (string->binary (string-replaces mask '(["0" "1"] ["X" "0"])))] [X-indices (indexes-of (string->list mask) #\X)] - [X-ormasks (map #{expt 2 (sub1 (- (string-length mask) %))} X-indices)]) + [X-ormasks (map #{expt 2 (- (sub1 (string-length mask)) %)} X-indices)]) (list 'mask ormask andmask X-ormasks))] [(regexp #px"^mem\\[(\\d+)\\] = (\\d+)" (list _ addr val)) (list 'write (string->number addr) (string->number val))])) @@ -32,35 +32,31 @@ rest-addrs)))) (define part1 - (match-let-values - ([(mem _ _) - (for/fold ([mem (hash)] - [ormask 0] - [andmask -1]) - ([instr (map parse1 input)]) - (match instr - [(list 'mask ormask andmask) - (values mem ormask andmask)] - [(list 'write addr val) - (let ([val (bitwise-ior ormask (bitwise-and andmask val))]) - (values (hash-set mem addr val) ormask andmask))]))]) - (sum (hash-values mem)))) + (for/fold ([mem (hash)] + [ormask 0] + [andmask -1] + #:result (sum (hash-values mem))) + ([instr (sequence-map parse1 input)]) + (match instr + [(list 'mask ormask andmask) + (values mem ormask andmask)] + [(list 'write addr val) + (let ([val (bitwise-ior ormask (bitwise-and andmask val))]) + (values (hash-set mem addr val) ormask andmask))]))) (define part2 - (match-let-values - ([(mem _ _ _) - (for/fold ([mem (hash)] - [ormask 0] - [andmask -1] - [X-ormasks '()]) - ([instr (map parse2 input)]) - (match instr - [(list 'mask ormask andmask X-ormasks) - (values mem ormask andmask X-ormasks)] - [(list 'write addr val) - (let* ([addr (bitwise-ior ormask (bitwise-and andmask addr))] - [mem (foldl #{hash-set %2 %1 val} mem (addrs addr X-ormasks))]) - (values mem ormask andmask X-ormasks))]))]) - (sum (hash-values mem)))) + (for/fold ([mem (hash)] + [ormask 0] + [andmask -1] + [X-ormasks '()] + #:result (sum (hash-values mem))) + ([instr (sequence-map parse2 input)]) + (match instr + [(list 'mask ormask andmask X-ormasks) + (values mem ormask andmask X-ormasks)] + [(list 'write addr val) + (let* ([addr (bitwise-ior ormask (bitwise-and andmask addr))] + [mem (foldl #{hash-set %2 %1 val} mem (addrs addr X-ormasks))]) + (values mem ormask andmask X-ormasks))]))) (show-solution part1 part2)