Skip to content

Commit 7b08a53

Browse files
2025/09 fucking hell!
1 parent eec3851 commit 7b08a53

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

src/2025/day09.enc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(:C "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" :I "yXMuM2+IyyKkjh6sJ9yX/hN3seUFPspBcdtPetwL1/s=" :G "JfbfelleBZN9zIVSVdp8DQ==")

src/2025/day09.lisp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
(defpackage :aoc/2025/09 #.cl-user::*aoc-use*)
2+
(in-package :aoc/2025/09)
3+
4+
(defun read-red-tiles (&optional (strings (uiop:read-file-lines #P"src/2025/day09.txt")))
5+
(mapcar #'extract-integers strings))
6+
7+
8+
(defun area (x1 y1 x2 y2)
9+
(* (1+ (- (max x1 x2) (min x1 x2)))
10+
(1+ (- (max y1 y2) (min y1 y2)))))
11+
12+
(defun part1 (&optional (reds (read-red-tiles)))
13+
(looping
14+
(dosublists (((x1 y1) . reds2) reds)
15+
(doseq ((x2 y2) reds2)
16+
(maximize! (area x1 y1 x2 y2))))))
17+
18+
19+
(defun compress-coordinates (reds)
20+
(flet ((unique&sorted (list &aux (list (remove-duplicates list)))
21+
(make-array (length list) :initial-contents (sort list #'<))))
22+
(loop for (x y) in reds
23+
collect x into xx
24+
collect y into yy
25+
finally (return (list (unique&sorted xx) (unique&sorted yy))))))
26+
27+
28+
(defun edge? (vv x y)
29+
(looping
30+
(loop
31+
for (x1 y1) in (cons (last-elt vv) vv)
32+
for (x2 y2) in vv
33+
do (cond ((= x x1 x2) (thereis! (<= (min y1 y2) y (max y1 y2))))
34+
((= y y1 y2) (thereis! (<= (min x1 x2) x (max x1 x2))))))))
35+
36+
37+
;; We cast a horizontal ray to the right and count how many
38+
;; vertical edges of the polygon it crosses. An odd count means the point
39+
;; is inside.
40+
;;
41+
;; Details / caveats:
42+
;;
43+
;; - The polygon is assumed to be axis-aligned, so edges are either vertical
44+
;; or horizontal. Only vertical edges can intersect a horizontal ray.
45+
;;
46+
;; - Horizontal edges are ignored entirely since they contribute no crossings
47+
;; (the ray is parallel to them).
48+
;;
49+
;; - For each vertical edge, we check whether Y lies within that edge’s
50+
;; Y-span, using a half-open interval [ymin, ymax):
51+
;; (<= ymin y) and (< y ymax)
52+
;; This avoids double-counting when the ray passes exactly through a
53+
;; vertex shared by two vertical edges: only the “lower” edge includes
54+
;; the vertex; the “upper” edge does not.
55+
;;
56+
;; - We also require (< x x1) so that only edges strictly to the right of
57+
;; the test point count as intersections. Note: equality here is handled
58+
;; elsewhere (EDGE?), so we deliberately do not treat x = x1 as a crossing.
59+
;;
60+
;; The final parity of the crossing count (odd/even) determines the result.
61+
(defun inside? (vv x y)
62+
(oddp
63+
(looping
64+
(loop
65+
for (x1 y1) in (cons (last-elt vv) vv)
66+
for (x2 y2) in vv
67+
do (when (= x1 x2)
68+
(count! (and (<= (min y1 y2) y)
69+
(< y (max y1 y2))
70+
(< x x1))))))))
71+
72+
(defun part2 (&optional (reds (read-red-tiles)))
73+
(destructuring-bind (xx yy) (compress-coordinates reds)
74+
(let1 grid (make-array (list (length yy) (length xx))
75+
:element-type 'boolean
76+
:initial-element nil)
77+
(doseq ((i y) (enumerate yy))
78+
(doseq ((j x) (enumerate xx))
79+
(setf (aref grid i j) (and (or (edge? reds x y)
80+
(inside? reds x y))
81+
t))))
82+
(flet ((index-of (item vector)
83+
(binary-search 0 (length vector) (partial-1 #'<=> (aref vector _) item))))
84+
(looping
85+
(dosublists (((x1 y1) . reds2) reds)
86+
(doseq ((x2 y2) reds2)
87+
(let1 valid (looping
88+
(dorangei (i (index-of (min y1 y2) yy) (index-of (max y1 y2) yy))
89+
(dorangei (j (index-of (min x1 x2) xx) (index-of (max x1 x2) xx))
90+
(always! (aref grid i j)))))
91+
(when valid
92+
(maximize! (area x1 y1 x2 y2)))))))))))
93+
94+
95+
(define-solution (2025 09) (reds read-red-tiles)
96+
(values (part1 reds) (part2 reds)))
97+
98+
(define-test (2025 09) (4782268188 1574717268))

0 commit comments

Comments
 (0)