aboutsummaryrefslogtreecommitdiff
path: root/2022/day-14/day-14.rkt
blob: 7950339b1e157557183fe84d76a58eee6098edeb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#lang racket

(require advent-of-code
         threading
         algorithms)

(define data (fetch-aoc-input (find-session) 2022 14 #:cache #true))

(define (trace-line-between-points p1 p2)
  (match* (p1 p2)
    [((list x y1) (list x y2))
     (for/list ([y [in-inclusive-range (min y1 y2) (max y1 y2)]])
       (cons x y))]
    [((list x1 y) (list x2 y))
     (for/list ([x [in-inclusive-range (min x1 x2) (max x1 x2)]])
       (cons x y))]))

(define all-coordinates
  (apply append
         (for/list ([formation (in-list (string-split data "\n"))])
           (define coord-list
             (for/list ([coord-pair (in-list (string-split formation " -> "))])
               (for/list ([coord (in-list (string-split coord-pair ","))])
                 (string->number coord))))
           (apply append (adjacent-map trace-line-between-points coord-list)))))

(define rock-structures-hash
  (for/hash ([p (in-list all-coordinates)])
    (values p 'rock)))

(define max-vertical-distance (~>> all-coordinates (argmax cdr) cdr add1))

(define (open? h x y)
  (not (hash-has-key? h (cons x y))))

;; part 1
(define (trace-grain h [pos (cons 500 0)])
  (match-define (cons x y) pos)
  (cond
    [(> y max-vertical-distance) 'break]
    [(open? h x (add1 y)) (trace-grain h (cons x (add1 y)))]
    [(open? h (sub1 x) (add1 y)) (trace-grain h (cons (sub1 x) (add1 y)))]
    [(open? h (add1 x) (add1 y)) (trace-grain h (cons (add1 x) (add1 y)))]
    [else (hash-set h (cons x y) 'sand)]))

(for/fold ([h rock-structures-hash] [grains 0] #:result grains) ([_ (in-naturals 1)])
  (define h* (trace-grain h))
  #:break (eq? h* 'break)
  (values h* (add1 grains)))

;; part 2
(define (trace-grain* h [pos (cons 500 0)])
  (match-define (cons x y) pos)
  (cond
    [(= y max-vertical-distance) (hash-set h (cons x y) 'sand)]
    [(open? h x (add1 y)) (trace-grain* h (cons x (add1 y)))]
    [(open? h (sub1 x) (add1 y)) (trace-grain* h (cons (sub1 x) (add1 y)))]
    [(open? h (add1 x) (add1 y)) (trace-grain* h (cons (add1 x) (add1 y)))]
    [else (hash-set h (cons x y) 'sand)]))

(for/fold ([h rock-structures-hash] [grains 0] #:result grains) ([_ (in-naturals 1)])
  #:break (not (open? h 500 0))
  (define h* (trace-grain* h))
  (values h* (add1 grains)))