Last active
December 12, 2020 07:38
-
-
Save dosbol/4e960dbb2b87a8fc0e2d54542233a0eb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns main | |
(:require | |
[clojure.string :as str] | |
[clojure.math.combinatorics :as combo])) | |
(comment | |
;; day 1 | |
;; | |
(def input (->> (slurp "input1.txt") | |
((fn [v] (str/split v #"\s"))) | |
(map #(Integer/parseInt %)))) | |
(reduce (fn [_ [a b]] (when (= 2020 (+ a b)) (reduced (* a b)))) | |
nil | |
(combo/combinations input 2)) | |
(reduce (fn [_ [a b c]] (when (= 2020 (+ a b c)) (reduced (* a b c)))) | |
nil | |
(combo/combinations input 3)) | |
;; day 2 | |
;; | |
;; | |
(def input (->> (slurp "input2.txt") | |
((fn [v] (str/split v #"\n"))) | |
(map (fn [v] (str/split v #" "))) | |
(map (fn [[x y z]] [(map #(Integer/parseInt %) (str/split x #"-")) | |
(first y) | |
z])))) | |
(count (filter #{\a} "aaabbc")) | |
(->> input | |
(filter (fn [[[min max] c s]] (<= min (->> s (filter #{c}) count) max))) | |
count) | |
(get "abc" 1) | |
(->> input | |
(map (fn [[[frst scnd] c s]] (count (filter #{c} [(get s (dec frst)) (get s (dec scnd))])))) | |
(filter #{1}) | |
count) | |
;; | |
;; day 3 | |
;; | |
(def input (->> (slurp "input3.txt") | |
((fn [v] (str/split v #"\n"))))) | |
(def height (count input)) | |
(def width (* height 3)) | |
(get (get input 1) 1) | |
(nth (take 10 (cycle "..#")) 8) | |
(def board (->> input (mapv #(take width (cycle %))))) | |
(def coords (map (fn [x y] [x y]) (range height) (range 0 width 3))) | |
(nth (nth board (ffirst coords)) 0) | |
(->> coords | |
(map (fn [[x y]] (-> (nth board x) | |
(nth y)))) | |
(filter #{\#}) | |
count) ;200 | |
;;part 2 | |
(def input (->> (slurp "input3.txt") | |
((fn [v] (str/split v #"\n"))))) | |
(def height (count input)) | |
(def width (* height 7)) | |
(def board (->> input (mapv #(take width (cycle %))))) | |
(def coords (map (fn [x y] [x y]) (range height) (range width))) | |
(->> coords | |
(map (fn [[x y]] (-> (nth board x) | |
(nth y)))) | |
(filter #{\#}) | |
count) ;66 | |
(def coords (map (fn [x y] [x y]) (range height) (range 0 width 5))) | |
(->> coords | |
(map (fn [[x y]] (-> (nth board x) | |
(nth y)))) | |
(filter #{\#}) | |
count);76 | |
(def coords (map (fn [x y] [x y]) (range height) (range 0 width 7))) | |
(->> coords | |
(map (fn [[x y]] (-> (nth board x) | |
(nth y)))) | |
(filter #{\#}) | |
count);81 | |
(def coords (map (fn [x y] [x y]) (range 0 height 2) (range width))) | |
(->> coords | |
(map (fn [[x y]] (-> (nth board x) | |
(nth y)))) | |
(filter #{\#}) | |
count);46 | |
(* 46 81 76 66 200) | |
;; | |
;; day4 | |
;; | |
(->> (slurp "input4.txt") | |
str/split-lines | |
(partition-by #(= "" %)) | |
(remove #{'("")}) | |
(map (fn [s] (str/split (str/join " " s) #"\s|:"))) | |
(map (fn [xs] (filter #{"byr" "eyr" "iyr" "hgt" "hcl" "ecl" "pid"} xs))) | |
(filter (fn [xs] (= (count xs) 7))) | |
count) | |
(def passports (->> (slurp "input4.txt") | |
str/split-lines | |
(partition-by #(= "" %)) | |
(remove #{'("")}) | |
(map (fn [s] (str/split (str/join " " s) #"\s|:"))) | |
(map #(->> (partition 2 %) | |
(map vec) | |
(into {}))))) | |
(->> passports | |
;; (filter (fn [p] (= (count (filter #{"byr" "eyr" "iyr" "hgt" "hcl" "ecl" "pid"} (keys p))) 7))) | |
;; | |
(filter (fn [p] (and (= (count (get p "byr")) 4) | |
(<= 1920 (Integer/parseInt (get p "byr")) 2002)))) | |
(filter (fn [p] (and (= (count (get p "iyr")) 4) | |
(<= 2010 (Integer/parseInt (get p "iyr")) 2020)))) | |
(filter (fn [p] (and (= (count (get p "eyr")) 4) | |
(<= 2020 (Integer/parseInt (get p "eyr")) 2030)))) | |
(filter (fn [p] (= (count (get p "pid")) 9))) | |
(filter (fn [p] (let [measure (str/join "" [(last (butlast (get p "hgt"))) (last (get p "hgt"))]) | |
height-str (str/join "" (butlast (butlast (get p "hgt")))) | |
height (when-not (str/blank? height-str) (Integer/parseInt height-str))] | |
(and (some #{"cm" "in"} [measure]) | |
(if (= measure "cm") | |
(<= 150 height 193) | |
(<= 59 height 76)))))) | |
(filter (fn [p] (some #{"amb" "blu" "brn" "gry" "grn" "hzl" "oth"} [(get p "ecl")]))) | |
(filter (fn [p] (let [hc (get p "hcl") | |
hc# (first (get p "hcl")) | |
hc- (str/join "" (next hc))] | |
(and (= hc# \#) | |
(= (count hc-) 6) | |
(every? #(re-matches #"[0-9]|[a-f]" (str %)) hc-))))) | |
count) | |
(some #{"cm" "in"} ["in"]) | |
;; (Integer/parseInt (str/join "" (butlast (butlast "17")))) | |
(str/join "" (butlast (butlast "17"))) | |
(re-matches #"[0-9]" "9") | |
(every? #(re-matches #"[a-f]" (str %)) "acd") | |
(some #{1 2 3} [4]) | |
(= \# (first "#adsfsadf")) | |
(every? #(re-matches #"[0-9]" (str %)) "123456a") | |
;; | |
;; day 5 | |
;; | |
"FBFBBFF" ;44 | |
"FBFBBFFRLR" ;357 | |
"BFFFBBFRRR" ;567 | |
"FFFBBBFRRR" ;119 | |
"BBFFBBFRLL" ;820 | |
(def l->b {\B 1 \F 0 \R 1 \L 0}) | |
(def powers-of-2 (iterate (partial * 2) 1)) | |
(take 4 powers-of-2) | |
(->> "FBFBBFF" | |
(map l->b) | |
reverse | |
(map * powers-of-2) | |
(apply +)) | |
(defn solve [s] | |
(+ (* 8 | |
(->> s | |
(take 7) | |
(map l->b) | |
(reverse) | |
(map (fn [b x] (* b x)) [1 2 4 8 16 32 64]) | |
(reduce +))) | |
(->> s | |
(reverse) | |
(take 3) | |
(map l->b) | |
(map (fn [b x] (* b x)) [1 2 4]) | |
(reduce +)))) | |
(solve "FBFBBFFRLR") | |
(solve "BFFFBBFRRR") | |
(solve "FFFBBBFRRR") | |
(solve "BBFFBBFRLL") | |
(->> (slurp "input5.txt") | |
str/split-lines | |
(map solve) | |
(apply max)) ;963 | |
(->> (slurp "input5.txt") | |
str/split-lines | |
(map solve) | |
set | |
((fn [xs ys] (clojure.set/difference xs ys)) (set (range 963)))) | |
;; | |
;; day 6 | |
;; | |
(str/split "abc" #"") | |
(str/join ["a"]) | |
(->> (slurp "input6.txt") | |
((fn [v] (str/split v #"\n\n"))) | |
(map str/split-lines) | |
(map (fn [xs] (-> xs str/join (str/split #"")))) | |
(map frequencies) | |
(map keys) | |
(map count) | |
(apply +)) | |
(->> (slurp "input6.txt") | |
((fn [v] (str/split v #"\n\n"))) | |
(map str/split-lines) | |
(map (fn [xs] [(count xs) (-> xs str/join (str/split #""))])) | |
(map (fn [[count xs]] (filter #(= count %) (vals (frequencies xs))))) | |
(map count) | |
(apply +)) | |
;; | |
;; day 7 | |
;; | |
(def data (->> (slurp "input7.txt") | |
((fn [v] (str/split v #"\n"))) | |
(map (fn [v] (str/split v #" bags contain "))) | |
(map (fn [[color contains]] [color (str/split contains #" bags?\.?\,?")])) | |
(remove (fn [[_ contains]] (= contains ["no other"]))) | |
(map (fn [[color contains]] | |
[color (set (flatten (map (partial drop 1) | |
(map (partial re-find #".?\d+ (.+)") contains))))])) | |
(into {}))) | |
(clojure.set/intersection #{} #{:a}) | |
(map first (filter #(seq (clojure.set/intersection (second %) #{"shiny gold"})) data)) | |
(into #{} [:a :b]) | |
(loop [bags #{"shiny gold"} | |
old-bags #{}] | |
(if (= bags old-bags) | |
(dec (count bags)) | |
(let [new-bags (into bags (map first | |
(filter #(seq (clojure.set/intersection bags (second %))) data)))] | |
(recur new-bags bags)))) | |
;; shiny gold bags contain 2 dark red bags. | |
;; dark red bags contain 2 dark orange bags. | |
;; dark orange bags contain 2 dark yellow bags. | |
;; dark yellow bags contain 2 dark green bags. | |
;; dark green bags contain 2 dark blue bags. | |
;; dark blue bags contain 2 dark violet bags. | |
;; dark violet bags contain no other bags. | |
;; | |
;; 2 red + 4 orange + 8 yellow + 16 green + 32 blue + 64 violet | |
(+ 2 4 8 16 32 64) | |
(def data (->> (slurp "input7.txt") | |
((fn [v] (str/split v #"\n"))) | |
(map (fn [v] (str/split v #" bags contain "))) | |
(map (fn [[color contains]] [color (str/split contains #" bags?\.?\,?")])) | |
(remove (fn [[_ contains]] (= contains ["no other"]))) | |
(map (fn [[color contains]] | |
[color (mapv (fn [[_ d c]] [c (Long/parseLong d)]) | |
(map (partial re-find #".?(\d+) (.+)") contains))])) | |
(into {}))) | |
(defn get-bags-inside [times [color amount]] | |
[(mapv (partial get-bags-inside (* times amount)) (data color)) (* times amount)]) | |
(dec (apply + (flatten (get-bags-inside 1 ["shiny gold" 1])))) | |
;; day 8 | |
(def program (->> (slurp "input8.txt") | |
((fn [v] (str/split v #"\n"))) | |
(mapv (fn [v] (let [[op arg] (str/split v #" ")] | |
[op (Long/parseLong arg)]))))) | |
(loop [acc 0 | |
line 1 | |
visited-lines #{}] | |
(let [[op arg] (nth program (dec line))] | |
(if (visited-lines line) | |
acc | |
(recur (if (= op "acc") (+ acc arg) acc) | |
(case op | |
"jmp" (+ line arg) | |
(inc line)) | |
(conj visited-lines line))))) | |
(def nops (for [x (range (dec (count program))) | |
:let [[op arg] (nth program x)] | |
:when (= op "nop")] | |
[x ["jmp" arg]])) | |
(def jmps (for [x (range (dec (count program))) | |
:let [[op arg] (nth program x)] | |
:when (= op "jmp")] | |
[x ["nop" arg]])) | |
(def all-position-with-ops (vec (concat nops jmps))) | |
(defn solve2 [program] | |
(loop [acc 0 | |
line 1 | |
visited-lines #{}] | |
(if (>= line (inc (count program))) | |
acc | |
(let [[op arg] (nth program (dec line))] | |
(if (visited-lines line) | |
nil | |
(recur (if (= op "acc") (+ acc arg) acc) | |
(case op | |
"jmp" (+ line arg) | |
(inc line)) | |
(conj visited-lines line))))))) | |
(for [[i change] all-position-with-ops | |
:when (solve2 (assoc program i change))] | |
(solve2 (assoc program i change))) | |
;; day 9 | |
(def data (->> (slurp "input9.txt") | |
((fn [v] (str/split v #"\n"))) | |
(map #(Long/parseLong %)))) | |
(def length 25) | |
(defn valid? [data i] | |
(when-not (seq (for [x (range (- i length) i) | |
y (range (- i length) i) | |
:when (and (not= x y) (= (+ (nth data x) | |
(nth data y)) | |
(nth data i)))] | |
true)) | |
(nth data i))) | |
(some identity (map (partial valid? data) (range length (count data)))) | |
;part 2 | |
(def target (some identity (map (partial valid? data) (range length (count data))))) | |
(def target-range | |
(loop [lo 0 | |
hi 0 | |
remain target] | |
(let [curr (nth data hi)] | |
(cond | |
(= curr remain) | |
[lo (inc hi)] | |
(> curr remain) | |
(recur (inc lo) (inc lo) target) | |
(< curr remain) | |
(recur lo (inc hi) (- remain curr)))))) | |
(->> (apply range target-range) | |
(map (partial nth data)) | |
(apply (juxt min max)) | |
(apply +)) | |
;; day 10 | |
(def data (->> (slurp "input10.txt") | |
((fn [v] (str/split v #"\n"))) | |
(map #(Long/parseLong %)))) | |
(def maximum (apply clojure.core/max data)) | |
(loop [one 0 | |
three 0 | |
jolt 0] | |
(if (= jolt maximum) | |
(* one (inc three)) | |
(cond | |
(some #{(+ jolt 1)} data) | |
(recur (inc one) three (+ jolt 1)) | |
(some #{(+ jolt 2)} data) | |
(recur one three (+ jolt 2)) | |
(some #{(+ jolt 3)} data) | |
(recur one (inc three) (+ jolt 3))))) | |
;; part 2 | |
;; | |
(defn next-numbers [x] | |
(remove nil? [(when (some #{(+ x 1)} data) (+ x 1)) | |
(when (some #{(+ x 2)} data) (+ x 2)) | |
(when (some #{(+ x 3)} data) (+ x 3))])) | |
(loop [ways '(0) | |
result 0] | |
(prn ways) | |
(if-not (seq ways) | |
result | |
(let [next-xs (mapcat next-numbers ways)] | |
(recur (remove #{maximum} next-xs) | |
(+ result (count (filter #{maximum} next-xs))))))) | |
{0 1} | |
{1 1} | |
{4 1} | |
{5 1, 6 1, 7 1} | |
{6 1, 7 2, 10 1} | |
{7 1, 10 2, 11 1, 12 1} | |
{10 1, 11 2, 12 3, 15 1} | |
{11 1, 12 3, 15 3, 16 1} | |
{12 1, 15 3, 16 3, 19 1} | |
{15 1, 16 3, 19 4} | |
{16 1, 19 7} | |
{19 8} | |
(defn magic [m] | |
(reduce-kv | |
(fn [m k v] | |
(-> (reduce (fn [m key] (update m key (fnil + 0) v)) | |
m | |
(next-numbers k)) | |
(update k - v) | |
(->> (filter (fn [[_ y]] (not= y 0))) | |
(into {})))) | |
m | |
(dissoc m maximum))) | |
(loop [ways {0 1}] | |
(if (= (keys ways) (list maximum)) | |
(ways maximum) | |
(recur (magic ways)))) | |
;; day 11 | |
(def data (->> (slurp "input11.txt") | |
((fn [v] (str/split v #"\n"))) | |
(mapv (fn [v] (str/split v #""))))) | |
(get-in data [0 -1] ".") | |
(defn get-adjacents [data [x y]] | |
(for [dx [-1 0 1] | |
dy [-1 0 1] | |
:when (not (= dx dy 0))] | |
(get-in data [(+ x dx) (+ y dy)] "."))) | |
(defn no-occupied-adjacents? [data [x y]] | |
(not (some #{"#"} (get-adjacents data [x y])))) | |
(no-occupied-adjacents? data [4 4]) | |
(defn four-or-more-occupied-adjacents? [data [x y]] | |
(<= 4 (count (filter #{"#"} (get-adjacents data [x y]))))) | |
(four-or-more-occupied-adjacents? data [4 4]) | |
(get-adjacents data [0 0]) | |
(get-adjacents data [4 4]) | |
(def rules {"." (fn [_ _] ".") | |
"L" (fn [data [x y]] (if (no-occupied-adjacents? data [x y]) | |
"#" | |
"L")) | |
"#" (fn [data [x y]] (if (four-or-more-occupied-adjacents? data [x y]) | |
"L" | |
"#"))}) | |
(def all-x-y (for [x (range (count data)) | |
y (range (count (first data)))] | |
[x y])) | |
(defn next-seat [data rules [x y]] | |
((rules (get-in data [x y])) data [x y])) | |
((rules (get-in data [0 0])) data [0 0]) | |
(next-seat data rules [0 0]) | |
(mapv vec (partition (count data) (mapv (partial next-seat data rules) all-x-y))) | |
(loop [old-data [] | |
new-data data | |
step 0] | |
(if (= old-data new-data) | |
(count (filter #{"#"} (flatten new-data))) | |
(recur new-data (mapv vec | |
(partition | |
(count (first data)) | |
(mapv (partial next-seat new-data rules) all-x-y))) (inc step)))) | |
;; part 2 | |
(def data (->> (slurp "input11.txt") | |
((fn [v] (str/split v #"\n"))) | |
(mapv (fn [v] (str/split v #""))))) | |
(defn coords [] | |
(for [dx [-1 0 1] | |
dy [-1 0 1] | |
:when (not (= dx dy 0))] | |
[dx dy])) | |
(defn diffs [data] | |
(map #(take (apply max [(count (first data)) (count data)]) %) (map repeat (coords)))) | |
(diffs data) | |
(defn coords-look-for [data [x y]] | |
(map (fn [ds] | |
(reduce (fn [[acc [x y]] [dx dy]] | |
(if (or (> 0 (+ x dx)) | |
(> 0 (+ y dy)) | |
(<= (count data) (+ x dx)) | |
(<= (count (first data)) (+ y dy))) | |
(reduced acc) | |
[(conj acc [(+ x dx) (+ y dy)]) [(+ x dx) (+ y dy)]])) | |
[[] [x y]] | |
ds)) | |
(diffs data))) | |
(coords-look-for data [0 0]) | |
(defn seen-seats [data [x y]] | |
(map | |
#(reduce | |
(fn [curr [x y]] | |
(let [seat (get-in data [x y] ".")] | |
(if-not (= curr seat) | |
(reduced seat) | |
curr))) | |
"." | |
%) | |
(coords-look-for data [x y]))) | |
(seen-seats data [3 3]) | |
(seen-seats data [0 0]) | |
(defn no-occupied-seen-seats? [data [x y]] | |
(not (some #{"#"} (seen-seats data [x y])))) | |
(no-occupied-seen-seats? data [0 0]) | |
(defn five-or-more-occupied-seen-seats? [data [x y]] | |
(<= 5 (count (filter #{"#"} (seen-seats data [x y]))))) | |
(five-or-more-occupied-seen-seats? data [4 4]) | |
(def rules {"." (fn [_ _] ".") | |
"L" (fn [data [x y]] (if (no-occupied-seen-seats? data [x y]) | |
"#" | |
"L")) | |
"#" (fn [data [x y]] (if (five-or-more-occupied-seen-seats? data [x y]) | |
"L" | |
"#"))}) | |
(defn next-seat [data rules [x y]] | |
((rules (get-in data [x y])) data [x y])) | |
((rules (get-in data [0 0])) data [0 0]) | |
(next-seat data rules [9 9]) | |
(defn all-x-ys [data] | |
(for [x (range (count data)) | |
y (range (count (first data)))] | |
[x y])) | |
(def x-ys (all-x-ys data)) | |
(loop [old-data [] | |
new-data data] | |
(if (= old-data new-data) | |
(count (filter #{"#"} (flatten new-data))) | |
(recur new-data (mapv vec | |
(partition | |
(count (first data)) | |
(mapv | |
(partial next-seat new-data rules) | |
x-ys)))))) | |
;; day 12 | |
(def data (->> (slurp "input12.txt") | |
((fn [v] (str/split v #"\n"))) | |
(map (fn [v] | |
(let [[_ inst n] (re-find #"(\w)(\d+)" v)] | |
[inst (Long/parseLong n)]))))) | |
(def initial-state {:dir "E" | |
"S" 0 | |
"N" 0 | |
"E" 0 | |
"W" 0}) | |
(def rotate {"L" {90 {"N" "W" | |
"W" "S" | |
"S" "E" | |
"E" "N"} | |
180 {"N" "S" | |
"S" "N" | |
"W" "E" | |
"E" "W"} | |
270 {"N" "E" | |
"W" "N" | |
"S" "W" | |
"E" "S"}} | |
"R" {90 {"N" "E" | |
"E" "S" | |
"S" "W" | |
"W" "N"} | |
180 {"N" "S" | |
"S" "N" | |
"W" "E" | |
"E" "W"} | |
270 {"N" "W" | |
"W" "S" | |
"S" "E" | |
"E" "N"}}}) | |
(def state (reduce | |
(fn [{dir :dir :as state} [instraction n]] | |
(case instraction | |
"F" (update state dir + n) | |
("L" "R") (assoc state :dir (get-in rotate [instraction n dir])) | |
("N" "S" "W" "E") (update state instraction + n))) | |
initial-state | |
data)) | |
(+ (Math/abs (- (state "N") (state "S"))) | |
(Math/abs (- (state "E") (state "W")))) | |
;; part 2 | |
;; | |
(def data (->> (slurp "input12.txt") | |
((fn [v] (str/split v #"\n"))) | |
(map (fn [v] | |
(let [[_ inst n] (re-find #"(\w)(\d+)" v)] | |
[inst (Long/parseLong n)]))))) | |
(defn rotate [{{E "E" W "W" S "S" N "N"} :waypoint :as state} | |
dir | |
degree] | |
(assoc state :waypoint (get-in {"L" {90 {"N" E | |
"W" N | |
"S" W | |
"E" S} | |
180 {"N" S | |
"S" N | |
"W" E | |
"E" W} | |
270 {"N" W | |
"E" N | |
"S" E | |
"W" S}} | |
"R" {90 {"N" W | |
"E" N | |
"S" E | |
"W" S} | |
180 {"N" S | |
"S" N | |
"W" E | |
"E" W} | |
270 {"N" E | |
"W" N | |
"S" W | |
"E" S}}} | |
[dir degree]))) | |
(rotate initial-state "R" 90) | |
(def initial-state {:waypoint {"E" 10 | |
"N" 1 | |
"W" 0 | |
"S" 0} | |
"S" 0 | |
"N" 0 | |
"E" 0 | |
"W" 0}) | |
(defn move-forward [{waypoint :waypoint :as from} times] | |
(reduce (fn [state [dir n]] (update state dir + (* n times))) | |
from | |
waypoint)) | |
(move-forward initial-state 10) | |
(def state (reduce | |
(fn [state [instruction n]] | |
(case instruction | |
"F" (move-forward state n) | |
("L" "R") (rotate state instruction n) | |
("N" "S" "W" "E") (update-in state [:waypoint instruction] + n))) | |
initial-state | |
data)) | |
(+ (Math/abs (- (state "N") (state "S"))) | |
(Math/abs (- (state "E") (state "W")))) | |
:a) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment