123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- (import
- (except (rnrs base) let-values map error)
- (only (guile)
- lambda* λ
- current-output-port)
- (fileio)
- (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 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 move-up
- (λ (coords)
- (cons (- (car coords) 1)
- (cdr coords))))
- (define move-down
- (λ (coords)
- (cons (+ (car coords) 1)
- (cdr coords))))
- (define move-left
- (λ (coords)
- (cons (car coords)
- (- (cdr coords) 1))))
- (define move-right
- (λ (coords)
- (cons (car coords)
- (+ (cdr coords) 1))))
- (define move-str-move-table
- (alist->hash-table
- `(("U" . ,move-up)
- ("D" . ,move-down)
- ("L" . ,move-left)
- ("R" . ,move-right))))
- (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 line->moves
- (λ (line)
- (let* ([parts (string-split line #\space)]
- [direction (first parts)]
- [times (string->number (second parts))])
- (let iter ([counter 0])
- (cond
- [(< counter times)
- (cons (hash-table-ref move-str-move-table direction)
- (iter (+ counter 1)))]
- [else '()])))))
- (define flatten
- (λ (lst)
- (cond [(null? lst) '()]
- [(pair? lst)
- (append (flatten (car lst))
- (flatten (cdr lst)))]
- [else
- (list lst)])))
- (define moves (flatten (map line->moves lines)))
- (define debug-peek
- (lambda* (sth #:optional (message ""))
- (let ([as-string
- (call-with-output-string
- (λ (port)
- (simple-format port "~a" sth)))])
- (simple-format (current-output-port)
- "~a~a\n"
- message
- as-string)
- sth)))
- (define tail-visited-table
- (let ([init-coords (cons 0 0)]
- [visited-table (make-hash-table equal?)])
- ;; Do not forget, that the tail is at the initial
- ;; coordinates initially.
- (hash-table-set! visited-table init-coords 1)
- (let iter ([moves° moves]
- ;; Assume that head anf tail both start at
- ;; (0,0).
- [tail-coords (cons 0 0)]
- [head-coords (cons 0 0)])
- (cond
- ;; No more moves? -> Return the table of visited
- ;; coordinates.
- [(null? moves°) visited-table]
- ;; Otherwise process the next move.
- [else
- (let* ([move (debug-peek (first moves°) "move:")]
- [updated-head-coords
- (debug-peek (move head-coords) "updated head:")]
- [head-tail-distance
- (debug-peek (coords-diff updated-head-coords tail-coords)
- "distance:")]
- [updated-tail-coords
- (debug-peek
- (update-coords tail-coords
- (debug-peek
- (hash-table-ref distances-tail-move-table
- head-tail-distance)
- "tail move:"))
- "updated tail:")])
- (hash-table-update! visited-table
- updated-tail-coords
- (λ (old-count)
- (+ old-count 1))
- (λ () 1))
- (iter (drop moves° 1)
- updated-tail-coords
- updated-head-coords))]))))
- (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))))
|