You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
aoc-racket/2018/09.rkt

59 lines
2.0 KiB
Racket

#lang debug br
(require racket/file)
#|
This puzzle seemed annoying at first but turned out to be educational.
An epic difference between the naive solution (= make a list and iterate from the start)
and using a double-linked list, which minimizes traversal.
|#
(struct dll (val prev next) #:mutable)
(define (move-by dll n)
(define iterator
(match n
[(? positive?) dll-next]
[(? negative?) dll-prev]
[_ values]))
(for/fold ([dll dll])
([i (in-range (abs n))])
(iterator dll)))
(define (remove-marble! marble)
(set-dll-next! (dll-prev marble) (dll-next marble))
(set-dll-prev! (dll-next marble) (dll-prev marble)))
(define (find-winner player-count max-marbles)
(define scores (make-hasheqv))
(define first-marble (dll 0 #f #f))
(set-dll-prev! first-marble first-marble)
(set-dll-next! first-marble first-marble)
(for/fold ([current-marble first-marble]
#:result (cdr (argmax cdr (hash->list scores))))
([marble (in-range 1 max-marbles)])
(cond
[(zero? (modulo marble 23))
(define marble-to-remove (move-by current-marble -7))
(remove-marble! marble-to-remove)
(define player (modulo marble player-count))
(hash-update! scores player (λ (sc) (+ (dll-val marble-to-remove) marble sc)) 0)
(dll-next marble-to-remove)]
[else
(define left-marble (move-by current-marble 1))
(define right-marble (dll-next left-marble))
(define new-marble (dll marble left-marble right-marble))
(set-dll-next! left-marble new-marble)
(set-dll-prev! right-marble new-marble)
new-marble])))
(match-define (list player-count max-marbles)
(map string->number (regexp-match* #px"\\d+" (file->string "09.txt"))))
(define () (find-winner player-count max-marbles))
(define (★★) (find-winner player-count (* 100 max-marbles)))
(module+ test
(require rackunit)
(check-equal? (time ()) 437654)
(check-equal? (time (★★)) 3689913905))