# HG changeset patch # User Steve Losh # Date 1512515800 18000 # Node ID b50f1ec26d640df599735106609ff95213eeafd8 # Parent 11607ca439c40825a59dfd7c814bb3fe19f422b0 Day 4 and 5 diff -r 11607ca439c4 -r b50f1ec26d64 src/main.lisp --- a/src/main.lisp Sun Dec 03 18:39:45 2017 -0500 +++ b/src/main.lisp Tue Dec 05 18:16:40 2017 -0500 @@ -12,18 +12,35 @@ (map 'list #'digit-char-p <>) (remove nil <>))) +(defun read-file-of-numbers (path) + (iterate (for line :in-file path :using #'read-line) + (appending (mapcar #'parse-integer (str:words line))))) + (defun read-file-of-lines-of-numbers (path) (iterate (for line :in-file path :using #'read-line) (collect (mapcar #'parse-integer (str:words line))))) +(defun read-file-of-lines-of-words (path) + (iterate (for line :in-file path :using #'read-line) + (collect (str:words line)))) + + +(defun contains-duplicates-p (list &key (test #'eql)) + (iterate (for (head . tail) :on list) + (thereis (member head tail :test test)))) + +(defun anagramp (string1 string2) + (string= (sort (copy-seq string1) #'char<) + (sort (copy-seq string2) #'char<))) + ;;;; Problems ----------------------------------------------------------------- -(defun day-1-part-1 () +(defun day-1/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 () +(defun day-1/2 () (iterate (with data = (coerce (read-file-of-digits "data/2017/01") 'vector)) (with length = (length data)) @@ -34,14 +51,14 @@ (sum x)))) -(defun day-2-part-1 () +(defun day-2/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 () +(defun day-2/2 () (labels ((validp (a b) (dividesp (max a b) (min a b))) (head-valid-p (list) @@ -53,7 +70,7 @@ :key #'checksum))) -(defun day-3-part-1 () +(defun day-3/1 () (labels ((manhattan-distance (a b) (+ (abs (- (realpart a) (realpart b))) @@ -63,7 +80,7 @@ (manhattan-distance #c(0 0) p))) (distance-to-origin (advent.spiral:number-coordinates 325489)))) -(defun day-3-part-2 () +(defun day-3/2 () (flet ((neighbors (coord) (iterate (for-nested ((dx :from -1 :to 1) (dy :from -1 :to 1))) @@ -78,3 +95,44 @@ (finding value :such-that (> value 325489)) (setf (gethash coord memory) value)))) + +(defun d4-valid-passphrase-p (phrase) + (not (contains-duplicates-p phrase :test #'string=))) + +(defun day-4/1 () + (count-if #'d4-valid-passphrase-p + (read-file-of-lines-of-words "data/2017/04"))) + +(defun day-4/2 () + (flet ((contains-anagram-p (phrase) + (iterate (for (word . tail) :on phrase) + (thereis (find-if (curry #'anagramp word) tail))))) + (-<> (read-file-of-lines-of-words "data/2017/04") + (remove-if-not #'d4-valid-passphrase-p <>) + (count-if-not #'contains-anagram-p <>)))) + + +(defun day-5/1 () + (iterate + (with maze = (coerce (read-file-of-numbers "data/2017/05") 'vector)) + (with bound = (1- (length maze))) + (with address = 0) + (for steps :from 0) + (finding steps :such-that (not (<= 0 address bound))) + (for offset = (aref maze address)) + (incf (aref maze address)) + (incf address offset))) + +(defun day-5/2 () + (iterate + (declare (optimize speed) + (type fixnum bound address steps offset)) + (with maze = (coerce (read-file-of-numbers "data/2017/05") 'simple-vector)) + (with bound = (1- (length maze))) + (with address = 0) + (for steps :from 0) + (finding steps :such-that (not (<= 0 address bound))) + (for offset = (aref maze address)) + (incf (aref maze address) + (if (>= offset 3) -1 1)) + (incf address offset))) diff -r 11607ca439c4 -r b50f1ec26d64 vendor/make-quickutils.lisp --- a/vendor/make-quickutils.lisp Sun Dec 03 18:39:45 2017 -0500 +++ b/vendor/make-quickutils.lisp Tue Dec 05 18:16:40 2017 -0500 @@ -8,6 +8,7 @@ :rcurry :range :compose + :ensure-keyword :read-file-into-string ) diff -r 11607ca439c4 -r b50f1ec26d64 vendor/quickutils.lisp --- a/vendor/quickutils.lisp Sun Dec 03 18:39:45 2017 -0500 +++ b/vendor/quickutils.lisp Tue Dec 05 18:16:40 2017 -0500 @@ -2,7 +2,7 @@ ;;;; See http://quickutil.org for details. ;;;; To regenerate: -;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:CURRY :RCURRY :RANGE :COMPOSE :READ-FILE-INTO-STRING) :ensure-package T :package "ADVENT.QUICKUTILS") +;;;; (qtlc:save-utils-as "quickutils.lisp" :utilities '(:CURRY :RCURRY :RANGE :COMPOSE :ENSURE-KEYWORD :READ-FILE-INTO-STRING) :ensure-package T :package "ADVENT.QUICKUTILS") (eval-when (:compile-toplevel :load-toplevel :execute) (unless (find-package "ADVENT.QUICKUTILS") @@ -15,8 +15,8 @@ (when (boundp '*utilities*) (setf *utilities* (union *utilities* '(:MAKE-GENSYM-LIST :ENSURE-FUNCTION :CURRY :RCURRY :RANGE :COMPOSE - :ONCE-ONLY :WITH-OPEN-FILE* - :WITH-INPUT-FROM-FILE + :ENSURE-KEYWORD :ONCE-ONLY + :WITH-OPEN-FILE* :WITH-INPUT-FROM-FILE :READ-FILE-INTO-STRING)))) (eval-when (:compile-toplevel :load-toplevel :execute) (defun make-gensym-list (length &optional (x "G")) @@ -109,6 +109,11 @@ ,(compose-1 funs)))))) + (defun ensure-keyword (x) + "Ensure that a keyword is returned for the string designator `x`." + (values (intern (string x) :keyword))) + + (defmacro once-only (specs &body forms) "Evaluates `forms` with symbols specified in `specs` rebound to temporary variables, ensuring that each initform is evaluated only once. @@ -200,6 +205,6 @@ :while (= bytes-read buffer-size))))))) (eval-when (:compile-toplevel :load-toplevel :execute) - (export '(curry rcurry range compose read-file-into-string))) + (export '(curry rcurry range compose ensure-keyword read-file-into-string))) ;;;; END OF quickutils.lisp ;;;;