-
Notifications
You must be signed in to change notification settings - Fork 2
/
16.clj
76 lines (64 loc) · 2.04 KB
/
16.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
(ns advent-of-code.2017.16
(:require [clojure.java.io :as io]
[clojure.string :as cs]))
(def raw-input (slurp (io/resource "data_2017/16.txt")))
(defn spin [coll n]
(let [part (- (count coll) n)
tail (subvec coll part)
head (subvec coll 0 part)]
(vec (concat tail head))))
(defn swap [coll i j]
(-> coll
(assoc i (nth coll j))
(assoc j (nth coll i))))
(defn positions [pred coll]
(keep-indexed (fn [i x] (when (pred x) i)) coll))
(defn parse-step [[typ & s]]
(let [s (apply str s)]
(case typ
\s (let [n (Integer/parseInt s)]
(fn [ps] (spin ps n)))
\x (let [idxs (->> (re-seq #"\d+" s)
(map #(Integer/parseInt %)))]
(fn [ps] (apply swap ps idxs)))
\p (let [progset (->> (re-seq #"[a-z]+" s)
(map first)
(set))]
(fn [ps] (->> (positions progset ps)
(apply swap ps)))))))
(def steps (map parse-step (cs/split raw-input #",")))
(def programs [\a \b \c \d \e \f \g \h \i \j \k \l \m \n \o \p])
;; solve part one
(apply str
(reduce
#(%2 %1)
programs
steps))
;; After admitting defeat w/brute force I knew I had to
;; be missing a ~key observation~. Given the nature of the
;; permissible moves, there was probably a pattern/cycle
;; repeated many times over 1B iterations...
(defn take-while-distinct [coll]
(let [seen (volatile! #{})]
(take-while (fn [v]
(if (@seen v)
false
(vswap! seen conj v)))
coll)))
(def cycle-len
(->> (reductions
#(%2 %1)
programs
(cycle steps))
(take-while-distinct)
(count)))
;; solve part two
(apply str
(reduce
#(%2 %1)
programs
;; problem is now tractable since we know the cycle length
;; and can skip (almost all the way) to the end
(->> (cycle steps)
(take (* (rem 1000000000 cycle-len)
(count steps))))))