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