123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- (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)
- (prefix (peg-tree-utils) peg-tree:)
- ;; (ice-9 format)
- (srfi srfi-1)
- (pipeline)
- (debug)
- (list-helpers)
- (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 COMMA none ",")
- (define-peg-pattern ARROW none "->")
- (define-peg-pattern SPACE none " ")
- (define-peg-pattern SEPARATOR none (and SPACE ARROW SPACE))
- (define-peg-pattern NUMBER body (+ (range #\0 #\9)))
- (define-peg-pattern COORD all NUMBER)
- (define-peg-pattern COORDS all (and COORD COMMA COORD))
- (define-peg-pattern COORDS-LIST all (* (and COORDS (? SEPARATOR))))
- (define-immutable-record-type <pos>
- (make-pos y x)
- coord?
- (x position-x set-position-x)
- (y position-y set-position-y))
- (define-immutable-record-type <segment>
- (make-segment start end)
- segment?
- (start segment-start set-segment-start)
- (end segment-end set-segment-end))
- (define-immutable-record-type <rock-path>
- (make-rock-path rock-segments)
- rock-path?
- (rock-segments rock-path-segments set-rock-path-segments))
- (define extract-parsed-poss
- (λ (parsed-coords-lists)
- (map (λ (line)
- (peg:tree (match-pattern COORDS-LIST line)))
- parsed-coords-lists)))
- (define parsed-pos->pos
- (λ (parsed-pos)
- (make-pos (-> parsed-pos third second string->number)
- (-> parsed-pos second second string->number))))
- (define parsed-poss->poss
- (λ (parsed-poss)
- (map parsed-pos->pos (drop parsed-poss 1))))
- (define poss->segments
- (λ (coords)
- (let iter ([start° (car coords)]
- [segments° '()]
- [coords° (cdr coords)])
- (cond
- [(null? coords°) segments°]
- [else
- (iter (car coords°)
- (cons (make-segment start° (car coords°))
- segments°)
- (cdr coords°))]))))
- (define all-positions
- (-> (get-lines-from-file input-filename)
- extract-parsed-poss
- (map (λ (parsed-poss) (parsed-poss->poss parsed-poss))
- #|arg|#)))
- (define rock-paths
- (-> all-positions
- (map (λ (poss) (poss->segments poss))
- #|arg|#)
- (map (λ (segmentss) (make-rock-path segmentss))
- #|arg|#)))
- (define in-inclusive-range?
- (λ (num1 start end)
- (or (and (>= num1 start) (<= num1 end))
- (and (>= num1 end) (<= num1 start)))))
- (define position-on-segment?
- (λ (position segment)
- (let ([pos-x (position-x position)]
- [pos-y (position-y position)]
- [seg-start-pos-x (position-x (segment-start segment))]
- [seg-start-pos-y (position-y (segment-start segment))]
- [seg-end-pos-x (position-x (segment-end segment))]
- [seg-end-pos-y (position-y (segment-end segment))])
- (cond
- ;; vertical segment case
- [(= pos-x seg-start-pos-x seg-end-pos-x)
- (in-inclusive-range? pos-y seg-start-pos-y seg-end-pos-y)]
- ;; horizontal segment case
- [(= pos-y seg-start-pos-y seg-end-pos-y)
- (in-inclusive-range? pos-x seg-start-pos-x seg-end-pos-x)]
- [else
- #f]))))
- (define position-on-rock-path?
- (λ (position rock-path)
- (-> (rock-path-segments rock-path)
- (map (λ (segment) (position-on-segment? position segment)))
- any?)))
- (define make-empty-set
- (λ ()
- (make-set
- (λ (p1 p2)
- (or (< (position-x p1) (position-x p2))
- (and (= (position-x p1) (position-x p2))
- (< (position-y p1) (position-y p2))))))))
- (define move-down
- (λ (pos)
- (set-position-y pos (+ (position-y pos) 1))))
- (define move-down-left
- (λ (pos)
- (set-fields pos
- ((position-y) (+ (position-y pos) 1))
- ((position-x) (- (position-x pos) 1)))))
- (define move-down-right
- (λ (pos)
- (set-fields pos
- ((position-y) (+ (position-y pos) 1))
- ((position-x) (+ (position-x pos) 1)))))
- (define calc-max-rock-depth
- (λ (rock-paths)
- (-> rock-paths
- (map rock-path-segments)
- flatten
- (filter (λ (seg)
- (= (position-y (segment-start seg))
- (position-y (segment-end seg)))))
- (map (λ (hseg)
- (max (position-y (segment-start hseg))
- (position-y (segment-end hseg)))))
- (apply max))))
- (define neighbors
- (λ (pos)
- (values (move-down pos)
- (move-down-left pos)
- (move-down-right pos))))
- (define chunked-rock-paths (split-into-n-segments rock-paths 4))
- (define position-blocked?
- (λ (pos rock-paths sand-blocked-positions)
- (or (set-member? sand-blocked-positions pos)
- (-> rock-paths
- (map (λ (rock-path) (position-on-rock-path? pos rock-path)))
- any?))))
- (define settle-sand-unit
- (λ (sand-pouring-coords max-rock-depth rock-paths sand-blocked-positions)
- (let iter-sand-move ([sand-position° sand-pouring-coords])
- (cond
- ;; Otherwise check, if the sand unit has come to
- ;; rest or can flow further.
- [else
- (let-values ([(down down-left down-right) (neighbors sand-position°)])
- ;; If any of the 3 neighbor positions is not
- ;; blocked, move the sand unit there, but
- ;; adhere to the specified order.
- (cond
- [(= (position-y down) (+ max-rock-depth 2))
- ;; (simple-format #t "hit rock bottom, settled at: ~a\n" sand-position°)
- (set-insert sand-blocked-positions sand-position°)]
- [(not (position-blocked? down rock-paths sand-blocked-positions))
- (iter-sand-move down)]
- [(not (position-blocked? down-left rock-paths sand-blocked-positions))
- (iter-sand-move down-left)]
- [(not (position-blocked? down-right rock-paths sand-blocked-positions))
- (iter-sand-move down-right)]
- ;; The sand unit has come to rest.
- [else
- ;; (simple-format #t "settled at: ~a\n" sand-position°)
- (set-insert sand-blocked-positions sand-position°)]))]))))
- (define max-rock-depth (calc-max-rock-depth rock-paths))
- (simple-format #t "max-rock-depth: ~a\n" max-rock-depth)
- (define fill-up-cave
- (λ (rock-paths sand-pouring-coords max-rock-depth)
- (let iter-sand-units ([sand-blocked-positions° (make-empty-set)])
- (simple-format #t "settled ~a units of sand\n" (set-size sand-blocked-positions°))
- (let ([updated-sand-blocked-positions
- (settle-sand-unit sand-pouring-coords
- max-rock-depth
- rock-paths
- sand-blocked-positions°)])
- (cond
- ;; CHANGE: new condition for part 02
- [(set-member? updated-sand-blocked-positions sand-pouring-coords)
- (simple-format #t "filled up\n")
- updated-sand-blocked-positions]
- [(= (set-size updated-sand-blocked-positions)
- (set-size sand-blocked-positions°))
- (simple-format #t "no more sand unit settled\n")
- updated-sand-blocked-positions]
- [else
- (iter-sand-units updated-sand-blocked-positions)])))))
- (define sand-pouring-coords (make-pos 0 500))
- (define cave-filled-up-sand-blocked
- (fill-up-cave rock-paths
- sand-pouring-coords
- max-rock-depth))
- (simple-format #t "result: count: ~a\n" (set-size cave-filled-up-sand-blocked))
- (assert (set-member? cave-filled-up-sand-blocked sand-pouring-coords))
|