-
Notifications
You must be signed in to change notification settings - Fork 1
/
common.clj
133 lines (110 loc) · 3.89 KB
/
common.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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
(ns aoc.common
(:require
[blancas.kern.core :refer [<$> <*> <|> any-char bind dec-num digit
get-position many many1 new-line* optional
return sep-by space sym* value]]
[clojure.java.io :refer [file]]
[clojure.pprint :refer [pprint]]
[clojure.string :as str])
(:import
[java.awt Color]
[java.awt.image BufferedImage]
[java.io File]
[javax.imageio ImageIO]))
(defn read-input-str [& {:keys [test use-test] :or {test nil use-test true}}]
(if (and use-test (some? test))
test
(-> *file*
file
.getParent
(file "input.txt")
slurp)))
(defn read-input [& {:keys [split-with test use-test] :or {split-with #"\n" test nil use-test true}}]
(->
(read-input-str :test test :use-test use-test)
(str/split split-with)))
(defn parse-input [parser & {:keys [test use-test state] :or {test nil use-test true state {}}}]
(value parser
(read-input-str :test test :use-test use-test) nil state))
(def get-img-dir
(memoize
(fn [f]
(let [dir (-> f
file
.getParent
(file "img"))]
(.mkdir dir)
(.toString dir)))))
(defn draw-image [w h i draw-fn]
(let [img (BufferedImage. w h BufferedImage/TYPE_INT_ARGB)
g (.getGraphics img)
dir (get-img-dir *file*)]
(.setColor g Color/WHITE)
(.fillRect g 0 0 w h)
(draw-fn g)
(ImageIO/write img "png" (File. (format "%s/%06d.png" dir i)))))
(defn split-to-ints [s]
(->> s
(re-seq #"-?\d+")
(map parse-long)))
(defn count-where [fn coll]
(count (filter fn coll)))
(defn zip [& lists]
(apply map (conj lists vector)))
(defn flip [f] (fn [a b] (f b a)))
(defn sum [& lists]
(apply + 0 (filter some? (flatten lists))))
(defn ++ [a b]
(cond (and (number? a) (number? b)) (+ a b)
(and (number? a) (seqable? b)) (->> b (map #(+ a %)))
(and (seqable? a) (number? b)) (->> a (map #(+ b %)))
:else (->> (zip a b) (map #(apply + %)))))
(defn -- [a b]
(++ a (if (number? b) (- b) (map - b))))
(defn ** [a b]
(cond (and (number? a) (number? b)) (* a b)
(and (number? a) (seqable? b)) (->> b (map #(* a %)))
(and (seqable? a) (number? b)) (->> a (map #(* b %)))
:else (->> (zip a b) (map #(apply * %)))))
(defn remove-index [vect idx]
(into (subvec vect 0 idx) (subvec vect (inc idx))))
(defn spy-with [f v] (pprint (f v)) v)
(def spy (partial spy-with identity))
(defn re-seq-indexed [pattern string]
(let [m (re-matcher pattern string)]
((fn step []
(when (. m find)
(cons {:match (. m group)
:start (. m start)
:end (. m end)} (lazy-seq (step))))))))
(defn numeric? [s] (re-matches #"\-?\d+" s))
(defn find-index [f coll]
(->> coll (keep-indexed #(when (f %1 %2) %1)) first))
(defn tee [fs val]
(map #(% val) fs))
(defn inclusive-range [a b]
(range (min a b) (inc (max a b))))
(defn manhattan [p1 p2]
(->> (zip p1 p2)
(map (fn [[v1 v2]] (abs (- v1 v2))))
sum))
(defn binsearch
"Returns the lowest number for which check returns true."
[check from to]
(if (= from to)
(if (check to) to nil)
(let [mid (quot (+ from to) 2)]
(if (check mid)
(recur check from mid)
(recur check (inc mid) to)))))
;; Parsers
(defn lines [p] (sep-by new-line* p))
(defn comma-or-space-sep [p] (sep-by (<|> (<*> (sym* \,) (many space))
(<*> (optional (sym* \,)) (many1 space))) p))
(def digit-num (<$> #(Character/digit % 10) digit))
(def dec-num- (<$> (fn [[d n]] (if d (- n) n)) (<*> (optional (sym* \-)) dec-num)))
(def nums (comma-or-space-sep dec-num))
(def points (<$> #(filter (fn [v] (not= \newline (first v))) %)
(many (bind [s any-char
p get-position]
(return [s (++ [(:line p) (:col p)] [-1 -2])])))))