Skip to content

Latest commit

 

History

History
130 lines (126 loc) · 5.11 KB

2018.03.org

File metadata and controls

130 lines (126 loc) · 5.11 KB

Day 1

Input

Each line of the input file had the format:

#ID @ LEFT,TOP : WIDTHxHEIGHT

I didn’t want to parse that, so I had emacs transform that into a list of the form:

((id (left top) (width height) ...)

A single read of the input file is all that’s needed to parse it thanks to CL’s reader.

(defvar *input-3*
  (with-open-file (s "input/3.txt")
    (read s)))

Part 1

We need to find out how many spaces have been claimed multiple times. The maximum size is 1000x1000 based on evaluating the claims.

(defun overlapping-spaces (cuts)
  (let ((fabric (make-array '(1000 1000) :initial-element 0))
        (overlap 0))
    (loop for (id (left top) (width height)) in cuts
          do (loop for i from left below (+ left width)
                   do (loop for j from top below (+ top height)
                            do (incf (aref fabric i j)))))
    (loop for i from 0 below 1000
          do (loop for j from 0 below 1000
                   if (> (aref fabric i j) 1)
                     do (incf overlap)))
    overlap))
(defun problem-3a () (format t "Problem 3a: ~a~%" (overlapping-spaces *input-3*)))

Part 2

So the logic above mostly works for what we need now. However, instead of counting the claims we will mark each space with the various claims, this will just be a list. nil will represent unclaimed spaces. At the end, we just need to find one claim which is fully its own. To do that, we iterate over the space of each claim. If it has any spaces which are shared, we skip it and go to the next one. If we get to the very end of the cut and there’s no overlap, we return that.

(defun unique-claim (cuts)
  (let ((fabric (make-array '(1000 1000) :initial-element nil))
        (unique nil))
    (loop for (id (left top) (width height)) in cuts
          do (loop for i from left below (+ left width)
                   do (loop for j from top below (+ top height)
                            do (setf (aref fabric i j) (cons id (aref fabric i j))))))
    (loop named outer
          for (id (left top) (width height)) in cuts
          do (loop named per-id
                   for i from left below (+ left width)
                   do (loop for j from top below (+ top height)
                            if (> (length (aref fabric i j)) 1)
                              do (return-from per-id nil)
                            if (and (= i (1- (+ left width)))
                                    (= j (1- (+ top height))))
                              do (return-from outer (aref fabric i j)))))))
(defun problem-3b () (format t "Problem 3b: ~a~%" (unique-claim *input-3*)))

Putting it all together

<<day3-input>>
<<problem-3a>>
<<problem-3b>>
(problem-3a)
(problem-3b)

Answers

Problem 3a: 110546
Problem 3b: (819)

Thoughts

I’m not going to clean up this code, it’s OK as is. But I did make an error in my thoughts on #2. The first loop didn’t need to be changed from the original, because ultimately I’m counting (via length) the same thing that was produced in the first loop in #1 (each cell in the array has an indicator of how many cuts try to claim it).

This would, very slightly, clean up the second loop as the test would go from:

if (> length (aref fabric i j) 1)

to:

if (> (aref fabric i j) 1)

And the variable I created, unique, in #2 was meant to be used with the second loop. If a cut had no overlaps unique would be set to that id. But I ended up not using it.

Below is how I’d have written unique-claim with those considerations.

(defun unique-claim (cuts)
  (let ((fabric (make-array '(1000 1000) :initial-element 0))
        (unique nil))
    (loop for (id (left top) (width height)) in cuts
          do (loop for i from left below (+ left width)
                   do (loop for j from top below (+ top height)
                            do (incf (aref fabric i j)))))
    (loop for (id (left top) (width height)) in cuts
          until unique
          do (loop named per-id
                   for i from left below (+ left width)
                   do (loop for j from top below (+ top height)
                            if (> (aref fabric i j) 1)
                              do (return-from per-id nil)
                            if (and (= i (1- (+ left width)))
                                    (= j (1- (+ top height))))
                              do (setf unique id))))
    unique))

Of course, since that first loop is now identical in each we could factor that into its own function. And since both problems now create the same fabric array, we could generate it once and pass it to each to use in their solutions. But I don’t feel like making those changes.