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)) _))
|