4d34827adc5b

Day 2
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sat, 02 Dec 2017 12:48:50 -0500
parents e96ba6a7b654
children 5e8fb9b8a553
branches/tags (none)
files advent.asd src/main.lisp vendor/make-quickutils.lisp vendor/quickutils.lisp

Changes

--- 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
--- 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)))
--- 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
 
--- 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 ;;;;