For Day 2 in the Advent of Code, we are given a file where each line in the file contains a list of integers separated by spaces. We will be performing some manipulations on these lists.
First, we need to read the file. We make a function to read a line as a string, then read the integers from the string and collect the result into a list.
(defun read-levels (stream eof-error-p eof-value) (let ((line (read-line stream eof-error-p eof-value))) (if (eq line eof-value) eof-value (with-input-from-string (stream line) (collect ’list (scan-stream stream))))))
We use this function to read the entire file into a list of lists of integers.
(defun read-input (input-pathname) (collect ’list (scan-file input-pathname #’read-levels)))
We are concerned with the deltas between adjacent elements in a
series of integers. We make a function to calculate the deltas.
This will be an optimizable-series-function
because it
returns a series of deltas. We declare
the argument to
be an “off-line” input series as well. This code will
be transformed into the equivalent loop code where we consume the
deltas.
chunk
is a series function that takes a series and
produces n
series of chunks that are offset by a
specified amount. We produce chunks of size 2, offset by 1. This
returns two series, the left number of each pair of numbers and the
right number of each pair of numbers. By mapping #’- over
these series, we get the series of deltas between adjacent
numbers.
(defun deltas (series) (declare (optimizable-series-function) (off-line-port series)) (multiple-value-bind (left right) (chunk 2 1 series) (#M- right left)))
As per the puzzle, a series of deltas is considered
“safe” if it is strictly ascending or descending, and
each step by which it ascends or descends is between 1 and 3
inclusive. We get the series of deltas, map #’plusp to get a
series of booleans indicating whether each delta is positive,
and collect-and
on the series of booleans. Likewise
with #’minusp for descending. Finally, we create a series of
booleans indicating whether the absolute value of the delta is <=
3 and collect-and
this as well. Whether the deltas are
considered “safe” is just a boolean operation on these
three boolean values:
(defun safe-levels? (list) (let ((deltas (deltas (scan list)))) (let ((ascending (collect-and (#Mplusp deltas))) (descending (collect-and (#Mminusp deltas))) (small (collect-and (#M<= (Mmabs deltas) (series 3))))) (and small (or ascending descending)))))
The first part of the puzzle asks us to count the number of lines considered “safe”:
(defun part-1 () (count-if #’safe-levels? (read-input (input-pathname))))
The second part of the puzzle relaxes the safety restriction by saying that you are allowed to ‘dampen’ the list by removing a single outlier before checking for safety.
(defun safe-dampened-levels? (levels) (find-if #’safe-levels? (remove-one-element levels))) (defun part-2 () (count-if #’safe-dampened-levels? (read-input (input-pathname))))
No comments:
Post a Comment