123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- (import
- (except (rnrs base)
- let-values
- map
- error
- vector-map)
- (only (guile)
- lambda* λ
- simple-format
- current-output-port)
- (fileio)
- (ice-9 pretty-print)
- (ice-9 peg)
- (ice-9 match)
- (prefix (peg-tree-utils) peg-tree:)
- ;; (ice-9 format)
- (srfi srfi-1)
- (pipeline)
- (debug)
- ;; (list-helpers)
- (array-helpers)
- (segment)
- (parallelism)
- ;; (math)
- ;; (logic)
- ;; receive
- ;; (srfi srfi-8)
- (srfi srfi-9 gnu)
- ;; let-values
- ;; (srfi srfi-11)
- ;; purely functional data structures
- ;; (pfds sets)
- ;; (timing)
- )
- (define input-filename "input")
- (define-peg-pattern NUMBER body (and (? (or "-" "+")) (+ (range #\0 #\9))))
- (define-peg-pattern ANYTHING-EXCEPT-NUMBER none
- (* (and (not-followed-by NUMBER) peg-any)))
- (define-peg-pattern COORD all NUMBER)
- (define-peg-pattern SENSOR-INFO body
- (and (and ANYTHING-EXCEPT-NUMBER COORD)
- (and ANYTHING-EXCEPT-NUMBER COORD)
- (and ANYTHING-EXCEPT-NUMBER COORD)
- (and ANYTHING-EXCEPT-NUMBER COORD)))
- (define-immutable-record-type <sensor>
- (make-sensor sy sx by bx)
- sensor?
- (sy sensor-y set-sensor-y)
- (sx sensor-x set-sensor-x)
- (by sensor-beacon-y set-sensor-beacon-y)
- (bx sensor-beacon-x set-sensor-beacon-x))
- (define parse-sensors
- (λ (line)
- (-> line
- (match-pattern SENSOR-INFO)
- peg:tree
- (map (λ (coord) (string->number (second coord))))
- ((λ (coords)
- (match coords
- [(sensor-x sensor-y beacon-x beacon-y)
- (make-sensor sensor-y sensor-x beacon-y beacon-x)]))))))
- (define sensors
- (-> (get-lines-from-file input-filename)
- (map parse-sensors)))
- (define manhattan-distance
- (λ (y1 x1 y2 x2)
- (+ (abs (- y1 y2))
- (abs (- x1 x2)))))
- (define calc-blocked-segment
- (λ (sensor line-y)
- (match sensor
- [($ <sensor> sy sx by bx)
- (let ([distance-to-line (abs (- sy line-y))]
- [distance-to-beacon (manhattan-distance sy sx by bx)])
- (let ([delta-x (- distance-to-beacon distance-to-line)])
- (cond
- [(>= delta-x 0)
- (cons (- sx delta-x)
- (+ sx delta-x))]
- [else #f])))])))
- (define make-range
- (λ (start end)
- (cons start end)))
- (define range-start
- (λ (range)
- (car range)))
- (define range-end
- (λ (range)
- (cdr range)))
- (define range+
- (λ (r1 r2)
- "Assumes, that the lower number is the first part of a
- range."
- (make-range (min (range-start r1) (range-start r2))
- (max (range-end r1) (range-end r2)))))
- (define ranges-less
- (λ (r1 r2)
- (or (< (range-start r1) (range-start r2))
- (and (= (range-start r1) (range-start r2))
- (< (range-end r1) (range-end r2))))))
- (define find-not-blocked
- (λ (ranges limit-lower-x limit-upper-x)
- "Sum length all the blocked RANGES from LIMIT-LOWER-X to
- LIMIT-UPPER-X."
- (let ([sorted-ranges (sort ranges ranges-less)])
- (let iter ([ranges° sorted-ranges] [max-x limit-lower-x])
- (cond
- [(null? ranges°) #f]
- ;; We are past the area where the beacon is
- ;; supposed to be. No gaps found.
- [(>= max-x limit-upper-x) #f]
- [else
- (let ([current-range (car ranges°)])
- (cond
- ;; Current range is completely outside of
- ;; already counted blocked, because its start
- ;; is already past the highest seen x.
- [(< max-x (range-start current-range))
- ;; Apparently we have found a gap. Since the
- ;; puzzle says there is only 1 gap, we can
- ;; assume, that it must be the position after
- ;; max-x.
- (+ max-x 1)]
- ;; Start of current range is equal than the
- ;; highest seen x. This means, that the range
- ;; starts, not leaving a gap between already
- ;; counted blocked and its fields.
- [(= max-x (range-start current-range))
- (iter (cdr ranges°)
- ;; Do not go over the upper limit for x.
- (min (range-end current-range)
- limit-upper-x))]
- ;; The start of the current range is before the
- ;; highest max-x we have seen so far. That
- ;; means there is overlap.
- [else
- (iter (cdr ranges°)
- ;; Do not go over the upper limit for x.
- (min (max (range-end current-range) max-x)
- limit-upper-x))]))])))))
- (define identity (λ (x) x))
- (define check-line
- (λ (sensors limit-lower-x limit-upper-x line-y)
- (-> sensors
- ;; calculate the blocked ranges for each sensor
- (map (λ (sensor) (calc-blocked-segment sensor line-y)) #|sensors|#)
- ;; filter out any #f values, which stand for "no blocked range"
- (filter identity #|ranges|#)
- ((λ (blocked-ranges) (sort blocked-ranges ranges-less)))
- ;; calculate the length of the blocked ranges
- ((λ (ranges)
- (find-not-blocked ranges limit-lower-x limit-upper-x))
- #|ranges|#)
- ((λ (line-x/false)
- (if line-x/false
- (cons line-y line-x/false)
- #f)))
- )))
- (define check-lines
- (λ (sensors limit-lower-x limit-upper-x line-ys)
- "Give all line-y of LINE-YS, which have any positions, where
- a beacon could be located. Should only return a single
- line-y or an empty list."
- (-> line-ys
- ;; for all given line-ys (rows) check, whether there
- ;; is any line, which has at least 1 non-blocked
- ;; position
- (segment-map (λ (line-y)
- (check-line sensors limit-lower-x limit-upper-x line-y))
- #|line-ys|#)
- (filter identity)
- )))
- (define tuning-frequency
- (λ (y x)
- (+ (* x (* 4 (expt 10 6))) y)))
- (define limit-lower-y 0)
- (define limit-upper-y #;20 (* 4 (expt 10 6)))
- (define limit-lower-x 0)
- (define limit-upper-x #;20 (* 4 (expt 10 6)))
- (define line-partitions
- (let ([start limit-lower-y]
- [end limit-upper-y]
- [num-cores 32])
- (segment start end num-cores)))
- (define distress-beacon-locations
- (run-in-parallel line-partitions
- (λ (line-ys _ind)
- (check-lines sensors limit-lower-x limit-upper-x line-ys))
- (λ (res acc)
- (cond
- [(null? res) acc]
- [else res]))
- '()))
- (simple-format
- #t "solution: ~a\n"
- (tuning-frequency (car (first distress-beacon-locations))
- (cdr (first distress-beacon-locations))))
|