Overview
| Comment: | Add Day 5 solutions (and false starts) |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
c07d620ac0557a32d88774252beef030 |
| User & Date: | joel on 2018-12-06 04:02:31 |
| Other Links: | manifest | tags |
Context
|
2018-12-07
| ||
| 17:09 | Add Day 6 input check-in: b4b3f5 user: joel tags: trunk | |
|
2018-12-06
| ||
| 04:02 | Add Day 5 solutions (and false starts) check-in: c07d62 user: joel tags: trunk | |
|
2018-12-05
| ||
| 19:21 | Add Day 5 input check-in: c5988d user: joel tags: trunk | |
Changes
Added day05-try1.rkt version [5ccb76].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
#lang racket
(require rackunit)
(define input (string-trim (file->string "day05-input.txt")))
(define (ascii-vector str)
(list->vector (map char->integer (string->list str))))
(define input-vec (ascii-vector input))
(define (ascii-at-pos str i)
(char->integer (list-ref (string->list str) i)))
;; The ASCII values of characters of alternating case ("aA" or "Gg") will always differ by 32
;; Return the first such occurrence or "" if none exists
(define (first-alternating-case str)
(or
(for/first ([i (in-range (sub1 (string-length str)))]
#:when (= 32 (abs (- (ascii-at-pos str i)
(ascii-at-pos str (add1 i))))))
(substring str i (+ i 2)))
""))
;; Eliminate the first pair of characters that differ only in case
(define (next-transformation str)
(or (string-replace str (first-alternating-case str) "") str))
;; Vector versions
(define (next-nonzero vec i)
(or
(for/first ([n (in-range (min (add1 i) (vector-length vec)) (vector-length vec))]
#:when (positive? (vector-ref vec n)))
n)
i))
(define (vec-first-alternating-case vec)
(or
(for/first ([i (in-range (vector-length vec))]
#:when (and (positive? (vector-ref vec i))
(= 32 (abs (- (vector-ref vec i)
(vector-ref vec (next-nonzero vec i)))))))
(list i (next-nonzero vec i)))
'()))
(define (vec-next-transform! vec)
(define next-pair (vec-first-alternating-case vec))
(cond
[(not (empty? next-pair))
(for ([i (in-list next-pair)])
(vector-set! vec i 0))
#t]
[else #f]))
;; Keep transforming as above until there's nothing left to do
(define (boil str)
(for/fold ([last-state ""]
[current-state str]
#:result current-state)
([x (in-naturals)]
#:break (string=? current-state last-state))
(values current-state (next-transformation current-state))))
;; Let's see if vectors are faster
(define (vector-boil vec)
(do ([xformed? (vec-next-transform! vec) (vec-next-transform! vec)])
[(not xformed?)] ))
;; I ran this function and started eating a bowl of chili.
;; When I was done with the chili it hadn't completed yet.
(define (day01-part1-try1)
(string-length (boil input)))
(define (ascii-vector->string vec)
(list->string (map integer->char (vector->list (vector-filter positive? vec)))))
(define (day01-part1-try2)
(vector-boil input-vec)
(vector-length (vector-filter positive? input-vec)))
(module+ test
(check-equal? (boil "dabAcCaCBAcCcaDA") "dabCBAcaDA")
;; Takes about 64sec on my laptop
(check-equal? (time (day01-part1-try2)) 10584)) ; Correct answer for part one
|
Added day05.rkt version [c264ac].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#lang racket
(require rackunit sugar/debug)
;; For efficiency and convenience, I'll be dealing with inputs as ASCII values.
(define (ascii-list str)
(map char->integer (string->list str)))
(define input (ascii-list (string-trim (file->string "day05-input.txt"))))
;; Treating lst as a stack, push an ASCII value on top.
;; If the new value is the same letter as the current top value
;; but differs by upper/lower case, eliminate both values.
(define (push-and-react lst val)
(cond
[(empty? lst) (list val)]
[(= 32 (abs (- (car lst) val))) (rest lst)]
[else (cons val lst)]))
;; Return a fully "reacted" version of the input list.
;; Reverses the list in the process, but the order of the finished
;; list does not matter for the solution, only the length.
(define (boil lst)
(for/fold ([output '()])
([v (in-list lst)])
(push-and-react output v)))
;; There it is: computes in 6msec!
(define (day05-part1)
(length (boil input)))
(module+ test
(define example-input (ascii-list "dabAcCaCBAcCcaDA"))
(check-equal? (length (boil example-input)) 10)
(check-equal? (day05-part1) 10584)) ; Correct answer for part one
;; Given a list and the ASCII value of an uppercase letter, first removes
;; all occurrences of that letter (both upper- and lower-case) then
;; boils the resulting list as above.
(define (remove-and-boil lst uc-asciival)
(define (keeper? a)
(not (member a (list uc-asciival (+ 32 uc-asciival)))))
(boil (filter keeper? lst)))
;; For each letter of the alphabet, create a copy of input that first removes that
;; letter, then boils the list. Find the shortest such list.
;; Computes in about 550msec
(define (day05-part2)
(define uc-letters (range 65 91))
(define boiler (curry remove-and-boil input))
(define boiled (map boiler uc-letters))
(apply min (report (map length boiled))))
(module+ test
(check-equal? (day05-part2) 6968))
;; This next has nothing to do with the solution; I was just curious which is the most
;; common letter in the original input, and if it was the removal of that letter
;; which yields the shortest boiled list. As it turns out: no.
(define (most-frequent-letter)
(define (count-letter lst a)
(count (lambda(c) (member c (list a (+ a 32)))) lst))
(define letter-counts
(map (curry count-letter input) (range 65 91)))
(integer->char (+ 65 (index-of (report letter-counts) (apply max letter-counts)))))
|