123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- (import
- (except (rnrs base) let-values map error)
- (only (guile)
- lambda* λ
- current-output-port)
- (fileio)
- (list-helpers)
- (srfi srfi-1)
- ;; let-values
- (srfi srfi-11)
- ;; hash tables
- (srfi srfi-69)
- (ice-9 pretty-print))
- (define array-len-in-dim
- (λ (arr dim)
- (let* ([shape (array-shape arr)]
- [dim-min-max (list-ref shape dim)])
- (+ (- (second dim-min-max)
- (first dim-min-max))
- 1))))
- (define distances
- (list->array
- 2
- '(((-2 . -2) (-2 . -1) (-2 . 0) (-2 . 1) (-2 . 2))
- ((-1 . -2) (-1 . -1) (-1 . 0) (-1 . 1) (-1 . 2))
- (( 0 . -2) ( 0 . -1) ( 0 . 0) ( 0 . 1) ( 0 . 2))
- (( 1 . -2) ( 1 . -1) ( 1 . 0) ( 1 . 1) ( 1 . 2))
- (( 2 . -2) ( 2 . -1) ( 2 . 0) ( 2 . 1) ( 2 . 2)))))
- (define tail-moves
- (list->array
- 2
- '(((-1 . -1) (-1 . -1) (-1 . 0) (-1 . 1) (-1 . 1))
- ((-1 . -1) ( 0 . 0) ( 0 . 0) ( 0 . 0) (-1 . 1))
- (( 0 . -1) ( 0 . 0) ( 0 . 0) ( 0 . 0) ( 0 . 1))
- (( 1 . -1) ( 0 . 0) ( 0 . 0) ( 0 . 0) ( 1 . 1))
- (( 1 . -1) ( 1 . -1) ( 1 . 0) ( 1 . 1) ( 1 . 1)))))
- (define move-str-move-table
- (alist->hash-table
- '(("U" . (-1 . 0))
- ("D" . (1 . 0))
- ("L" . (0 . -1))
- ("R" . (0 . 1)))))
- (define arrays->hash-table
- (lambda* (keys-arr vals-arrs #:optional (equal-func equal?))
- (let ([rows (array-len-in-dim keys-arr 0)]
- [cols (array-len-in-dim keys-arr 1)]
- [table (make-hash-table equal-func)])
- (let iter-rows ([row-ind 0])
- (let iter-cols ([col-ind 0])
- (cond
- [(< row-ind rows)
- (cond
- [(< col-ind cols)
- (hash-table-set! table
- (array-ref keys-arr row-ind col-ind)
- (array-ref vals-arrs row-ind col-ind))
- (iter-cols (+ col-ind 1))]
- [else (iter-rows (+ row-ind 1))])]
- [else table]))))))
- (define distances-tail-move-table
- (arrays->hash-table distances tail-moves))
- (define update-coords
- (λ (coords diff-coords)
- (cons (+ (car coords)
- (car diff-coords))
- (+ (cdr coords)
- (cdr diff-coords)))))
- (define coords-diff
- (λ (coords1 coords2)
- (cons (- (car coords1)
- (car coords2))
- (- (cdr coords1)
- (cdr coords2)))))
- (define lines (get-lines-from-file "input"))
- (define make-list
- (λ (val count)
- (cond
- [(> count 0)
- (cons val (make-list val (- count 1)))]
- [else '()])))
- (define line->moves
- (λ (line)
- (let* ([parts (string-split line #\space)]
- [direction (first parts)]
- [times (string->number (second parts))])
- (make-list (hash-table-ref move-str-move-table direction)
- times))))
- (define moves (apply append (map line->moves lines)))
- (define simulate-move
- (λ (state move visited-table)
- (let iter-knots ([state-ind 0] [move° move])
- ;; (simple-format (current-output-port) "state: ~a\n" state)
- ;; (simple-format (current-output-port)
- ;; "updating knot: ~a at coordinates: ~a with move: ~a\n"
- ;; state-ind
- ;; (vector-ref state state-ind)
- ;; move°)
- (cond
- [(< state-ind (- (vector-length state) 1))
- (let* ([knot (vector-ref state state-ind)]
- [updated-knot (update-coords knot move°)])
- (vector-set! state state-ind updated-knot)
- (let* ([next-knot (vector-ref state (+ state-ind 1))]
- [next-move (hash-table-ref distances-tail-move-table
- (coords-diff updated-knot
- next-knot))])
- (iter-knots (+ state-ind 1) next-move)))]
- ;; If at last knot, move it and store its
- ;; coordinates.
- [else
- (let* ([knot (vector-ref state state-ind)]
- [updated-knot (update-coords knot move°)])
- ;; Update the knot's coords.
- (vector-set! state state-ind updated-knot)
- ;; Mark the updated knot coords as visited.
- (hash-table-update! visited-table
- updated-knot
- (λ (old-count) (+ old-count 1))
- (λ () 1))
- (values state visited-table))]))))
- (define tail-visited-table
- (let* ([init-coords (cons 0 0)]
- [initial-state (make-vector 10 init-coords)])
- (let iter ([state initial-state]
- [moves° moves]
- [visited-table
- ;; Do not forget, that the tail is at the initial
- ;; coordinates initially.
- (alist->hash-table `((,init-coords . 1)))])
- (cond
- [(null? moves°) visited-table]
- [else
- (let-values ([(updated-state updated-visited-table)
- (simulate-move state
- (first moves°)
- visited-table)])
- (iter updated-state
- (drop moves° 1)
- updated-visited-table))]))))
- (define sum
- (λ (lst)
- (apply + lst)))
- (simple-format (current-output-port)
- "~a\n"
- (sum
- (map (λ (val) (if (> val 0) 1 0))
- (hash-table-values tail-visited-table))))
|