part-02.scm 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. (import
  2. (except (rnrs base) let-values map error)
  3. (only (guile)
  4. lambda* λ
  5. current-output-port)
  6. (fileio)
  7. (list-helpers)
  8. (srfi srfi-1)
  9. ;; let-values
  10. (srfi srfi-11)
  11. ;; hash tables
  12. (srfi srfi-69)
  13. (ice-9 pretty-print))
  14. (define array-len-in-dim
  15. (λ (arr dim)
  16. (let* ([shape (array-shape arr)]
  17. [dim-min-max (list-ref shape dim)])
  18. (+ (- (second dim-min-max)
  19. (first dim-min-max))
  20. 1))))
  21. (define distances
  22. (list->array
  23. 2
  24. '(((-2 . -2) (-2 . -1) (-2 . 0) (-2 . 1) (-2 . 2))
  25. ((-1 . -2) (-1 . -1) (-1 . 0) (-1 . 1) (-1 . 2))
  26. (( 0 . -2) ( 0 . -1) ( 0 . 0) ( 0 . 1) ( 0 . 2))
  27. (( 1 . -2) ( 1 . -1) ( 1 . 0) ( 1 . 1) ( 1 . 2))
  28. (( 2 . -2) ( 2 . -1) ( 2 . 0) ( 2 . 1) ( 2 . 2)))))
  29. (define tail-moves
  30. (list->array
  31. 2
  32. '(((-1 . -1) (-1 . -1) (-1 . 0) (-1 . 1) (-1 . 1))
  33. ((-1 . -1) ( 0 . 0) ( 0 . 0) ( 0 . 0) (-1 . 1))
  34. (( 0 . -1) ( 0 . 0) ( 0 . 0) ( 0 . 0) ( 0 . 1))
  35. (( 1 . -1) ( 0 . 0) ( 0 . 0) ( 0 . 0) ( 1 . 1))
  36. (( 1 . -1) ( 1 . -1) ( 1 . 0) ( 1 . 1) ( 1 . 1)))))
  37. (define move-str-move-table
  38. (alist->hash-table
  39. '(("U" . (-1 . 0))
  40. ("D" . (1 . 0))
  41. ("L" . (0 . -1))
  42. ("R" . (0 . 1)))))
  43. (define arrays->hash-table
  44. (lambda* (keys-arr vals-arrs #:optional (equal-func equal?))
  45. (let ([rows (array-len-in-dim keys-arr 0)]
  46. [cols (array-len-in-dim keys-arr 1)]
  47. [table (make-hash-table equal-func)])
  48. (let iter-rows ([row-ind 0])
  49. (let iter-cols ([col-ind 0])
  50. (cond
  51. [(< row-ind rows)
  52. (cond
  53. [(< col-ind cols)
  54. (hash-table-set! table
  55. (array-ref keys-arr row-ind col-ind)
  56. (array-ref vals-arrs row-ind col-ind))
  57. (iter-cols (+ col-ind 1))]
  58. [else (iter-rows (+ row-ind 1))])]
  59. [else table]))))))
  60. (define distances-tail-move-table
  61. (arrays->hash-table distances tail-moves))
  62. (define update-coords
  63. (λ (coords diff-coords)
  64. (cons (+ (car coords)
  65. (car diff-coords))
  66. (+ (cdr coords)
  67. (cdr diff-coords)))))
  68. (define coords-diff
  69. (λ (coords1 coords2)
  70. (cons (- (car coords1)
  71. (car coords2))
  72. (- (cdr coords1)
  73. (cdr coords2)))))
  74. (define lines (get-lines-from-file "input"))
  75. (define make-list
  76. (λ (val count)
  77. (cond
  78. [(> count 0)
  79. (cons val (make-list val (- count 1)))]
  80. [else '()])))
  81. (define line->moves
  82. (λ (line)
  83. (let* ([parts (string-split line #\space)]
  84. [direction (first parts)]
  85. [times (string->number (second parts))])
  86. (make-list (hash-table-ref move-str-move-table direction)
  87. times))))
  88. (define moves (apply append (map line->moves lines)))
  89. (define simulate-move
  90. (λ (state move visited-table)
  91. (let iter-knots ([state-ind 0] [move° move])
  92. ;; (simple-format (current-output-port) "state: ~a\n" state)
  93. ;; (simple-format (current-output-port)
  94. ;; "updating knot: ~a at coordinates: ~a with move: ~a\n"
  95. ;; state-ind
  96. ;; (vector-ref state state-ind)
  97. ;; move°)
  98. (cond
  99. [(< state-ind (- (vector-length state) 1))
  100. (let* ([knot (vector-ref state state-ind)]
  101. [updated-knot (update-coords knot move°)])
  102. (vector-set! state state-ind updated-knot)
  103. (let* ([next-knot (vector-ref state (+ state-ind 1))]
  104. [next-move (hash-table-ref distances-tail-move-table
  105. (coords-diff updated-knot
  106. next-knot))])
  107. (iter-knots (+ state-ind 1) next-move)))]
  108. ;; If at last knot, move it and store its
  109. ;; coordinates.
  110. [else
  111. (let* ([knot (vector-ref state state-ind)]
  112. [updated-knot (update-coords knot move°)])
  113. ;; Update the knot's coords.
  114. (vector-set! state state-ind updated-knot)
  115. ;; Mark the updated knot coords as visited.
  116. (hash-table-update! visited-table
  117. updated-knot
  118. (λ (old-count) (+ old-count 1))
  119. (λ () 1))
  120. (values state visited-table))]))))
  121. (define tail-visited-table
  122. (let* ([init-coords (cons 0 0)]
  123. [initial-state (make-vector 10 init-coords)])
  124. (let iter ([state initial-state]
  125. [moves° moves]
  126. [visited-table
  127. ;; Do not forget, that the tail is at the initial
  128. ;; coordinates initially.
  129. (alist->hash-table `((,init-coords . 1)))])
  130. (cond
  131. [(null? moves°) visited-table]
  132. [else
  133. (let-values ([(updated-state updated-visited-table)
  134. (simulate-move state
  135. (first moves°)
  136. visited-table)])
  137. (iter updated-state
  138. (drop moves° 1)
  139. updated-visited-table))]))))
  140. (define sum
  141. (λ (lst)
  142. (apply + lst)))
  143. (simple-format (current-output-port)
  144. "~a\n"
  145. (sum
  146. (map (λ (val) (if (> val 0) 1 0))
  147. (hash-table-values tail-visited-table))))