advent-of-code

Perserverance, or the lack thereof

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

day08.scm (3287B)

    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 (ice-9 regex))
    7 (use-modules (srfi srfi-1))
    8 
    9 (define (parse-input filename)
   10   (let ((file (open-input-file filename))
   11         (instructions '())
   12         (left-map (make-hash-table))
   13         (right-map (make-hash-table)))
   14     (let ((line (car (%read-line file))))
   15       (set! instructions (string->list line)))
   16     (%read-line file)
   17     (while #t
   18            (let ((line (car (%read-line file))))
   19              (if (eof-object? line)
   20                  (break)
   21                  (let* ((tmp (string-split (regexp-substitute #f (string-match "([A-Z]{3}) = \\(([A-Z]{3}), ([A-Z]{3})\\)" line) 1 " " 2 " " 3) #\ ))
   22                         (curr (car tmp))
   23                         (left (list-ref tmp 1))
   24                         (right (list-ref tmp 2)))
   25                    (hash-set! left-map curr left)
   26                    (hash-set! right-map curr right)))))
   27     (values instructions left-map right-map)))
   28 
   29 (define (is-zzz start step-count)
   30   (equal? start "ZZZ"))
   31 
   32 (define (count-step instructions left-map right-map start end-checker step-count)
   33   (if (end-checker start step-count)
   34       (cons step-count start)
   35       (let* ((curr-dir (list-ref instructions (floor-remainder step-count (length instructions))))
   36              (next-start (cond ((eq? curr-dir #\L) (hash-ref left-map start))
   37                                ((eq? curr-dir #\R) (hash-ref right-map start))
   38                                (#t #nil)))
   39              (next-step-count (1+ step-count)))
   40         (count-step instructions left-map right-map next-start end-checker next-step-count))))
   41 
   42 (receive (instructions left-map right-map) (parse-input "input.txt")
   43   ;; 11309
   44   (format #t "Part 1: ~d" (car (count-step instructions left-map right-map "AAA" is-zzz 0)))
   45   (newline))
   46 
   47 (define (is-any-z start step-count)
   48   (and (> step-count 0) (equal? (string-ref start 2) #\Z)))
   49 
   50 (define (check-z-cycle instructions left-map right-map start)
   51   (let* ((tmp (count-step instructions left-map right-map start is-any-z 0))
   52          (tmp2 (count-step instructions left-map right-map start is-any-z 0)))
   53     (if (and (= 0 (floor-remainder (car tmp) (length instructions)))
   54              (= 0 (floor-remainder (car tmp) (length instructions)))
   55              (= (car tmp) (car tmp2)))
   56         (car tmp)
   57         #nil)))
   58 
   59 (define (solve-extended-eculidean a b)
   60   (let ((r_prev a)
   61         (r_curr b))
   62     (while (> r_curr 0)
   63            (receive (q_curr r_next) (euclidean/ r_prev r_curr)
   64                    (set! r_prev r_curr)
   65                    (set! r_curr r_next)))
   66     r_prev))
   67 
   68 (define (find-lcm a b)
   69   (let ((gcd (solve-extended-eculidean a b)))
   70     (/ (* a b) gcd)))
   71 
   72 (receive (instructions left-map right-map) (parse-input "input.txt")
   73   ;; turned out all xxA->xxZ at full cycles of the instructions and xxZ->xxZ the
   74   ;; same, so we can freely add cycles after.
   75   (let* ((starts (filter (lambda (x) (equal? (string-ref x 2) #\A)) (hash-map->list (lambda (k v) k) left-map)))
   76          (cycle-spec (map (lambda (x) (check-z-cycle instructions left-map right-map x)) starts)))
   77     ;; 13740108158591
   78     (format #t "Part 2: ~d" (reduce find-lcm #nil cycle-spec))
   79     (newline)))