aboutsummaryrefslogtreecommitdiff
path: root/2021/day8
diff options
context:
space:
mode:
Diffstat (limited to '2021/day8')
-rw-r--r--2021/day8/08a.clj12
-rw-r--r--2021/day8/08b.clj69
2 files changed, 81 insertions, 0 deletions
diff --git a/2021/day8/08a.clj b/2021/day8/08a.clj
new file mode 100644
index 0000000..dc261e5
--- /dev/null
+++ b/2021/day8/08a.clj
@@ -0,0 +1,12 @@
+(ns day-8)
+
+(require '[clojure.string :as str])
+
+(def input (as-> (slurp "./input") x
+ (str/split x #"\n")
+ (map (fn [l]
+ (map (fn [p] (str/split (str/trim p) #" ")) (str/split l #"\|"))) x)))
+
+(def onlyOutputs (flatten (map second input)))
+(def knownDigits (filter (fn [xs] (contains? (set '(2 4 3 7)) (count xs))) onlyOutputs))
+(println (count knownDigits))
diff --git a/2021/day8/08b.clj b/2021/day8/08b.clj
new file mode 100644
index 0000000..067f802
--- /dev/null
+++ b/2021/day8/08b.clj
@@ -0,0 +1,69 @@
+(ns day-8)
+
+(require '[clojure.string :as str])
+(require '[clojure.set :as set])
+
+(def ALPHABET #{\a \b \c \d \e \f \g})
+(defn decodeWith [signal mapping]
+ (cond (every? (fn [x] (contains? mapping x)) signal) (set (map (fn [x] (get mapping x)) signal))
+ :else false))
+
+(def SIGNAL_TO_NUM {#{\a \b \c \e \f \g} 0
+ #{\c \f} 1
+ #{\a \c \d \e \g} 2
+ #{\a \c \d \f \g} 3
+ #{\b \c \d \f} 4
+ #{\a \b \d \f \g} 5
+ #{\a \b \d \e \f \g} 6
+ #{\a \c \f} 7
+ #{\a \b \c \d \e \f \g} 8
+ #{\a \b \c \d \f \g} 9})
+
+(defn decodedArrToNum [arr]
+ (reduce + (map-indexed (fn [idx sig] (* (Math/pow 10 (- (count arr) idx 1)) (SIGNAL_TO_NUM sig))) arr)))
+
+; characters that haven't been mapped (ie the mapping doesnt specify what they actually should be)
+(defn unmappedChars [mapping]
+ (set/difference ALPHABET (keys mapping)))
+
+; characters that haven't been used (ie there is no character in the mapping that results in them)
+(defn unusedChars [mapping]
+ (set/difference ALPHABET (vals mapping)))
+
+(defn validResult [x]
+ (contains? #{#{\a \b \c \e \f \g} #{\c \f} #{\a \c \d \e \g} #{\a \c \d \f \g} #{\b \c \d \f} #{\a \b \d \f \g} #{\a \b \d \e \f \g}#{\a \c \f} #{\a \b \c \d \e \f \g} #{\a \b \c \d \f \g}} x))
+
+(defn tryWith [signals mapping knownValues]
+ (cond
+ (not (every? (fn [[in expected]]
+ (def attemptedDecode (decodeWith in mapping))
+ (or (= false attemptedDecode) (= expected attemptedDecode)))
+ knownValues)) false ; stop considering path if it breaks any known values
+ (not (every? (fn [in]
+ (def attemptedDecode (decodeWith in mapping))
+ (or (= false attemptedDecode) (validResult attemptedDecode)))
+ signals)) false ; stop when any of the fully resolved signals are invalid
+ (every? validResult (map (fn [x] (decodeWith x mapping)) signals)) mapping ; base case - all resolved to valid values
+ :else (let [tryingToMap (first (unmappedChars mapping))]
+ (first (filter (comp true? boolean) (for [candidate (unusedChars mapping)]
+ (do
+ (tryWith signals (assoc mapping tryingToMap candidate) knownValues))))))))
+
+(def KNOWN_VALUES {2 #{\c \f} 4 #{\b \c \d \f} 3 #{\a \c \f} 7 #{\a \b \c \d \e \f \g}})
+
+(defn extractKnownValues [signals]
+ (reduce (fn [m s] (cond (contains? KNOWN_VALUES (count s)) (assoc m s (get KNOWN_VALUES (count s)))
+ :else m)) {} signals))
+
+(def input (as-> (slurp "./input") x
+ (str/split x #"\n")
+ (map (fn [l]
+ (map (fn [p] (map set (str/split (str/trim p) #" "))) (str/split l #"\|"))) x)))
+
+(def lineMappings (map (fn [l] (let [signals (set (flatten l))]
+ (tryWith signals {} (extractKnownValues signals)))) input))
+(def decodedOutputs (map (fn [l m] (let [signals (second l)]
+ (map (fn [x] (decodeWith x m)) signals))) input lineMappings))
+(def outputs (map decodedArrToNum decodedOutputs))
+
+(println (reduce + outputs))