diff --git a/p9/p9.org b/p9/p9.org index b43a4c4..42b16ca 100644 --- a/p9/p9.org +++ b/p9/p9.org @@ -2,7 +2,7 @@ #+begin_src emacs-lisp :results none (with-temp-buffer - (insert-file-contents "input-test") + (insert-file-contents "input") (advent/replace-multiple-regex-buffer '(("," . " ") ("^" . "(") @@ -17,7 +17,7 @@ Find max area #+begin_src emacs-lisp (defun area (el) - (let ((a (car el)) + (let ((a (car el)) (b (cdr el))) (abs (* (- (car a) (car b) -1) (- (cadr a) (cadr b) -1))))) @@ -31,13 +31,14 @@ Find max area #+end_src #+RESULTS: -: 50 +: 4737096935 For part 2, we begin by removing the vertices that are not corners. (there may be some, or none, but I don't know for sure) #+begin_src emacs-lisp :results none (setq data-prev (-rotate 1 data) data-next (-rotate -1 data) + edges (-zip-lists data data-next) data-pv (-zip-lists data data-prev data-next)) (defun normalize (x) @@ -57,160 +58,129 @@ For part 2, we begin by removing the vertices that are not corners. (cons (cornerize (cadr it) (car it)) (cornerize (car it) (caddr it)))) data-pv)) - - (setq data-corners - (--remove (equal (cadr it) (cddr it)) data-corners)) #+end_src OK, the datapoints are all corners. Now I know. Find which way is inside -#+begin_src emacs-lisp - ;; find the leftmost and topmost coordinate - (setq leftmost (-min (-map #'car data)) - topmost (-min (-map #'cadr data))) - - ;; find corners that lie on the leftmost coordinate; the domain must - ;; be to their right it appears that there are only two such corners; - ;; take the first one, and the outgoing direction; it is going down - ;; and it must come from the right, so it should be (-1 0) . (0 -1) - - (car (--filter (= (caar it) leftmost) data-corners)) - - ;; We therefore know what corners are convex and what corners are concave - (setq quadrant-map - '( (((-1 0) . (0 -1)) . (4)) - (((0 -1) . (1 0)) . (1)) - (((1 0) . (0 1)) . (2)) - (((0 1) . (-1 0)) . (3)) - (((-1 0) . (0 1)) . (2 3 4)) - (((0 1) . (1 0)) . (1 3 4)) - (((1 0) . (0 -1)) . (4 1 2)) - (((0 -1) . (-1 0)) . ( 1 2 3)))) - - (setq rects (symmetric-pairs data)) - - ;; first filter away those that strictly contain a vertex - (defun strictly-contains-p (rect p) - (let ((minx (min (caar rect) (cadr rect))) - (maxx (max (caar rect) (cadr rect))) - (miny (min (cadar rect) (caddr rect))) - (maxy (max (cadar rect) (caddr rect))) - (px (car p)) - (py (cadr p))) - (and (< minx px) (< px maxx) - (< miny py) (< py maxy)))) - - (setq rects-sifted (-remove (lambda (rect) (--any (strictly-contains-p rect it) data)) rects)) -#+end_src +#+begin_src emacs-lisp :results none + ;; find the leftmost and topmost coordinate + (setq leftmost (-min (-map #'car data)) + topmost (-min (-map #'cadr data))) -#+begin_src emacs-lisp - (defun incompatible-p (rect corner) + ;; find corners that lie on the leftmost coordinate; the domain must + ;; be to their right it appears that there are only two such corners; + ;; take the first one, and the outgoing direction; it is going down + ;; and it must come from the right, so it should be (-1 0) . (0 1) + + (setq orientation (-last-item (car (--filter (= (caar it) leftmost) data-corners)))) + + ;; We therefore know what corners are convex and what corners are concave + + (defun corner-normal (corner) + (let* ((cor (cdr corner)) + (a (caar cor)) + (d (caddr cor)) + (b (cadar cor)) + (c (cadr cor)) + (det (* orientation (- (* b c) (* a d))))) + (list det (- c a) (- d b)))) + + (setq data-normals (--map (cons (car it) (corner-normal it)) data-corners)) + + (setq rects (symmetric-pairs data)) + + ;; first filter those rectangles that are defined by vertices that + ;; have the wrong orientation + + (defun compatible-or (u v) + (if (or (= (car u) 0) (= (cadr u) 0)) t + (if (> (car v) 0) (equal u (cdr v)) ;convex corner + (not (equal u (cdr v))) ;concave corner + ))) + + (defun good-orientation-p (rect) + (let ((a (assoc (car rect) data-normals)) + (b (assoc (cdr rect) data-normals))) + (and (compatible-or (cornerize (car b) (car a)) (cdr b)) + (compatible-or (cornerize (car a) (car b)) (cdr a))))) + + (setq good-rects (-filter #'good-orientation-p rects)) + + ;; then filter away those that strictly contain a vertex + (defun strictly-contains-p (rect p) (let ((minx (min (caar rect) (cadr rect))) (maxx (max (caar rect) (cadr rect))) (miny (min (cadar rect) (caddr rect))) (maxy (max (cadar rect) (caddr rect))) - (px (caar corner)) - (py (cadar corner)) - (quadrant-list (cdr (assoc (cdr corner) quadrant-map)))) - (or (and (= px minx) (< miny py) (< py maxy) (< 2 (length (-intersection '(1 4) quadrant-list)))) ; on left edge - (and (= px maxx) (< miny py) (< py maxy) (< 2 (length (-intersection '(2 3) quadrant-list)))) - (and (= py miny) (< minx px) (< px maxx) (< 2 (length (-intersection '(1 2) quadrant-list)))) - (and (= py maxy) (< minx px) (< px maxx) (< 2 (length (-intersection '(3 4) quadrant-list))))))) - - (setq final-rects (-remove (lambda (rect) (--any (incompatible-p rect it) data-corners)) rects-sifted)) - (-max (-map #'area final-rects)) -#+end_src + (px (car p)) + (py (cadr p))) + (and (< minx px) (< px maxx) + (< miny py) (< py maxy)))) -#+RESULTS: -: 40 + (setq rects-sifted (-remove (lambda (rect) (--any (strictly-contains-p rect it) data)) good-rects)) -#+begin_src emacs-lisp - (car rects) - (--filter (incompatible-p (cadr rects-sifted) it) data-corners) + (length rects-sifted) +#+end_src - (cadr rects-sifted) +#+begin_src emacs-lisp :results none + (defun incompatible-p (rect corner) + (let ((minx (min (caar rect) (cadr rect))) + (maxx (max (caar rect) (cadr rect))) + (miny (min (cadar rect) (caddr rect))) + (maxy (max (cadar rect) (caddr rect))) + (px (caar corner)) + (py (cadar corner)) + (convexity (cadr corner)) + (normal (cddr corner))) + + (or (and (= px minx) (< miny py) (< py maxy) (< (advent/dot normal (list convexity 0)) 0)) ; on left edge + (and (= px maxx) (< miny py) (< py maxy) (> (advent/dot normal (list convexity 0)) 0)) + (and (= py miny) (< minx px) (< px maxx) (< (advent/dot normal (list 0 convexity)) 0)) + (and (= py maxy) (< minx px) (< px maxx) (> (advent/dot normal (list 0 convexity)) 0))))) + + (setq rects-refined (-remove (lambda (rect) (--any (incompatible-p rect it) data-normals)) rects-sifted)) #+end_src -#+RESULTS: -| (7 1) | 11 | 1 | -| (7 1) | 11 | 7 | -| (7 1) | 9 | 7 | -| (7 1) | 9 | 5 | -| (7 1) | 2 | 5 | -| (7 1) | 2 | 3 | -| (7 1) | 7 | 3 | -| (11 1) | 11 | 7 | -| (11 1) | 9 | 7 | -| (11 1) | 9 | 5 | -| (11 1) | 2 | 5 | -| (11 1) | 2 | 3 | - -| (11 1) | 7 | 3 | -| (11 7) | 9 | 7 | -| (11 7) | 9 | 5 | -| (11 7) | 2 | 5 | -| (11 7) | 2 | 3 | -| (11 7) | 7 | 3 | -| (9 7) | 9 | 5 | -| (9 7) | 2 | 5 | -| (9 7) | 2 | 3 | -| (9 7) | 7 | 3 | -| (9 5) | 2 | 5 | -| (9 5) | 2 | 3 | -| (9 5) | 7 | 3 | -| (2 5) | 2 | 3 | -| (2 5) | 7 | 3 | -| (2 3) | 7 | 3 | +Now we should have eliminated all corner cases; we just need to remove +those that are cut by an edge #+begin_src emacs-lisp - rects-sifted -#+end_src + (length rects) + (length good-rects) + (length rects-sifted) + (length rects-refined) -#+RESULTS: -| (7 1) | 11 | 1 | -| (7 1) | 9 | 7 | -| (7 1) | 9 | 5 | -| (7 1) | 2 | 5 | -| (7 1) | 2 | 3 | -| (7 1) | 7 | 3 | -| (11 1) | 11 | 7 | -| (11 1) | 9 | 7 | -| (11 1) | 9 | 5 | -| (11 1) | 2 | 3 | -| (11 1) | 7 | 3 | -| (11 7) | 9 | 7 | -| (11 7) | 9 | 5 | -| (11 7) | 2 | 5 | -| (9 7) | 9 | 5 | -| (9 7) | 2 | 5 | -| (9 7) | 2 | 3 | -| (9 7) | 7 | 3 | -| (9 5) | 2 | 5 | -| (9 5) | 2 | 3 | -| (9 5) | 7 | 3 | -| (2 5) | 2 | 3 | -| (2 5) | 7 | 3 | -| (2 3) | 7 | 3 | + (defun cuts-p (rect edge) + (let* ((minx (min (caar rect) (cadr rect))) + (maxx (max (caar rect) (cadr rect))) + (miny (min (cadar rect) (caddr rect))) + (maxy (max (cadar rect) (caddr rect))) + (eminx (min (caar edge) (caadr edge))) + (emaxx (max (caar edge) (caadr edge))) + (eminy (min (cadar edge) (cadadr edge))) + (emaxy (max (cadar edge) (cadadr edge))) + (ver (= eminx emaxx))) + (if ver (and (< minx eminx) (< eminx maxx) (< eminy miny) (< maxy emaxy)) + (and (< miny eminy) (< eminy maxy) (< eminx minx) (< maxx emaxx)))) + ) + + (setq rects-uncut (-remove (lambda (rect) (--any (cuts-p rect it) edges)) rects-refined)) + (length rects-uncut) + + + (-max (-map #'area rects-uncut)) -#+begin_src emacs-lisp - final-rects #+end_src #+RESULTS: -| (7 1) | 11 | 1 | -| (7 1) | 9 | 7 | -| (7 1) | 9 | 5 | -| (7 1) | 2 | 5 | -| (7 1) | 2 | 3 | -| (7 1) | 7 | 3 | -| (11 1) | 11 | 7 | -| (11 1) | 9 | 7 | -| (11 1) | 9 | 5 | -| (11 1) | 2 | 3 | +: 1644057540 + | (11 1) | 7 | 3 | | (11 7) | 9 | 7 | | (11 7) | 9 | 5 | | (11 7) | 2 | 5 | +| (11 7) | 2 | 3 | +| (11 7) | 7 | 3 | | (9 7) | 9 | 5 | | (9 7) | 2 | 5 | | (9 7) | 2 | 3 |