part-02.scm 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. (ice-9 match)
  15. (prefix (peg-tree-utils) peg-tree:)
  16. ;; (ice-9 format)
  17. (srfi srfi-1)
  18. (pipeline)
  19. (debug)
  20. ;; (list-helpers)
  21. (array-helpers)
  22. (segment)
  23. (parallelism)
  24. ;; (math)
  25. ;; (logic)
  26. ;; receive
  27. ;; (srfi srfi-8)
  28. (srfi srfi-9 gnu)
  29. ;; let-values
  30. ;; (srfi srfi-11)
  31. ;; purely functional data structures
  32. ;; (pfds sets)
  33. ;; (timing)
  34. )
  35. (define input-filename "input")
  36. (define-peg-pattern NUMBER body (and (? (or "-" "+")) (+ (range #\0 #\9))))
  37. (define-peg-pattern ANYTHING-EXCEPT-NUMBER none
  38. (* (and (not-followed-by NUMBER) peg-any)))
  39. (define-peg-pattern COORD all NUMBER)
  40. (define-peg-pattern SENSOR-INFO body
  41. (and (and ANYTHING-EXCEPT-NUMBER COORD)
  42. (and ANYTHING-EXCEPT-NUMBER COORD)
  43. (and ANYTHING-EXCEPT-NUMBER COORD)
  44. (and ANYTHING-EXCEPT-NUMBER COORD)))
  45. (define-immutable-record-type <sensor>
  46. (make-sensor sy sx by bx)
  47. sensor?
  48. (sy sensor-y set-sensor-y)
  49. (sx sensor-x set-sensor-x)
  50. (by sensor-beacon-y set-sensor-beacon-y)
  51. (bx sensor-beacon-x set-sensor-beacon-x))
  52. (define parse-sensors
  53. (λ (line)
  54. (-> line
  55. (match-pattern SENSOR-INFO)
  56. peg:tree
  57. (map (λ (coord) (string->number (second coord))))
  58. ((λ (coords)
  59. (match coords
  60. [(sensor-x sensor-y beacon-x beacon-y)
  61. (make-sensor sensor-y sensor-x beacon-y beacon-x)]))))))
  62. (define sensors
  63. (-> (get-lines-from-file input-filename)
  64. (map parse-sensors)))
  65. (define manhattan-distance
  66. (λ (y1 x1 y2 x2)
  67. (+ (abs (- y1 y2))
  68. (abs (- x1 x2)))))
  69. (define calc-blocked-segment
  70. (λ (sensor line-y)
  71. (match sensor
  72. [($ <sensor> sy sx by bx)
  73. (let ([distance-to-line (abs (- sy line-y))]
  74. [distance-to-beacon (manhattan-distance sy sx by bx)])
  75. (let ([delta-x (- distance-to-beacon distance-to-line)])
  76. (cond
  77. [(>= delta-x 0)
  78. (cons (- sx delta-x)
  79. (+ sx delta-x))]
  80. [else #f])))])))
  81. (define make-range
  82. (λ (start end)
  83. (cons start end)))
  84. (define range-start
  85. (λ (range)
  86. (car range)))
  87. (define range-end
  88. (λ (range)
  89. (cdr range)))
  90. (define range+
  91. (λ (r1 r2)
  92. "Assumes, that the lower number is the first part of a
  93. range."
  94. (make-range (min (range-start r1) (range-start r2))
  95. (max (range-end r1) (range-end r2)))))
  96. (define ranges-less
  97. (λ (r1 r2)
  98. (or (< (range-start r1) (range-start r2))
  99. (and (= (range-start r1) (range-start r2))
  100. (< (range-end r1) (range-end r2))))))
  101. (define find-not-blocked
  102. (λ (ranges limit-lower-x limit-upper-x)
  103. "Sum length all the blocked RANGES from LIMIT-LOWER-X to
  104. LIMIT-UPPER-X."
  105. (let ([sorted-ranges (sort ranges ranges-less)])
  106. (let iter ([ranges° sorted-ranges] [max-x limit-lower-x])
  107. (cond
  108. [(null? ranges°) #f]
  109. ;; We are past the area where the beacon is
  110. ;; supposed to be. No gaps found.
  111. [(>= max-x limit-upper-x) #f]
  112. [else
  113. (let ([current-range (car ranges°)])
  114. (cond
  115. ;; Current range is completely outside of
  116. ;; already counted blocked, because its start
  117. ;; is already past the highest seen x.
  118. [(< max-x (range-start current-range))
  119. ;; Apparently we have found a gap. Since the
  120. ;; puzzle says there is only 1 gap, we can
  121. ;; assume, that it must be the position after
  122. ;; max-x.
  123. (+ max-x 1)]
  124. ;; Start of current range is equal than the
  125. ;; highest seen x. This means, that the range
  126. ;; starts, not leaving a gap between already
  127. ;; counted blocked and its fields.
  128. [(= max-x (range-start current-range))
  129. (iter (cdr ranges°)
  130. ;; Do not go over the upper limit for x.
  131. (min (range-end current-range)
  132. limit-upper-x))]
  133. ;; The start of the current range is before the
  134. ;; highest max-x we have seen so far. That
  135. ;; means there is overlap.
  136. [else
  137. (iter (cdr ranges°)
  138. ;; Do not go over the upper limit for x.
  139. (min (max (range-end current-range) max-x)
  140. limit-upper-x))]))])))))
  141. (define identity (λ (x) x))
  142. (define check-line
  143. (λ (sensors limit-lower-x limit-upper-x line-y)
  144. (-> sensors
  145. ;; calculate the blocked ranges for each sensor
  146. (map (λ (sensor) (calc-blocked-segment sensor line-y)) #|sensors|#)
  147. ;; filter out any #f values, which stand for "no blocked range"
  148. (filter identity #|ranges|#)
  149. ((λ (blocked-ranges) (sort blocked-ranges ranges-less)))
  150. ;; calculate the length of the blocked ranges
  151. ((λ (ranges)
  152. (find-not-blocked ranges limit-lower-x limit-upper-x))
  153. #|ranges|#)
  154. ((λ (line-x/false)
  155. (if line-x/false
  156. (cons line-y line-x/false)
  157. #f)))
  158. )))
  159. (define check-lines
  160. (λ (sensors limit-lower-x limit-upper-x line-ys)
  161. "Give all line-y of LINE-YS, which have any positions, where
  162. a beacon could be located. Should only return a single
  163. line-y or an empty list."
  164. (-> line-ys
  165. ;; for all given line-ys (rows) check, whether there
  166. ;; is any line, which has at least 1 non-blocked
  167. ;; position
  168. (segment-map (λ (line-y)
  169. (check-line sensors limit-lower-x limit-upper-x line-y))
  170. #|line-ys|#)
  171. (filter identity)
  172. )))
  173. (define tuning-frequency
  174. (λ (y x)
  175. (+ (* x (* 4 (expt 10 6))) y)))
  176. (define limit-lower-y 0)
  177. (define limit-upper-y #;20 (* 4 (expt 10 6)))
  178. (define limit-lower-x 0)
  179. (define limit-upper-x #;20 (* 4 (expt 10 6)))
  180. (define line-partitions
  181. (let ([start limit-lower-y]
  182. [end limit-upper-y]
  183. [num-cores 32])
  184. (segment start end num-cores)))
  185. (define distress-beacon-locations
  186. (run-in-parallel line-partitions
  187. (λ (line-ys _ind)
  188. (check-lines sensors limit-lower-x limit-upper-x line-ys))
  189. (λ (res acc)
  190. (cond
  191. [(null? res) acc]
  192. [else res]))
  193. '()))
  194. (simple-format
  195. #t "solution: ~a\n"
  196. (tuning-frequency (car (first distress-beacon-locations))
  197. (cdr (first distress-beacon-locations))))