advent-of-code

Perserverance, or the lack thereof

git clone git://git.shimmy1996.com/advent-of-code.git

day14.scm (5391B)

    1 (use-modules (ice-9 popen))
    2 (use-modules (ice-9 rdelim))
    3 (use-modules (ice-9 format))
    4 (use-modules (ice-9 hash-table))
    5 (use-modules (ice-9 receive))
    6 (use-modules (srfi srfi-1))
    7 
    8 (define (parse-input filename)
    9   (let ((file (open-input-file filename))
   10         (platform '()))
   11     (while #t
   12            (let ((line (car (%read-line file))))
   13              (if (eof-object? line)
   14                  (break)
   15                  (set! platform (cons (string->list line) platform)))))
   16     (reverse platform)))
   17 
   18 (define (array-to-dict platform)
   19   (let ((platform-dict (make-hash-table))
   20         (y-max (1- (length platform)))
   21         (x-max (1- (length (car platform)))))
   22     (do ((y 0 (1+ y))) ((> y y-max))
   23       (do ((x 0 (1+ x))) ((> x x-max))
   24         (hash-set! platform-dict
   25                    (cons x y)
   26                    (list-ref (list-ref platform y) x))))
   27     (values platform-dict x-max y-max)))
   28 
   29 (define (display-platform platform-dict x-max y-max)
   30   (do ((y 0 (1+ y))) ((> y y-max))
   31     (do ((x 0 (1+ x))) ((> x x-max))
   32       (display (hash-ref platform-dict (cons x y))))
   33     (newline)))
   34 
   35 (define (between x a b)
   36   (and (>= x a) (<= x b)))
   37 
   38 (define (swap-vals dict a b)
   39   (let ((val-a (hash-ref dict a))
   40         (val-b (hash-ref dict b)))
   41     (hash-set! dict a val-b)
   42     (hash-set! dict b val-a)))
   43 
   44 (define (move-rock platform-dict x-max y-max dx dy x y)
   45   (let ((curr-x x)
   46         (curr-y y))
   47     ;; (display (cons x y)) (newline)
   48     (while #t
   49            (let ((next-x (+ curr-x dx))
   50                  (next-y (+ curr-y dy)))
   51              ;; (display (list "checking" (cons next-x next-y) (hash-ref platform-dict (cons next-x next-y)))) (newline)
   52              (case (hash-ref platform-dict (cons next-x next-y))
   53                ((#f) (break))
   54                ((#\#) (break))
   55                ((#\O) (break)))
   56              ;; (display (list "passed" (cons next-x next-y))) (newline)
   57              (set! curr-x next-x)
   58              (set! curr-y next-y)))
   59     ;; (display (list "moving rock from" (cons x y) "to" (cons curr-x curr-y))) (newline)
   60     (swap-vals platform-dict (cons x y) (cons curr-x curr-y))))
   61 
   62 (define (tilt-platform platform-dict x-max y-max dx dy)
   63   (if (and (= dx 0) (= dy -1))
   64       (do ((y 0 (1+ y))) ((> y y-max))
   65         (do ((x 0 (1+ x))) ((> x x-max))
   66           (if (equal? (hash-ref platform-dict (cons x y)) #\O)
   67               (move-rock platform-dict x-max y-max dx dy x y)))))
   68   (if (and (= dx 0) (= dy 1))
   69       (do ((y y-max (1- y))) ((< y 0))
   70         (do ((x 0 (1+ x))) ((> x x-max))
   71           (if (equal? (hash-ref platform-dict (cons x y)) #\O)
   72               (move-rock platform-dict x-max y-max dx dy x y)))))
   73   (if (and (= dx -1) (= dy 0))
   74       (do ((x 0 (1+ x))) ((> x x-max))
   75         (do ((y 0 (1+ y))) ((> y y-max))
   76           (if (equal? (hash-ref platform-dict (cons x y)) #\O)
   77               (move-rock platform-dict x-max y-max dx dy x y)))))
   78   (if (and (= dx 1) (= dy 0))
   79       (do ((x x-max (1- x))) ((< x 0))
   80         (do ((y 0 (1+ y))) ((> y y-max))
   81           (if (equal? (hash-ref platform-dict (cons x y)) #\O)
   82               (move-rock platform-dict x-max y-max dx dy x y)))))
   83   platform-dict)
   84 
   85 (define (compute-load platform-dict x-max y-max)
   86   (let ((load 0))
   87     (do ((y 0 (1+ y))) ((> y y-max))
   88         (do ((x 0 (1+ x))) ((> x x-max))
   89           (if (equal? (hash-ref platform-dict (cons x y)) #\O)
   90               (set! load (+ load (- (1+ y-max) y))))))
   91     load))
   92 
   93 (receive (platform-dict x-max y-max) (array-to-dict (parse-input "input.txt"))
   94   (tilt-platform platform-dict x-max y-max 0 -1)
   95   ;; 110565
   96   (format #t "Part 1: ~d" (compute-load platform-dict x-max y-max))
   97   (newline))
   98 
   99 (receive (platform-dict x-max y-max) (array-to-dict (parse-input "input.txt"))
  100   ;; Load pattern repeats after 102th cycle (89803) every 42 cycles. However the
  101   ;; repeating pattern contains duplicated entries, so can't use tortois-hare to
  102   ;; automate this.
  103   (let ((hist-load (make-hash-table))
  104         (cycle 0)
  105         (max-cycle 1000000000)
  106         (period #nil)
  107         (period-start #nil))
  108     ;; I see - here's what you do, for every repeat, check backwards to see if
  109     ;; (last-repeat, curr-repeat] is the same as (last-repeat - diff,
  110     ;; last-repeat]. If so we have a cycle - this should work as long as there's
  111     ;; at least one non-repeating element in the cycle.
  112     (while #t
  113            (tilt-platform platform-dict x-max y-max 0 -1)
  114            (tilt-platform platform-dict x-max y-max -1 0)
  115            (tilt-platform platform-dict x-max y-max 0 1)
  116            (tilt-platform platform-dict x-max y-max 1 0)
  117            (set! cycle (1+ cycle))
  118            (let ((curr-load (compute-load platform-dict x-max y-max)))
  119              (if (and (hash-ref hist-load curr-load)
  120                       ;; hack
  121                       (= curr-load 89803))
  122                  (begin
  123                    (set! period-start (hash-ref hist-load curr-load))
  124                    (set! period (- cycle period-start))
  125                    (break)))
  126              (hash-set! hist-load curr-load cycle))
  127            (if (>= cycle max-cycle)
  128                (break)))
  129     (let ((terminal-cycle (+ period-start (floor-remainder (- max-cycle period-start) period)))
  130           (terminal-load #nil))
  131       (hash-for-each (lambda (k v) (if (= v terminal-cycle) (set! terminal-load k))) hist-load)
  132       ;; 89845
  133       (format #t "Part 2: ~d" terminal-load)
  134       (newline))))