Overview
Comment: | Add Day 9 solution finally! |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
3893cb5af06e0157e578a2237dace188 |
User & Date: | joel on 2018-12-14 04:46:24 |
Other Links: | manifest | tags |
Context
2018-12-15
| ||
03:54 | Add Day 10 input check-in: 0f1f90 user: joel tags: trunk | |
2018-12-14
| ||
04:46 | Add Day 9 solution finally! check-in: 3893cb user: joel tags: trunk | |
2018-12-13
| ||
19:01 | Add first and second tries at Day 9 solutions β too slow! check-in: 711f70 user: joel tags: trunk | |
Changes
Added day09.rkt version [997d00].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | #lang racket (require rackunit sugar) ;; Parse the problem input (define input (map string->number (rest (regexp-match #px"(\\d+) players; last marble is worth (\\d+) points" (file->string "day09-input.txt"))))) (match-define (list input-num-players input-last-marble) input) (struct zipper (head current tail) #:transparent) ;; Zipper movement, transparently wrapping around in circular fashion (define (zipper-next z) (match-define (zipper h c t) z) (cond [(and (empty? t) (empty? h)) z] [(empty? t) (zipper (list c) (first (reverse h)) (rest (reverse h)))] [else (zipper (cons c h) (first t) (rest t))])) (define (zipper-prev z) (match-define (zipper h c t) z) (cond [(and (empty? t) (empty? h)) z] [(empty? h) (zipper (rest (reverse t)) (first (reverse t)) (list c))] [else (zipper (rest h) (first h) (cons c t))])) ;; Change the value at the cursor location (define (zipper-set z new-current) (match-define (zipper h _ t) z) (zipper h new-current t)) ;; Applies pred to the current value (define (zipper-edit z pred) (match-define (zipper h c t) z) (zipper h (pred c) t)) ;; Remove the current value and move the cursor to the next ;; item in `tail`. Returns 2 values: the resulting zipper and the ;; removed value. (define (zipper-remove z) (match-define (zipper h c t) z) (values (cond [(empty? t) (zipper '() (first (reverse h)) (rest (reverse h)))] [else (zipper h (first t) (rest t))]) c)) ;; Insert a value into the current position, pushing the ;; old current value to the left (onto the `head`) (define (zipper-insert z val) (match-define (zipper h c t) z) (cond [(empty? h) (zipper (list c) val t)] [else (zipper (cons c h) val t)])) ;; Move the zipper a given number of times using dir ;; `dir` would normally be zipper-next or zipper-prev ;; but can also be zipper-remove or any function that ;; takes a zipper as its only argument (define (move-along z dir #:times [times 1]) (cond [(zero? times) z] [else (move-along (dir z) dir #:times (sub1 times))])) (define (list->zipper lst) (zipper empty (first lst) (rest lst))) (define (zipper->list z) (match-define (zipper h c t) z) (append (reverse h) (list c) t)) ;; Now that we have zippers to play with, spell out the problemβs ;; functions with painful clarity ;; Insert a marble between the first and second marbles after the ;; current marble (define (insert-marble z marble) (zipper-insert (zipper-next z) marble)) ;; Remove the seventh marble and return `(values zipper removed-marble)` (define (remove-7th-marble z) (zipper-remove (move-along z zipper-prev #:times 7))) ;; Returns a function that will add a single number to the (define (adder marble1 marble2) (curry + (* (+ marble1 marble2) (sgn marble2)))) ;; Play the game with specified number of players and marbles. ;; Returns zippers for both the player scores and the resulting marble circle (define (play-game num-players last-marble) (for/fold ([scores (list->zipper (make-list num-players 0))] [circle (list->zipper '(0))]) ([current-marble (in-naturals 1)]) #:final (equal? current-marble last-marble) (define-values (result-circle maybe-removed-marble) (cond [(zero? (modulo current-marble 23)) (remove-7th-marble circle)] [else (values (insert-marble circle current-marble) 0)])) (define new-score (+ (zipper-current scores) (* (+ current-marble maybe-removed-marble) (sgn maybe-removed-marble)))) (values (zipper-next (zipper-set scores new-score)) result-circle))) (define (day09-part1 [players input-num-players] [last-marble input-last-marble]) (define-values (scores _) (play-game players last-marble)) (apply max (zipper->list scores))) (module+ test ;; Example inputs (check-equal? (day09-part1 10 1618) 8317) (check-equal? (day09-part1 13 7999) 146373) (check-equal? (day09-part1 17 1104) 2764) (check-equal? (day09-part1 21 6111) 54718) (check-equal? (day09-part1 30 5807) 37305) ;; Finishes in β40 msec (using `raco test`) or β120 msec (in DrRacket) (check-equal? (time (day09-part1)) 374287)) ; Correct answer for part 1 (define (day09-part2) (day09-part1 input-num-players (* 100 input-last-marble))) (module+ test ;; Finishes in β7,500 msec (using `raco test`) or β18,400 msec (in DrRacket) (check-equal? (time (day09-part2)) 3083412635)) ; Correct answer for part 2 |