part-01.scm 5.4 KB

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