part-01.scm 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. (srfi srfi-9 gnu)
  24. ;; let-values
  25. (srfi srfi-11)
  26. ;; purely functional data structures
  27. (pfds sets)
  28. (timing))
  29. (define input-filename "input")
  30. ;; QLIST -- Merely adding a Q to avoid any name clashes, either actual
  31. ;; ones or in my mind.
  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. (parallel-map (λ (line _ind)
  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. (parallel-map (λ (parsed-poss _ind) (parsed-poss->poss parsed-poss))
  82. #|arg|#)))
  83. (define rock-paths
  84. (-> all-positions
  85. ;; ((λ (thing) (pretty-peek thing #:width 20)))
  86. (parallel-map (λ (poss _ind) (poss->segments poss))
  87. #|arg|#)
  88. (parallel-map (λ (segmentss _ind) (make-rock-path segmentss))
  89. #|arg|#)
  90. ;; ((λ (thing) (pretty-peek thing #:width 40)))
  91. ))
  92. (define in-inclusive-range?
  93. (λ (num1 start end)
  94. (or (and (>= num1 start) (<= num1 end))
  95. (and (>= num1 end) (<= num1 start)))))
  96. (assert (in-inclusive-range? 75 50 100))
  97. (assert (in-inclusive-range? 75 100 50))
  98. (assert (not (in-inclusive-range? 3 100 50)))
  99. (assert (not (in-inclusive-range? 103 100 50)))
  100. (assert (not (in-inclusive-range? 3 50 100)))
  101. (assert (not (in-inclusive-range? 103 50 100)))
  102. (define position-on-segment?
  103. (λ (position segment)
  104. (let ([pos-x (position-x position)]
  105. [pos-y (position-y position)]
  106. [seg-start-pos-x (position-x (segment-start segment))]
  107. [seg-start-pos-y (position-y (segment-start segment))]
  108. [seg-end-pos-x (position-x (segment-end segment))]
  109. [seg-end-pos-y (position-y (segment-end segment))])
  110. (cond
  111. ;; vertical segment case
  112. [(= pos-x seg-start-pos-x seg-end-pos-x)
  113. (in-inclusive-range? pos-y seg-start-pos-y seg-end-pos-y)]
  114. ;; horizontal segment case
  115. [(= pos-y seg-start-pos-y seg-end-pos-y)
  116. (in-inclusive-range? pos-x seg-start-pos-x seg-end-pos-x)]
  117. [else
  118. #f]))))
  119. (assert (position-on-segment?
  120. (make-pos 28 40)
  121. (make-segment (make-pos 28 35) (make-pos 28 40))))
  122. (assert (not
  123. (position-on-segment?
  124. (make-pos 30 40)
  125. (make-segment (make-pos 28 35) (make-pos 28 40)))))
  126. (define position-on-rock-path?
  127. (λ (position rock-path)
  128. (any? (map (λ (segment) (position-on-segment? position segment))
  129. (rock-path-segments rock-path)))))
  130. (assert
  131. (position-on-rock-path? (make-pos 30 40)
  132. (make-rock-path
  133. (list (make-segment (make-pos 28 35) (make-pos 28 40))
  134. (make-segment (make-pos 28 40) (make-pos 30 40))))))
  135. (assert
  136. (not
  137. (position-on-rock-path? (make-pos 30 40)
  138. (make-rock-path
  139. (list (make-segment (make-pos 28 35) (make-pos 28 40))
  140. (make-segment (make-pos 28 40) (make-pos 29 40)))))))
  141. (define make-empty-set
  142. (λ ()
  143. (make-set
  144. (λ (p1 p2)
  145. (or (< (position-x p1) (position-x p2))
  146. (and (= (position-x p1) (position-x p2))
  147. (< (position-y p1) (position-y p2))))))))
  148. (define move-down
  149. (λ (pos)
  150. (set-position-y pos (+ (position-y pos) 1))))
  151. (define move-down-left
  152. (λ (pos)
  153. (set-fields pos
  154. ((position-y) (+ (position-y pos) 1))
  155. ((position-x) (- (position-x pos) 1)))))
  156. (define move-down-right
  157. (λ (pos)
  158. (set-fields pos
  159. ((position-y) (+ (position-y pos) 1))
  160. ((position-x) (+ (position-x pos) 1)))))
  161. (define calc-max-rock-depth
  162. (λ (rock-paths)
  163. (-> rock-paths
  164. ;; ((λ (rock-paths) (pretty-print (take rock-paths 5)) rock-paths))
  165. (map rock-path-segments)
  166. flatten
  167. (filter (λ (seg)
  168. (= (position-y (segment-start seg))
  169. (position-y (segment-end seg)))))
  170. (map (λ (hseg)
  171. (max (position-y (segment-start hseg))
  172. (position-y (segment-end hseg)))))
  173. (apply max))))
  174. (define neighbors
  175. (λ (pos)
  176. (values (move-down pos)
  177. (move-down-left pos)
  178. (move-down-right pos))))
  179. (define chunked-rock-paths (split-into-n-segments rock-paths 4))
  180. (define position-blocked?
  181. (λ (pos rock-paths sand-blocked-positions)
  182. (or (set-member? sand-blocked-positions pos)
  183. (any? (map (λ (rock-path)
  184. (position-on-rock-path? pos rock-path))
  185. rock-paths)))))
  186. (define settle-sand-unit
  187. (λ (sand-pouring-coords max-rock-depth rock-paths sand-blocked-positions)
  188. (let iter-sand-move ([sand-position° sand-pouring-coords])
  189. ;; (simple-format #t "sand unit moved to ~a\n" sand-position°)
  190. (cond
  191. ;; If one unit of sand flows into the abyss, the
  192. ;; next one will also flow there, as it starts at
  193. ;; the same position and the state of the cave
  194. ;; has not changed.
  195. [(> (position-y sand-position°) max-rock-depth) sand-blocked-positions]
  196. ;; Otherwise check, if the sand unit has come to
  197. ;; rest or can flow further.
  198. [else
  199. (let-values ([(down down-left down-right) (neighbors sand-position°)])
  200. ;; If any of the 3 neighbor positions is not
  201. ;; blocked, move the sand unit there, but
  202. ;; adhere to the specified order.
  203. (cond
  204. [(not (position-blocked? down rock-paths sand-blocked-positions))
  205. (iter-sand-move down)]
  206. [(not (position-blocked? down-left rock-paths sand-blocked-positions))
  207. (iter-sand-move down-left)]
  208. [(not (position-blocked? down-right rock-paths sand-blocked-positions))
  209. (iter-sand-move down-right)]
  210. ;; The sand unit has come to rest.
  211. [else
  212. (set-insert sand-blocked-positions sand-position°)]))]))))
  213. (define count-sand-units
  214. (λ (rock-paths sand-pouring-coords)
  215. (let ([max-rock-depth (calc-max-rock-depth rock-paths)])
  216. (simple-format #t "max-rock-depth: ~a\n" max-rock-depth)
  217. ;; TODO: There is a weird case: What if the sand fills
  218. ;; up the cave up to the sand pouring position?
  219. (let iter-sand-units ([counter 0]
  220. [sand-blocked-positions° (make-empty-set)])
  221. ;; (simple-format #t "already placed ~a units of sand\n" counter)
  222. (let ([updated-sand-blocked-positions
  223. (settle-sand-unit sand-pouring-coords
  224. max-rock-depth
  225. rock-paths
  226. sand-blocked-positions°)])
  227. (cond
  228. [(= (set-size updated-sand-blocked-positions)
  229. (set-size sand-blocked-positions°))
  230. counter]
  231. [else
  232. (iter-sand-units (+ counter 1)
  233. updated-sand-blocked-positions)]))))))
  234. (define sand-pouring-coords (make-pos 0 500))
  235. (simple-format #t "result: ~a\n" (count-sand-units rock-paths sand-pouring-coords))