DEV Community

Discussion on: AoC Day 3: No Matter How You Slice It

Collapse
 
ballpointcarrot profile image
Christopher Kruse

Adding my Clojure solution here - will write another post at some point. I'm oncall this week and got paged at 3am for something out of my control, so I figured "hey, I'm up, might as well." get-overlap solves part 1, while find-no-overlap solves part 2. Second part is a little brute-force, but still worked.

(ns aoc.aoc3
  (:require [clojure.string :as s]
            [clojure.set :as set]))

(defrecord Claim [claim-number squares])

(defn convert-to-grid
  "Converts a claim into a sequence of 'taken' squares."
  [claim grid-width]
  ;; Named groups would be great here, but Clojure doesn't support this natively.
  (let [matcher #"#(?<claim>\d+)\s@\s(?<x>\d+),(?<y>\d+):\s(?<width>\d+)x(?<height>\d+)$"
        matches (re-find matcher claim)
        [_ claim horiz vert width height] matches
        x (Integer. horiz)
        y (Integer. vert)
        w (Integer. width)
        h (Integer. height)
        rows (take h (iterate inc y))]
    (->> (map #(range (+ x (* grid-width %)) (+ (+ x w) (* grid-width %))) rows)
         (flatten)
         (set)
         (Claim. (Integer. claim) ))))

(defn get-overlap
  "returns the amount of overlap based on calculated inputs.
   Answer provided in square units matching the units entered
   (for the case of the problem, square inches)."
  [claims]
  ;; Perform intersection to find any matches, then union to combine; repeat through the list.
  (loop [mapped-area (map #(convert-to-grid % 1000) claims)
         shared-fabric #{}
         intersections #{}]
    (if (empty? mapped-area)
      intersections
      (let [intersect (set/intersection shared-fabric (:squares (first mapped-area)))
            union (set/union shared-fabric (:squares (first mapped-area)))]
        (recur (rest mapped-area) union (set/union intersections intersect))))))

(defn overlapping-claim [c1 c2]
  (cond
    (= (:claim-number c1) (:claim-number c2)) nil
    (not-empty (set/intersection (:squares c1) (:squares c2))) c2))

(defn find-no-overlap
"given a set of input claims, find the claim that has no overlap
  with any other claims."
[claims]
(let [grid-claims (map #(convert-to-grid % 1000) claims)]
  (loop [idx 0 ignores #{}]
    (if-not (contains? (:claim-id (nth grid-claims idx)) ignores)
      (if-let [overlap (some #(overlapping-claim (nth grid-claims idx) %) grid-claims)]
        (recur (inc idx) (conj ignores (:claim-number overlap)))
        (:claim-number (nth grid-claims idx)))
      (recur (inc idx) ignores)))))