# HG changeset patch # User Steve Losh # Date 1512236930 18000 # Node ID 4d34827adc5be1005beb96978aa68423be8aeca3 # Parent e96ba6a7b65438b48cf755c4aff857d90077b70d Day 2 diff -r e96ba6a7b654 -r 4d34827adc5b advent.asd --- a/advent.asd Fri Dec 01 13:42:19 2017 -0500 +++ b/advent.asd Sat Dec 02 12:48:50 2017 -0500 @@ -5,7 +5,7 @@ :license "MIT" - :depends-on (:iterate :losh) + :depends-on (:iterate :losh :split-sequence :str) :serial t :components ((:module "vendor" :serial t diff -r e96ba6a7b654 -r 4d34827adc5b src/main.lisp --- a/src/main.lisp Fri Dec 01 13:42:19 2017 -0500 +++ b/src/main.lisp Sat Dec 02 12:48:50 2017 -0500 @@ -12,19 +12,42 @@ (map 'list #'digit-char-p <>) (remove nil <>))) +(defun read-file-of-lines-of-numbers (path) + (iterate (for line :in-file path :using #'read-line) + (collect (mapcar #'parse-integer (str:words line))))) + ;;;; Problems ----------------------------------------------------------------- (defun day-1-part-1 () - (iterate (for (x . y) :pairs-of-list (read-file-of-digits "data/2017/01-1")) + (iterate (for (x . y) :pairs-of-list (read-file-of-digits "data/2017/01")) (when (= x y) (sum x)))) (defun day-1-part-2 () (iterate - (with data = (coerce (read-file-of-digits "data/2017/01-1") 'vector)) + (with data = (coerce (read-file-of-digits "data/2017/01") 'vector)) (with length = (length data)) (for x :in-vector data) (for iy :modulo length :from (truncate length 2)) (for y = (aref data iy)) (when (= x y) (sum x)))) + + +(defun day-2-part-1 () + (flet ((checksum (line) + (- (apply #'max line) + (apply #'min line)))) + (summation (remove nil (read-file-of-lines-of-numbers "data/2017/02")) + :key #'checksum))) + +(defun day-2-part-2 () + (labels ((validp (a b) + (dividesp (max a b) (min a b))) + (head-valid-p (list) + (some (curry #'validp (car list)) + (cdr list))) + (checksum (line) + (somelist #'head-valid-p line))) + (summation (remove nil (read-file-of-lines-of-numbers "data/2017/02")) + :key #'checksum))) diff -r e96ba6a7b654 -r 4d34827adc5b vendor/make-quickutils.lisp --- a/vendor/make-quickutils.lisp Fri Dec 01 13:42:19 2017 -0500 +++ b/vendor/make-quickutils.lisp Sat Dec 02 12:48:50 2017 -0500 @@ -5,6 +5,7 @@ :utilities '( :curry + :extremum :rcurry :read-file-into-string diff -r e96ba6a7b654 -r 4d34827adc5b vendor/quickutils.lisp --- a/vendor/quickutils.lisp Fri Dec 01 13:42:19 2017 -0500 +++ b/vendor/quickutils.lisp Sat Dec 02 12:48:50 2017 -0500 @@ -2,7 +2,7 @@ ;;;; See http://quickutil.org for details. ;;;; To regenerate: -;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:CURRY :RCURRY :READ-FILE-INTO-STRING) :ensure-package T :package "ADVENT.QUICKUTILS") +;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:CURRY :EXTREMUM :RCURRY :READ-FILE-INTO-STRING) :ensure-package T :package "ADVENT.QUICKUTILS") (eval-when (:compile-toplevel :load-toplevel :execute) (unless (find-package "ADVENT.QUICKUTILS") @@ -14,7 +14,7 @@ (when (boundp '*utilities*) (setf *utilities* (union *utilities* '(:MAKE-GENSYM-LIST :ENSURE-FUNCTION - :CURRY :RCURRY :ONCE-ONLY + :CURRY :EXTREMUM :RCURRY :ONCE-ONLY :WITH-OPEN-FILE* :WITH-INPUT-FROM-FILE :READ-FILE-INTO-STRING)))) (eval-when (:compile-toplevel :load-toplevel :execute) @@ -61,6 +61,50 @@ (apply ,fun ,@curries more))))) + (defun extremum (sequence predicate &key key (start 0) end) + "Returns the element of `sequence` that would appear first if the subsequence +bounded by `start` and `end` was sorted using `predicate` and `key`. + +`extremum` determines the relationship between two elements of `sequence` by using +the `predicate` function. `predicate` should return true if and only if the first +argument is strictly less than the second one (in some appropriate sense). Two +arguments `x` and `y` are considered to be equal if `(funcall predicate x y)` +and `(funcall predicate y x)` are both false. + +The arguments to the `predicate` function are computed from elements of `sequence` +using the `key` function, if supplied. If `key` is not supplied or is `nil`, the +sequence element itself is used. + +If `sequence` is empty, `nil` is returned." + (let* ((pred-fun (ensure-function predicate)) + (key-fun (unless (or (not key) (eq key 'identity) (eq key #'identity)) + (ensure-function key))) + (real-end (or end (length sequence)))) + (cond ((> real-end start) + (if key-fun + (flet ((reduce-keys (a b) + (if (funcall pred-fun + (funcall key-fun a) + (funcall key-fun b)) + a + b))) + (declare (dynamic-extent #'reduce-keys)) + (reduce #'reduce-keys sequence :start start :end real-end)) + (flet ((reduce-elts (a b) + (if (funcall pred-fun a b) + a + b))) + (declare (dynamic-extent #'reduce-elts)) + (reduce #'reduce-elts sequence :start start :end real-end)))) + ((= real-end start) + nil) + (t + (error "Invalid bounding indexes for sequence of length ~S: ~S ~S, ~S ~S" + (length sequence) + :start start + :end end))))) + + (defun rcurry (function &rest arguments) "Returns a function that applies the arguments it is called with and `arguments` to `function`." @@ -162,6 +206,6 @@ :while (= bytes-read buffer-size))))))) (eval-when (:compile-toplevel :load-toplevel :execute) - (export '(curry rcurry read-file-into-string))) + (export '(curry extremum rcurry read-file-into-string))) ;;;; END OF quickutils.lisp ;;;;