diff --git a/p11/p11.org b/p11/p11.org new file mode 100644 index 0000000..791a669 --- /dev/null +++ b/p11/p11.org @@ -0,0 +1,47 @@ +#+title: solution to p11 + +#+begin_src emacs-lisp :results none + (with-temp-buffer + (insert-file-contents "input") + (advent/replace-multiple-regex-buffer + '((":" . " ") + ("^" . "(") + ("$" . ")"))) + (goto-char (point-min)) + (insert "(setq data '(") + (goto-char (point-max)) + (insert "))") + (eval-buffer)) +#+end_src + +This is for part 1 +#+begin_src emacs-lisp + (defun paths-from (label) + (if (eq label 'out) 1 + (-sum (-map 'paths-from (cdr (assq label data)))))) + (memoize 'paths-from) + (paths-from 'you) +#+end_src + +#+RESULTS: +: 701 + +And this for part 2; note that there are no paths from dac to fft +(there can be only paths in one direction, otherwise we would get +a loop. +#+begin_src emacs-lisp + (defun paths-from-to (label exit) + (if (eq label exit) 1 + (if (eq label 'out) 0 + (-sum (--map (paths-from-to it exit) (cdr (assq label data))))))) + (memoize 'paths-from-to) +(* (paths-from-to 'svr 'fft) + (paths-from-to 'fft 'dac) + (paths-from 'dac)) +#+end_src + +#+RESULTS: +: 390108778818526 + + + diff --git a/p9/p9.org b/p9/p9.org index c5e3377..b47e619 100644 --- a/p9/p9.org +++ b/p9/p9.org @@ -1,7 +1,6 @@ -#+title: Solution to p9 +#+title: Solution to p9, aka the shitshow -Well, this was quite the shitshow… -I need to cleanup this mess +Load the data #+begin_src emacs-lisp :results none (with-temp-buffer (insert-file-contents "input") @@ -16,20 +15,24 @@ I need to cleanup this mess (eval-buffer)) #+end_src -Find max area -#+begin_src emacs-lisp +General preparation; the area is symmetric so I consider only +half of the pairs of vertices. +#+begin_src emacs-lisp :results none (defun area (el) - (let ((a (car el)) - (b (cdr el))) + (let ((a (car el)) + (b (cdr el))) (* (1+ (abs (- (car a) (car b)))) (1+ (abs (- (cadr a) (cadr b))))))) (defun symmetric-pairs (list) - (apply #'append (--map-indexed (-map (lambda (other) (cons it other)) - (-drop (1+ it-index) list)) - list))) + (apply #'append (--map-indexed (-map (lambda (other) (cons it other)) + (-drop (1+ it-index) list)) + list))) +#+end_src - (-max (-map 'area (symmetric-pairs data))) +This is for part 1. Easy. +#+begin_src emacs-lisp + (-max (-map 'area (symmetric-pairs data))) #+end_src #+RESULTS: @@ -97,42 +100,102 @@ if it is -1, then the domain is always to the left of the edges Now we cook up a function to check if a given point X Y is inside or outside #+begin_src emacs-lisp :results none - ;; The next two functions could be sped up by using bisection. See if it is necessary - - (defun vertical-edges-up-to (x) - (--take-while (<= (caar it) x) data-vertical-edges)) - - (defun horizontal-edges-up-to (y) - (--take-while (<= (cadar it) y) data-horizontal-edges)) - - (defun vertical-edge-goes-through (edge y) - (let ((miny (min (cadar edge) (cadadr edge))) - (maxy (max (cadar edge) (cadadr edge)))) - (and (< miny y) (< y maxy)))) - - (defun horizontal-edge-goes-through (edge x) - (let ((minx (min (caar edge) (caadr edge))) - (maxx (max (caar edge) (caadr edge)))) - (and (< minx x) (< x maxx)))) - - (defun odd-p (n) - (= 1 (logand n 1))) - - (defun even-p (n) - (= 0 (logand n 1))) - - (defun inside-p (x y) - (let* ((horizontal-head (horizontal-edges-up-to y)) - (vertical-head (vertical-edges-up-to x)) - (x (+ x 0.5)) - (y (+ y 0.5)) - (filtered-horizontal-head (--filter (horizontal-edge-goes-through it x) horizontal-head)) - (filtered-vertical-head (--filter (vertical-edge-goes-through it y) vertical-head))) - (and (odd-p (length filtered-horizontal-head)) - (odd-p (length filtered-vertical-head))))) + ;; The next two functions could be sped up by using bisection. + ;; See if it is necessary + + (defun vertical-edges-up-to (x) + (--take-while (<= (caar it) x) data-vertical-edges)) + + (defun horizontal-edges-up-to (y) + (--take-while (<= (cadar it) y) data-horizontal-edges)) + + (defun vertical-edge-goes-through (edge y) + (let ((miny (min (cadar edge) (cadadr edge))) + (maxy (max (cadar edge) (cadadr edge)))) + (and (< miny y) (< y maxy)))) + + (defun horizontal-edge-goes-through (edge x) + (let ((minx (min (caar edge) (caadr edge))) + (maxx (max (caar edge) (caadr edge)))) + (and (< minx x) (< x maxx)))) + + (defun odd-p (n) + (= 1 (logand n 1))) + + (defun even-p (n) + (= 0 (logand n 1))) + + (defun inside-p (x y) + (let* ((horizontal-head (horizontal-edges-up-to y)) + (vertical-head (vertical-edges-up-to x)) + (x (+ x 0.5)) + (y (+ y 0.5)) + (filtered-horizontal-head (--filter (horizontal-edge-goes-through it x) horizontal-head)) + (filtered-vertical-head (--filter (vertical-edge-goes-through it y) vertical-head))) + (and (odd-p (length filtered-horizontal-head)) + (odd-p (length filtered-vertical-head))))) +#+end_src + + + #+RESULTS: + +Of course it would be too costly to check for every square in the +candidate rects, so we first remove rectangles that cannot work for a +number of reasons; since vertices are unique, if a vertex sits +strictly inside a rectangle, the rectangle must have some bad tiles +inside. We call a rect _reasonable_ if such a thing does not happen. + +#+begin_src emacs-lisp + (setq rects (symmetric-pairs data)) + + (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 reasonable-rects + (-remove (lambda (rect) (--any (strictly-contains-p rect it) data)) rects)) + + (length reasonable-rects) +#+end_src + +Nice, that is an OK number. +Since a rectangle is reasonable, possible edges that cut through it +would have to do through all of it. We can thus check along the edges +only +#+begin_src emacs-lisp + (defun whole-rect-inside-p (rect) + (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)))) + ;; Check along the minx column and miny row + (and (--every (inside-p minx it) (-iota (- maxy miny) miny)) + (--every (inside-p it miny) (-iota (- maxx minx) minx))))) + + (setq sorted-reasonable-rects (--sort (> (area it) (area other)) reasonable-rects)) #+end_src -Let me be silly and draw the thing. +Grab some popcorn, this will take a while +#+begin_src emacs-lisp + (let ((num 0)) + (setq largest-good-rect (--first (progn + (message (format "%d" (setq num (1+ num)))) + (whole-rect-inside-p it)) + sorted-reasonable-rects))) +(area largest-good-rect) +#+end_src + +#+RESULTS: +1644094530 + +what follows is an alternative way... first realize what the shape +looks like #+begin_src emacs-lisp (setq svg-preamble " " - (scale-coordinate 5639) - (scale-coordinate 50249) - (scale-coordinate (- 94532 5639)) - (scale-coordinate (- 68743 50249)))) (insert "") ) - (write-file "tmp-2.svg"))) + (write-file "tmp.svg"))) (draw-svg) #+end_src - #+RESULTS: - -Oh motherfucker; the domain has a very special shape. +Oh motherfucker; Find the two possible vertices #+begin_src emacs-lisp @@ -238,196 +293,5 @@ Find the two possible vertices #+RESULTS: | (94532 50249) | 5639 | 68743 | -#+begin_src emacs-lisp - largest-good-rect -#+end_src - -#+RESULTS: -| (5639 68743) | 94532 | 50249 | - -(area largest-good-rect) -1644057540 - -Of course it would be too costly to check for every square in the -candidate rects, so we first remove rectangles that cannot work for a -number of reasons; since vertices are unique, if a vertex sits -strictly inside a rectangle, the rectangle must have some bad tiles -inside. We call a rect _reasonable_ if such a thing does not happen. - -#+begin_src emacs-lisp - (setq rects (symmetric-pairs data)) - - (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 reasonable-rects - (-remove (lambda (rect) (--any (strictly-contains-p rect it) data)) rects)) - - (length reasonable-rects) -#+end_src - - -Nice, that is an OK number. -Since a rectangle is reasonable, possible edges that cut through it -would have to do through all of it. We can thus check along the edges -only -#+begin_src emacs-lisp - (defun whole-rect-inside-p (rect) - (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)))) - ;; Check along the minx column and miny row - (and (--every (inside-p minx it) (-iota (- maxy miny) miny)) - (--every (inside-p it miny) (-iota (- maxx minx) minx))))) - - (setq sorted-reasonable-rects (--sort (> (area it) (area other)) reasonable-rects)) -#+end_src - -Grab some popcorn, this will take a while -#+begin_src emacs-lisp - (let ((num 0)) - (setq largest-good-rect (--first (progn - (message (format "%d" (setq num (1+ num)))) - (whole-rect-inside-p it)) - sorted-reasonable-rects))) -#+end_src - -#+RESULTS: -| (5639 68743) | 94532 | 50249 | - -(area largest-good-rect) -1644094530 -1644057540 ; it does not work. - -* +Then we can go from here... - -* - - -** This is old stuff -#+begin_src emacs-lisp :results none - (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 (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)) good-rects)) - - (length rects-sifted) -#+end_src - - -#+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 - -Now we should have eliminated all corner cases; we just need to remove -those that are cut by an edge - -#+begin_src emacs-lisp - (length rects) - (length good-rects) - (length rects-sifted) - (length rects-refined) - - (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)) - -#+end_src - -#+RESULTS: -: 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 | -| (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 |