@@ 14,40 14,23 @@
(mapcar #'parse-integer (split "," s)))
(split " -> " line)))))
-;; Brute-force all combinations, time typing was cheaper than time thinking
-;; about a more elegant way to do this.
-(defun walk-line (function line count-diagonals)
+(defun walk-line (function line)
(destructuring-bind (x1 y1 x2 y2) line
- (cond
- ((and (= x1 x2) (<= y1 y2))
- (loop :for y :from y1 :to y2
- :do (funcall function x1 y)))
- ((= x1 x2)
- (loop :for y :from y1 :downto y2
- :do (funcall function x1 y)))
- ((and (= y1 y2) (<= x1 x2))
- (loop :for x :from x1 :to x2
- :do (funcall function x y1)))
- ((= y1 y2)
- (loop :for x :from x1 :downto x2
- :do (funcall function x y1)))
- (count-diagonals) ;; skip diagonals here
- ((and (<= x1 x2) (<= y1 y2))
- (loop :for x :from x1 :to x2
- :for y :from y1 :to y2
- :do (funcall function x y)))
- ((and (<= x1 x2))
- (loop :for x :from x1 :to x2
- :for y :from y1 :downto y2
- :do (funcall function x y)))
- ((and (<= y1 y2))
- (loop :for x :from x1 :downto x2
- :for y :from y1 :to y2
- :do (funcall function x y)))
- (t
- (loop :for x :from x1 :downto x2
- :for y :from y1 :downto y2
- :do (funcall function x y))))))
+ (loop :with dx := (signum (- x2 x1))
+ :with dy := (signum (- y2 y1))
+
+ :for x := x1 :then (+ x dx)
+ :for y := y1 :then (+ y dy)
+
+ :do (funcall function x y)
+ :until (and (= x x2) (= y y2)))))
+
+(defmacro do-line ((x y) line &body body)
+ `(walk-line (lambda (,x ,y) ,@body) ,line))
+
+(defun is-orthographic (line)
+ (destructuring-bind (x1 y1 x2 y2) line
+ (or (= x1 x2) (= y1 y2))))
(defun max-dimensions ()
(loop :for (x1 y1 x2 y2) :in +input+
@@ 55,20 38,20 @@
:maximize (max y1 y2) :into y
:finally (return (list (1+ x) (1+ y)))))
-(defun solve (count-diags)
+(defun solve (count-diagonals)
(loop :with (w h) := (max-dimensions)
:with grid := (make-array (list h w) :element-type 'integer)
:for line :in +input+
- :do (walk-line (lambda (x y)
- (incf (aref grid y x)))
- line count-diags)
+ :when (or (is-orthographic line) count-diagonals)
+ :do (do-line (x y) line
+ (incf (aref grid y x)))
:finally (return
(loop :for x :below w
:sum (loop :for y :below h
:count (> (aref grid y x) 1))))))
(defun solve-part-1 ()
- (solve t))
+ (solve nil))
(defun solve-part-2 ()
- (solve nil))
+ (solve t))