part-02.scm 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. (import
  2. (except (rnrs base)
  3. let-values
  4. map
  5. error
  6. vector-map)
  7. (only (guile)
  8. lambda* λ
  9. simple-format
  10. current-output-port)
  11. (fileio)
  12. (ice-9 pretty-print)
  13. (ice-9 peg)
  14. (prefix (peg-tree-utils) peg-tree:)
  15. ;; (ice-9 format)
  16. (srfi srfi-1)
  17. (pipeline)
  18. (debug)
  19. (list-helpers)
  20. (parallelism)
  21. ;; (math)
  22. (logic)
  23. ;; receive
  24. (srfi srfi-8)
  25. (srfi srfi-9 gnu)
  26. ;; let-values
  27. (srfi srfi-11)
  28. ;; purely functional data structures
  29. (pfds sets)
  30. (timing))
  31. (define input-filename "input")
  32. (define-peg-pattern COMMA none ",")
  33. (define-peg-pattern ARROW none "->")
  34. (define-peg-pattern SPACE none " ")
  35. (define-peg-pattern SEPARATOR none (and SPACE ARROW SPACE))
  36. (define-peg-pattern NUMBER body (+ (range #\0 #\9)))
  37. (define-peg-pattern COORD all NUMBER)
  38. (define-peg-pattern COORDS all (and COORD COMMA COORD))
  39. (define-peg-pattern COORDS-LIST all (* (and COORDS (? SEPARATOR))))
  40. (define-immutable-record-type <pos>
  41. (make-pos y x)
  42. coord?
  43. (x position-x set-position-x)
  44. (y position-y set-position-y))
  45. (define-immutable-record-type <segment>
  46. (make-segment start end)
  47. segment?
  48. (start segment-start set-segment-start)
  49. (end segment-end set-segment-end))
  50. (define-immutable-record-type <rock-path>
  51. (make-rock-path rock-segments)
  52. rock-path?
  53. (rock-segments rock-path-segments set-rock-path-segments))
  54. (define extract-parsed-poss
  55. (λ (parsed-coords-lists)
  56. (map (λ (line)
  57. (peg:tree (match-pattern COORDS-LIST line)))
  58. parsed-coords-lists)))
  59. (define parsed-pos->pos
  60. (λ (parsed-pos)
  61. (make-pos (-> parsed-pos third second string->number)
  62. (-> parsed-pos second second string->number))))
  63. (define parsed-poss->poss
  64. (λ (parsed-poss)
  65. (map parsed-pos->pos (drop parsed-poss 1))))
  66. (define poss->segments
  67. (λ (coords)
  68. (let iter ([start° (car coords)]
  69. [segments° '()]
  70. [coords° (cdr coords)])
  71. (cond
  72. [(null? coords°) segments°]
  73. [else
  74. (iter (car coords°)
  75. (cons (make-segment start° (car coords°))
  76. segments°)
  77. (cdr coords°))]))))
  78. (define all-positions
  79. (-> (get-lines-from-file input-filename)
  80. extract-parsed-poss
  81. (map (λ (parsed-poss) (parsed-poss->poss parsed-poss))
  82. #|arg|#)))
  83. (define rock-paths
  84. (-> all-positions
  85. (map (λ (poss) (poss->segments poss))
  86. #|arg|#)
  87. (map (λ (segmentss) (make-rock-path segmentss))
  88. #|arg|#)))
  89. (define in-inclusive-range?
  90. (λ (num1 start end)
  91. (or (and (>= num1 start) (<= num1 end))
  92. (and (>= num1 end) (<= num1 start)))))
  93. (define position-on-segment?
  94. (λ (position segment)
  95. (let ([pos-x (position-x position)]
  96. [pos-y (position-y position)]
  97. [seg-start-pos-x (position-x (segment-start segment))]
  98. [seg-start-pos-y (position-y (segment-start segment))]
  99. [seg-end-pos-x (position-x (segment-end segment))]
  100. [seg-end-pos-y (position-y (segment-end segment))])
  101. (cond
  102. ;; vertical segment case
  103. [(= pos-x seg-start-pos-x seg-end-pos-x)
  104. (in-inclusive-range? pos-y seg-start-pos-y seg-end-pos-y)]
  105. ;; horizontal segment case
  106. [(= pos-y seg-start-pos-y seg-end-pos-y)
  107. (in-inclusive-range? pos-x seg-start-pos-x seg-end-pos-x)]
  108. [else
  109. #f]))))
  110. (define position-on-rock-path?
  111. (λ (position rock-path)
  112. (-> (rock-path-segments rock-path)
  113. (map (λ (segment) (position-on-segment? position segment)))
  114. any?)))
  115. (define make-empty-set
  116. (λ ()
  117. (make-set
  118. (λ (p1 p2)
  119. (or (< (position-x p1) (position-x p2))
  120. (and (= (position-x p1) (position-x p2))
  121. (< (position-y p1) (position-y p2))))))))
  122. (define move-down
  123. (λ (pos)
  124. (set-position-y pos (+ (position-y pos) 1))))
  125. (define move-down-left
  126. (λ (pos)
  127. (set-fields pos
  128. ((position-y) (+ (position-y pos) 1))
  129. ((position-x) (- (position-x pos) 1)))))
  130. (define move-down-right
  131. (λ (pos)
  132. (set-fields pos
  133. ((position-y) (+ (position-y pos) 1))
  134. ((position-x) (+ (position-x pos) 1)))))
  135. (define calc-max-rock-depth
  136. (λ (rock-paths)
  137. (-> rock-paths
  138. (map rock-path-segments)
  139. flatten
  140. (filter (λ (seg)
  141. (= (position-y (segment-start seg))
  142. (position-y (segment-end seg)))))
  143. (map (λ (hseg)
  144. (max (position-y (segment-start hseg))
  145. (position-y (segment-end hseg)))))
  146. (apply max))))
  147. (define neighbors
  148. (λ (pos)
  149. (values (move-down pos)
  150. (move-down-left pos)
  151. (move-down-right pos))))
  152. (define chunked-rock-paths (split-into-n-segments rock-paths 4))
  153. (define position-blocked?
  154. (λ (pos rock-paths sand-blocked-positions)
  155. (or (set-member? sand-blocked-positions pos)
  156. (-> rock-paths
  157. (map (λ (rock-path) (position-on-rock-path? pos rock-path)))
  158. any?))))
  159. (define settle-sand-unit
  160. (λ (sand-pouring-coords max-rock-depth rock-paths sand-blocked-positions)
  161. (let iter-sand-move ([sand-position° sand-pouring-coords])
  162. (cond
  163. ;; Otherwise check, if the sand unit has come to
  164. ;; rest or can flow further.
  165. [else
  166. (let-values ([(down down-left down-right) (neighbors sand-position°)])
  167. ;; If any of the 3 neighbor positions is not
  168. ;; blocked, move the sand unit there, but
  169. ;; adhere to the specified order.
  170. (cond
  171. [(= (position-y down) (+ max-rock-depth 2))
  172. ;; (simple-format #t "hit rock bottom, settled at: ~a\n" sand-position°)
  173. (set-insert sand-blocked-positions sand-position°)]
  174. [(not (position-blocked? down rock-paths sand-blocked-positions))
  175. (iter-sand-move down)]
  176. [(not (position-blocked? down-left rock-paths sand-blocked-positions))
  177. (iter-sand-move down-left)]
  178. [(not (position-blocked? down-right rock-paths sand-blocked-positions))
  179. (iter-sand-move down-right)]
  180. ;; The sand unit has come to rest.
  181. [else
  182. ;; (simple-format #t "settled at: ~a\n" sand-position°)
  183. (set-insert sand-blocked-positions sand-position°)]))]))))
  184. (define max-rock-depth (calc-max-rock-depth rock-paths))
  185. (simple-format #t "max-rock-depth: ~a\n" max-rock-depth)
  186. (define fill-up-cave
  187. (λ (rock-paths sand-pouring-coords max-rock-depth)
  188. (let iter-sand-units ([sand-blocked-positions° (make-empty-set)])
  189. (simple-format #t "settled ~a units of sand\n" (set-size sand-blocked-positions°))
  190. (let ([updated-sand-blocked-positions
  191. (settle-sand-unit sand-pouring-coords
  192. max-rock-depth
  193. rock-paths
  194. sand-blocked-positions°)])
  195. (cond
  196. ;; CHANGE: new condition for part 02
  197. [(set-member? updated-sand-blocked-positions sand-pouring-coords)
  198. (simple-format #t "filled up\n")
  199. updated-sand-blocked-positions]
  200. [(= (set-size updated-sand-blocked-positions)
  201. (set-size sand-blocked-positions°))
  202. (simple-format #t "no more sand unit settled\n")
  203. updated-sand-blocked-positions]
  204. [else
  205. (iter-sand-units updated-sand-blocked-positions)])))))
  206. (define sand-pouring-coords (make-pos 0 500))
  207. (define cave-filled-up-sand-blocked
  208. (fill-up-cave rock-paths
  209. sand-pouring-coords
  210. max-rock-depth))
  211. (simple-format #t "result: count: ~a\n" (set-size cave-filled-up-sand-blocked))
  212. (assert (set-member? cave-filled-up-sand-blocked sand-pouring-coords))