+13
.gitignore
+13
.gitignore
+24
CHANGELOG.md
+24
CHANGELOG.md
···
1
+
# Change Log
2
+
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
3
+
4
+
## [Unreleased]
5
+
### Changed
6
+
- Add a new arity to `make-widget-async` to provide a different widget shape.
7
+
8
+
## [0.1.1] - 2025-12-01
9
+
### Changed
10
+
- Documentation on how to make the widgets.
11
+
12
+
### Removed
13
+
- `make-widget-sync` - we're all async, all the time.
14
+
15
+
### Fixed
16
+
- Fixed widget maker to keep working when daylight savings switches over.
17
+
18
+
## 0.1.0 - 2025-12-01
19
+
### Added
20
+
- Files from the new template.
21
+
- Widget maker public API - `make-widget-sync`.
22
+
23
+
[Unreleased]: https://sourcehost.site/your-name/aoc2025/compare/0.1.1...HEAD
24
+
[0.1.1]: https://sourcehost.site/your-name/aoc2025/compare/0.1.0...0.1.1
+280
LICENSE
+280
LICENSE
···
1
+
Eclipse Public License - v 2.0
2
+
3
+
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
4
+
PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
5
+
OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6
+
7
+
1. DEFINITIONS
8
+
9
+
"Contribution" means:
10
+
11
+
a) in the case of the initial Contributor, the initial content
12
+
Distributed under this Agreement, and
13
+
14
+
b) in the case of each subsequent Contributor:
15
+
i) changes to the Program, and
16
+
ii) additions to the Program;
17
+
where such changes and/or additions to the Program originate from
18
+
and are Distributed by that particular Contributor. A Contribution
19
+
"originates" from a Contributor if it was added to the Program by
20
+
such Contributor itself or anyone acting on such Contributor's behalf.
21
+
Contributions do not include changes or additions to the Program that
22
+
are not Modified Works.
23
+
24
+
"Contributor" means any person or entity that Distributes the Program.
25
+
26
+
"Licensed Patents" mean patent claims licensable by a Contributor which
27
+
are necessarily infringed by the use or sale of its Contribution alone
28
+
or when combined with the Program.
29
+
30
+
"Program" means the Contributions Distributed in accordance with this
31
+
Agreement.
32
+
33
+
"Recipient" means anyone who receives the Program under this Agreement
34
+
or any Secondary License (as applicable), including Contributors.
35
+
36
+
"Derivative Works" shall mean any work, whether in Source Code or other
37
+
form, that is based on (or derived from) the Program and for which the
38
+
editorial revisions, annotations, elaborations, or other modifications
39
+
represent, as a whole, an original work of authorship.
40
+
41
+
"Modified Works" shall mean any work in Source Code or other form that
42
+
results from an addition to, deletion from, or modification of the
43
+
contents of the Program, including, for purposes of clarity any new file
44
+
in Source Code form that contains any contents of the Program. Modified
45
+
Works shall not include works that contain only declarations,
46
+
interfaces, types, classes, structures, or files of the Program solely
47
+
in each case in order to link to, bind by name, or subclass the Program
48
+
or Modified Works thereof.
49
+
50
+
"Distribute" means the acts of a) distributing or b) making available
51
+
in any manner that enables the transfer of a copy.
52
+
53
+
"Source Code" means the form of a Program preferred for making
54
+
modifications, including but not limited to software source code,
55
+
documentation source, and configuration files.
56
+
57
+
"Secondary License" means either the GNU General Public License,
58
+
Version 2.0, or any later versions of that license, including any
59
+
exceptions or additional permissions as identified by the initial
60
+
Contributor.
61
+
62
+
2. GRANT OF RIGHTS
63
+
64
+
a) Subject to the terms of this Agreement, each Contributor hereby
65
+
grants Recipient a non-exclusive, worldwide, royalty-free copyright
66
+
license to reproduce, prepare Derivative Works of, publicly display,
67
+
publicly perform, Distribute and sublicense the Contribution of such
68
+
Contributor, if any, and such Derivative Works.
69
+
70
+
b) Subject to the terms of this Agreement, each Contributor hereby
71
+
grants Recipient a non-exclusive, worldwide, royalty-free patent
72
+
license under Licensed Patents to make, use, sell, offer to sell,
73
+
import and otherwise transfer the Contribution of such Contributor,
74
+
if any, in Source Code or other form. This patent license shall
75
+
apply to the combination of the Contribution and the Program if, at
76
+
the time the Contribution is added by the Contributor, such addition
77
+
of the Contribution causes such combination to be covered by the
78
+
Licensed Patents. The patent license shall not apply to any other
79
+
combinations which include the Contribution. No hardware per se is
80
+
licensed hereunder.
81
+
82
+
c) Recipient understands that although each Contributor grants the
83
+
licenses to its Contributions set forth herein, no assurances are
84
+
provided by any Contributor that the Program does not infringe the
85
+
patent or other intellectual property rights of any other entity.
86
+
Each Contributor disclaims any liability to Recipient for claims
87
+
brought by any other entity based on infringement of intellectual
88
+
property rights or otherwise. As a condition to exercising the
89
+
rights and licenses granted hereunder, each Recipient hereby
90
+
assumes sole responsibility to secure any other intellectual
91
+
property rights needed, if any. For example, if a third party
92
+
patent license is required to allow Recipient to Distribute the
93
+
Program, it is Recipient's responsibility to acquire that license
94
+
before distributing the Program.
95
+
96
+
d) Each Contributor represents that to its knowledge it has
97
+
sufficient copyright rights in its Contribution, if any, to grant
98
+
the copyright license set forth in this Agreement.
99
+
100
+
e) Notwithstanding the terms of any Secondary License, no
101
+
Contributor makes additional grants to any Recipient (other than
102
+
those set forth in this Agreement) as a result of such Recipient's
103
+
receipt of the Program under the terms of a Secondary License
104
+
(if permitted under the terms of Section 3).
105
+
106
+
3. REQUIREMENTS
107
+
108
+
3.1 If a Contributor Distributes the Program in any form, then:
109
+
110
+
a) the Program must also be made available as Source Code, in
111
+
accordance with section 3.2, and the Contributor must accompany
112
+
the Program with a statement that the Source Code for the Program
113
+
is available under this Agreement, and informs Recipients how to
114
+
obtain it in a reasonable manner on or through a medium customarily
115
+
used for software exchange; and
116
+
117
+
b) the Contributor may Distribute the Program under a license
118
+
different than this Agreement, provided that such license:
119
+
i) effectively disclaims on behalf of all other Contributors all
120
+
warranties and conditions, express and implied, including
121
+
warranties or conditions of title and non-infringement, and
122
+
implied warranties or conditions of merchantability and fitness
123
+
for a particular purpose;
124
+
125
+
ii) effectively excludes on behalf of all other Contributors all
126
+
liability for damages, including direct, indirect, special,
127
+
incidental and consequential damages, such as lost profits;
128
+
129
+
iii) does not attempt to limit or alter the recipients' rights
130
+
in the Source Code under section 3.2; and
131
+
132
+
iv) requires any subsequent distribution of the Program by any
133
+
party to be under a license that satisfies the requirements
134
+
of this section 3.
135
+
136
+
3.2 When the Program is Distributed as Source Code:
137
+
138
+
a) it must be made available under this Agreement, or if the
139
+
Program (i) is combined with other material in a separate file or
140
+
files made available under a Secondary License, and (ii) the initial
141
+
Contributor attached to the Source Code the notice described in
142
+
Exhibit A of this Agreement, then the Program may be made available
143
+
under the terms of such Secondary Licenses, and
144
+
145
+
b) a copy of this Agreement must be included with each copy of
146
+
the Program.
147
+
148
+
3.3 Contributors may not remove or alter any copyright, patent,
149
+
trademark, attribution notices, disclaimers of warranty, or limitations
150
+
of liability ("notices") contained within the Program from any copy of
151
+
the Program which they Distribute, provided that Contributors may add
152
+
their own appropriate notices.
153
+
154
+
4. COMMERCIAL DISTRIBUTION
155
+
156
+
Commercial distributors of software may accept certain responsibilities
157
+
with respect to end users, business partners and the like. While this
158
+
license is intended to facilitate the commercial use of the Program,
159
+
the Contributor who includes the Program in a commercial product
160
+
offering should do so in a manner which does not create potential
161
+
liability for other Contributors. Therefore, if a Contributor includes
162
+
the Program in a commercial product offering, such Contributor
163
+
("Commercial Contributor") hereby agrees to defend and indemnify every
164
+
other Contributor ("Indemnified Contributor") against any losses,
165
+
damages and costs (collectively "Losses") arising from claims, lawsuits
166
+
and other legal actions brought by a third party against the Indemnified
167
+
Contributor to the extent caused by the acts or omissions of such
168
+
Commercial Contributor in connection with its distribution of the Program
169
+
in a commercial product offering. The obligations in this section do not
170
+
apply to any claims or Losses relating to any actual or alleged
171
+
intellectual property infringement. In order to qualify, an Indemnified
172
+
Contributor must: a) promptly notify the Commercial Contributor in
173
+
writing of such claim, and b) allow the Commercial Contributor to control,
174
+
and cooperate with the Commercial Contributor in, the defense and any
175
+
related settlement negotiations. The Indemnified Contributor may
176
+
participate in any such claim at its own expense.
177
+
178
+
For example, a Contributor might include the Program in a commercial
179
+
product offering, Product X. That Contributor is then a Commercial
180
+
Contributor. If that Commercial Contributor then makes performance
181
+
claims, or offers warranties related to Product X, those performance
182
+
claims and warranties are such Commercial Contributor's responsibility
183
+
alone. Under this section, the Commercial Contributor would have to
184
+
defend claims against the other Contributors related to those performance
185
+
claims and warranties, and if a court requires any other Contributor to
186
+
pay any damages as a result, the Commercial Contributor must pay
187
+
those damages.
188
+
189
+
5. NO WARRANTY
190
+
191
+
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
192
+
PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
193
+
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
194
+
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
195
+
TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
196
+
PURPOSE. Each Recipient is solely responsible for determining the
197
+
appropriateness of using and distributing the Program and assumes all
198
+
risks associated with its exercise of rights under this Agreement,
199
+
including but not limited to the risks and costs of program errors,
200
+
compliance with applicable laws, damage to or loss of data, programs
201
+
or equipment, and unavailability or interruption of operations.
202
+
203
+
6. DISCLAIMER OF LIABILITY
204
+
205
+
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
206
+
PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
207
+
SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
208
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
209
+
PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
210
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
211
+
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
212
+
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
213
+
POSSIBILITY OF SUCH DAMAGES.
214
+
215
+
7. GENERAL
216
+
217
+
If any provision of this Agreement is invalid or unenforceable under
218
+
applicable law, it shall not affect the validity or enforceability of
219
+
the remainder of the terms of this Agreement, and without further
220
+
action by the parties hereto, such provision shall be reformed to the
221
+
minimum extent necessary to make such provision valid and enforceable.
222
+
223
+
If Recipient institutes patent litigation against any entity
224
+
(including a cross-claim or counterclaim in a lawsuit) alleging that the
225
+
Program itself (excluding combinations of the Program with other software
226
+
or hardware) infringes such Recipient's patent(s), then such Recipient's
227
+
rights granted under Section 2(b) shall terminate as of the date such
228
+
litigation is filed.
229
+
230
+
All Recipient's rights under this Agreement shall terminate if it
231
+
fails to comply with any of the material terms or conditions of this
232
+
Agreement and does not cure such failure in a reasonable period of
233
+
time after becoming aware of such noncompliance. If all Recipient's
234
+
rights under this Agreement terminate, Recipient agrees to cease use
235
+
and distribution of the Program as soon as reasonably practicable.
236
+
However, Recipient's obligations under this Agreement and any licenses
237
+
granted by Recipient relating to the Program shall continue and survive.
238
+
239
+
Everyone is permitted to copy and distribute copies of this Agreement,
240
+
but in order to avoid inconsistency the Agreement is copyrighted and
241
+
may only be modified in the following manner. The Agreement Steward
242
+
reserves the right to publish new versions (including revisions) of
243
+
this Agreement from time to time. No one other than the Agreement
244
+
Steward has the right to modify this Agreement. The Eclipse Foundation
245
+
is the initial Agreement Steward. The Eclipse Foundation may assign the
246
+
responsibility to serve as the Agreement Steward to a suitable separate
247
+
entity. Each new version of the Agreement will be given a distinguishing
248
+
version number. The Program (including Contributions) may always be
249
+
Distributed subject to the version of the Agreement under which it was
250
+
received. In addition, after a new version of the Agreement is published,
251
+
Contributor may elect to Distribute the Program (including its
252
+
Contributions) under the new version.
253
+
254
+
Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
255
+
receives no rights or licenses to the intellectual property of any
256
+
Contributor under this Agreement, whether expressly, by implication,
257
+
estoppel or otherwise. All rights in the Program not expressly granted
258
+
under this Agreement are reserved. Nothing in this Agreement is intended
259
+
to be enforceable by any entity that is not a Contributor or Recipient.
260
+
No third-party beneficiary rights are created under this Agreement.
261
+
262
+
Exhibit A - Form of Secondary Licenses Notice
263
+
264
+
"This Source Code may also be made available under the following
265
+
Secondary Licenses when the conditions for such availability set forth
266
+
in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public
267
+
License as published by the Free Software Foundation, either version 2
268
+
of the License, or (at your option) any later version, with the GNU
269
+
Classpath Exception which is available at
270
+
https://www.gnu.org/software/classpath/license.html."
271
+
272
+
Simply including a copy of this Agreement, including this Exhibit A
273
+
is not sufficient to license the Source Code under Secondary Licenses.
274
+
275
+
If it is not possible or desirable to put the notice in a particular
276
+
file, then You may include the notice in a location (such as a LICENSE
277
+
file in a relevant directory) where a recipient would be likely to
278
+
look for such a notice.
279
+
280
+
You may add additional accurate notices of copyright ownership.
+44
README.md
+44
README.md
···
1
+
# aoc2025
2
+
3
+
FIXME: description
4
+
5
+
## Installation
6
+
7
+
Download from http://example.com/FIXME.
8
+
9
+
## Usage
10
+
11
+
FIXME: explanation
12
+
13
+
$ java -jar aoc2025-0.1.0-standalone.jar [args]
14
+
15
+
## Options
16
+
17
+
FIXME: listing of options this app accepts.
18
+
19
+
## Examples
20
+
21
+
...
22
+
23
+
### Bugs
24
+
25
+
...
26
+
27
+
### Any Other Sections
28
+
### That You Think
29
+
### Might be Useful
30
+
31
+
## License
32
+
33
+
Copyright © 2025 FIXME
34
+
35
+
This program and the accompanying materials are made available under the
36
+
terms of the Eclipse Public License 2.0 which is available at
37
+
http://www.eclipse.org/legal/epl-2.0.
38
+
39
+
This Source Code may also be made available under the following Secondary
40
+
Licenses when the conditions for such availability set forth in the Eclipse
41
+
Public License, v. 2.0 are satisfied: GNU General Public License as published by
42
+
the Free Software Foundation, either version 2 of the License, or (at your
43
+
option) any later version, with the GNU Classpath Exception which is available
44
+
at https://www.gnu.org/software/classpath/license.html.
+3
doc/intro.md
+3
doc/intro.md
+27
flake.lock
+27
flake.lock
···
1
+
{
2
+
"nodes": {
3
+
"nixpkgs": {
4
+
"locked": {
5
+
"lastModified": 1764517877,
6
+
"narHash": "sha256-pp3uT4hHijIC8JUK5MEqeAWmParJrgBVzHLNfJDZxg4=",
7
+
"owner": "NixOS",
8
+
"repo": "nixpkgs",
9
+
"rev": "2d293cbfa5a793b4c50d17c05ef9e385b90edf6c",
10
+
"type": "github"
11
+
},
12
+
"original": {
13
+
"owner": "NixOS",
14
+
"ref": "nixos-unstable",
15
+
"repo": "nixpkgs",
16
+
"type": "github"
17
+
}
18
+
},
19
+
"root": {
20
+
"inputs": {
21
+
"nixpkgs": "nixpkgs"
22
+
}
23
+
}
24
+
},
25
+
"root": "root",
26
+
"version": 7
27
+
}
+24
flake.nix
+24
flake.nix
···
1
+
{
2
+
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
3
+
4
+
outputs = {nixpkgs, ...}: let
5
+
forAllSystems =
6
+
function:
7
+
nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (
8
+
system: function nixpkgs.legacyPackages.${system}
9
+
);
10
+
in {
11
+
systems = [ "x86_64-linux" ];
12
+
13
+
14
+
packages = forAllSystems (pkgs: {
15
+
default = pkgs.mkShell {
16
+
nativeBuildInputs = with pkgs; [
17
+
babashka
18
+
clojure
19
+
leiningen
20
+
];
21
+
};
22
+
});
23
+
};
24
+
}
+10
project.clj
+10
project.clj
···
1
+
(defproject aoc2025 "0.1.0-SNAPSHOT"
2
+
:description "FIXME: write description"
3
+
:url "http://example.com/FIXME"
4
+
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
5
+
:url "https://www.eclipse.org/legal/epl-2.0/"}
6
+
:dependencies [[org.clojure/clojure "1.11.1"]]
7
+
:main ^:skip-aot aoc2025.core
8
+
:target-path "target/%s"
9
+
:profiles {:uberjar {:aot :all
10
+
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})
+7
src/aoc2025/core.clj
+7
src/aoc2025/core.clj
+138
src/aoc2025/util.clj
+138
src/aoc2025/util.clj
···
1
+
(ns aoc2025.util
2
+
(:require [clojure.string :as s]
3
+
[clojure.walk :as walk]))
4
+
5
+
(defn read-file
6
+
"Reads fname as a resource into a list of strings of the given resource, split by newlines"
7
+
[fname]
8
+
(->> fname clojure.java.io/resource slurp s/split-lines))
9
+
10
+
(defn gridify
11
+
"Takes array of strings and turns it into a 2d grid of chars"
12
+
[rows]
13
+
(mapv vec rows))
14
+
15
+
(defn transpose [m]
16
+
(apply mapv vector m))
17
+
18
+
(defn parse-int [s] (Integer/parseInt s))
19
+
(defn parse-long [s] (Long/parseLong s))
20
+
(defn parse-ints [st] (map parse-int (s/split st #"\s+")))
21
+
22
+
(def reverse-str
23
+
"Just reverses a string into a string"
24
+
(comp (partial apply str) reverse))
25
+
26
+
(defn indexes-of
27
+
"Returns the indexes of coll where pred-or-val returns true. Values are compared using =, using a function will use that as the predicate instead of ="
28
+
[pred-or-val coll]
29
+
(if (fn? pred-or-val)
30
+
(keep-indexed #(when (pred-or-val %2) %1) coll)
31
+
(keep-indexed #(when (= %2 pred-or-val) %1) coll)))
32
+
33
+
(defn middle
34
+
"Get the middle element of a collection"
35
+
([[a b c & rs :as coll]]
36
+
(if rs
37
+
(nth coll (-> coll count dec (/ 2)))
38
+
b)))
39
+
40
+
(def pairs "Make pairs of a collection" (partial partition 2 1))
41
+
42
+
(def diffs
43
+
"Calculate the differences of each step of a sequence of numbers"
44
+
(comp (partial map (partial apply -))
45
+
pairs))
46
+
47
+
(defn re-named-groups
48
+
"Returns map of the named groups in re to the matches in s"
49
+
[re s]
50
+
(let [group-names (->> re str
51
+
(re-seq #"(?:\(\?<([^>]+)>)")
52
+
(map #(-> % second keyword)))
53
+
[_ & matches] (re-matches re s)]
54
+
(zipmap group-names matches)))
55
+
56
+
(defn -sym?->seq
57
+
"Returns (seq form) if form is a sequence and the first element is sym, else nil"
58
+
[sym form]
59
+
(let [match? (every-pred sequential? #(= sym (first %)))]
60
+
(if (match? form) (seq form) nil)))
61
+
62
+
(defn get-all
63
+
"Return all elements of ks as a key in m"
64
+
[m ks]
65
+
(for [k ks]
66
+
(get m k)))
67
+
68
+
(defn divisible?
69
+
([b] #(divisible? % b))
70
+
([a b] (zero? (mod a b))))
71
+
72
+
(defn gcd
73
+
"Calculates the greatest common divisor of a and b"
74
+
([a b]
75
+
(if (zero? b)
76
+
a
77
+
(let [[a b] (sort > [a b])]
78
+
(recur b (rem a b)))))
79
+
([a b & xs] (reduce gcd (gcd a b) xs)))
80
+
81
+
(defn lcm
82
+
"Calculates the least common divisor of a and b"
83
+
([a b]
84
+
(/ (abs (* a b))
85
+
(gcd a b)))
86
+
([a b & xs] (reduce lcm (lcm a b) xs)))
87
+
88
+
(def split-at-space #(clojure.string/split % #" "))
89
+
90
+
(defn take-until [pred coll]
91
+
(concat
92
+
(take-while (complement pred) coll)
93
+
(list (first (filter pred coll)))))
94
+
95
+
(def Vector2D [:tuple :int :int])
96
+
97
+
(defn vec- [[a1 b1] [a2 b2]] [(- a1 a2) (- b1 b2)])
98
+
99
+
(defn vec+ [[a1 b1] [a2 b2]] [(+ a2 a1) (+ b2 b1)])
100
+
101
+
(defn determinant [[y1 x1] [y2 x2]] (- (* y1 x2) (* x1 y2)))
102
+
103
+
(defn drop-nth
104
+
"Returns coll without the nth element (lazily too, I think?)"
105
+
[n coll]
106
+
(lazy-cat (take n coll) (drop (inc n) coll)))
107
+
108
+
(defn ordered?
109
+
"Returns non-nill if nums are all in an increasing or decreasing order"
110
+
[coll]
111
+
(or (apply < coll) (apply > coll)))
112
+
113
+
(defn splarse
114
+
"Splits line with re and parses all longs out of the resulting split. Single argument returns a curried call with the specified re"
115
+
([re] (partial splarse re))
116
+
([re line]
117
+
(->> (s/split line re) (mapv parse-long))))
118
+
119
+
(defn between?
120
+
"Defaults to inclusive checking (0 with a min of 0 and max of 10 would return true)"
121
+
([min-value max-value] #(between? % min-value max-value >=))
122
+
([min-value max-value pred] #(between? % min-value max-value pred))
123
+
([x min-value max-value pred] (and (pred x min-value) (pred max-value x))))
124
+
125
+
(defn invert-map
126
+
"Inverts map, joining duplicate keys as a sequence of values in the result"
127
+
[m]
128
+
(-> (group-by second m) (update-vals (partial mapv first))))
129
+
130
+
(def adj4 [[0 1] [0 -1] [1 0] [-1 0]])
131
+
(def adj8 (conj adj4 [1 1] [1 -1] [-1 1] [-1 -1]))
132
+
133
+
(defn adj+
134
+
"Returns vector of all adjacent points. Defaults to 8-point, can be passed :4 to only return cardinals"
135
+
([p] (adj+ :8 p))
136
+
([t p]
137
+
(let [tm {:4 adj4 :8 adj8}]
138
+
(mapv #(vec+ p %) (get tm t)))))