aboutsummaryrefslogtreecommitdiff
path: root/aoc2023-racket/day-10/day-10.rkt
blob: 64d8727018879a5c48bb5ab9388652da1bb6c57b (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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#lang racket

(require advent-of-code
         threading)

(struct posn (r c) #:transparent)

(define/match (add-posns _p1 _p2)
  [((posn x1 y1) (posn x2 y2)) (posn (+ x1 x2) (+ y1 y2))])

(define go-north (posn -1 0))
(define go-south (posn 1 0))
(define go-east (posn 0 1))
(define go-west (posn 0 -1))

(define initial-directions
  (list (cons go-north '(#\| #\7 #\F))
        (cons go-south '(#\| #\J #\L))
        (cons go-east '(#\- #\J #\7))
        (cons go-west '(#\- #\F #\L))))

(define/match (pipe-neighbors _pipe)
  [(#\|) (list go-north go-south)]
  [(#\-) (list go-east go-west)]
  [(#\L) (list go-north go-east)]
  [(#\F) (list go-south go-east)]
  [(#\7) (list go-south go-west)]
  [(#\J) (list go-north go-west)])

(define (make-pipe-grid in)
  (for*/hash ([(row r) (in-indexed (string-split in "\n"))] 
              [(ch c) (in-indexed (string->list row))])
    (values (posn (add1 r) (add1 c)) ch)))

(define (get-valid-S-neighbors S grid)
  (for/list ([dir (in-list initial-directions)]
             #:do [(match-define (cons d valid) dir)]
             #:do [(define neighbor (add-posns d S))]
             #:when (member (hash-ref grid neighbor 'none) valid))
    neighbor))

(define (to-next-pipe current previous grid [acc '()])
  (cond
    [(equal? (hash-ref grid current #f) #\S) acc]
    [else
     (define next
       (for/first ([d (in-list (pipe-neighbors (hash-ref grid current)))]
                   #:do [(define neighbor (add-posns d current))]
                   #:unless (equal? neighbor previous))
         neighbor))
     (~> next (to-next-pipe _ current grid (cons current acc)))]))

;; part 1
(define input (fetch-aoc-input (find-session) 2023 10 #:cache #true))

(define pipe-grid (make-pipe-grid input))

(define S-posn
  (for/first ([(k v) (in-hash pipe-grid)] #:when (equal? v #\S))
    k))

(define S-neighbors (get-valid-S-neighbors S-posn pipe-grid))

(define pipe-loop (to-next-pipe (first S-neighbors) S-posn pipe-grid '()))

(/ (add1 (length pipe-loop)) 2)

;; part 2
(define pipe-loop-set (~> (list->set pipe-loop) (set-add S-posn)))

(define (trace-rays pt pipes grid)
  (cond
    [(set-member? pipes pt) #f]
    [else (odd? (trace-ray pt pipes grid))]))

(define (trace-ray pt pipes grid)
  (define row (posn-r pt))
  (for/fold ([acc 0] 
             [corner #f] 
             #:result acc)
            ([col (in-naturals (posn-c pt))]
             #:do [(define test-pt (posn row col))]
             #:break (not (hash-has-key? grid test-pt))
             #:when (set-member? pipes test-pt))
    (define pipe (hash-ref grid test-pt))
    (match* (corner pipe)
      [(#f #\|) (values (add1 acc) #f)] ; vertical crossing
      [(#f (or #\F #\L)) (values acc pipe)]
      [(#\F #\J) (values (add1 acc) #f)] ; a  ┏━┛ shape counts as a vertical crossing
      [(#\L #\7) (values (add1 acc) #f)]
      [(#\F #\7) (values acc #f)] ; a  ┏━┓ shape doesn't count
      [(#\L #\J) (values acc #f)]
      [(_ _) (values acc corner)])))

(~> pipe-grid 
    hash-keys 
    (count (λ~> (trace-rays pipe-loop-set pipe-grid)) _))