This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-12-04
Channels
- # adventofcode (129)
- # announcements (1)
- # babashka (7)
- # beginners (30)
- # calva (42)
- # cider (2)
- # clj-commons (2)
- # clj-on-windows (27)
- # clj-yaml (4)
- # clojure (69)
- # clojure-belgium (4)
- # clojure-europe (5)
- # clojure-norway (4)
- # clr (1)
- # css (3)
- # datomic (19)
- # dev-tooling (2)
- # events (1)
- # humbleui (1)
- # hyperfiddle (17)
- # introduce-yourself (4)
- # java (1)
- # joyride (3)
- # kaocha (1)
- # lsp (4)
- # malli (10)
- # mount (1)
- # nbb (34)
- # off-topic (37)
- # pathom (1)
- # ring (4)
- # tools-deps (12)
A demo of using Clojure to solve Advent of Code problems in your editor, using VS Code + #joyride. https://www.youtube.com/watch?v=0rJvOtbJDyI
And the starter template project is a bit updated as well: https://github.com/PEZ/joyride-aoc-2022
;; 202204
(let [d (->> (slurp "src/y2022/input202204")
(re-seq #"\d+")
(map parse-long)
(partition 4))
f (fn [[a1 a2 b1 b2]]
(or (<= a1 b1 b2 a2)
(<= b1 a1 a2 b2)))
g (fn [[a1 a2 b1 b2]]
(or (<= a1 b2 a2)
(<= b1 a2 b2)))]
(map #(count (filter % d)) [f g]))
;; (464 770)
(def input
(->> (util/load-lines "resources/day04.data")
(map #(re-seq #"\d+" %))
(map util/parse-ints)))
;; Part 1
(defn fully-contains? [[a b c d]]
(or (<= a c d b)
(<= c a b d)))
(count (filter fully-contains? input)) ;; 487
;; Part 2
(defn overlap? [[a b c d]] (and (<= a d) (<= c b)))
(count (filter overlap? input)) ;; 849
https://github.com/abyala/advent-2022-clojure/blob/main/src/advent_2022_clojure/day04.clj looks similar to most of yours, but as usual I wrote a https://github.com/abyala/advent-2022-clojure/blob/main/docs/day04.md to explain it for the newbies!
https://github.com/jantorestolsvik/advent-of-code-2022/blob/main/src/day04.clj
After the initial impl, I tried to write a fast non-allocating one, but got a measly 8.1x speedup for a trememdous readability-cost:
;; 988.65µs (+- 54.56µs)
(defn day4 [fs]
(let [xs (->> (re-seq #"(?:(\d+)-(\d+),(\d+)-(\d+)\n)" fs)
(mapv #(mapv parse-long (rest %))))
count-by #(transduce
(comp (filter %) (map (constantly 1)))
+ xs)]
[(count-by (fn [[a b x y]] (or (<= x a b y) (<= a x y b))))
(count-by (fn [[a b x y]] (and (>= y a) (<= x b))))]))
;; 121.68µs (+- 7.01µs)
(defn day4b [^String fs]
(let [add (fn [^long x ^Character c]
(+ (- (int c) 48) (* 10 x)))
n (count fs)]
(loop [i 0, state 0, p1 0, p2 0
a 0, b 0, x 0, y 0]
(if (= i n) [p1 p2]
(let [c (.charAt fs i)]
(case c
\newline
(recur (inc i) 0
(if (or (<= x a b y) (<= a x y b))
(inc p1) p1)
(if (and (>= y a) (<= x b))
(inc p2) p2)
0 0 0 0)
(\- \,)
(recur (inc i) (inc state) p1 p2 a b x y)
(case state
0 (recur (inc i) state p1 p2 (long (add a c)) b x y)
1 (recur (inc i) state p1 p2 a (long (add b c)) x y)
2 (recur (inc i) state p1 p2 a b (long (add x c)) y)
(recur (inc i) state p1 p2 a b x (long (add y c))))))))))
(defn parse [line]
(->> line (re-seq #"\d+") (map parse-long)))
(defn fully? [[A B X Y]]
(or (<= A X Y B) (<= X A B Y)))
(defn partially? [[A B X Y]]
(or (<= X A Y) (<= A X B)))
(defn -main [day]
(let [input (map parse (file->lines day))
overlaps (fn [f] (count (filter true? (map f input))))]
{:part1 (overlaps fully?)
:part2 (overlaps partially?)}))
Oh, filter true?
is totally redundant here!
I guess there are two types of solutions. 1. comparing numbers of start and end ranges 2. using sets I will always use sets for these types of problems. Feels more flexible and better describable.
https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day04.clj
I'm not an algo expert, but the solution with sets is much less optimal, because it... generates sets (time proportional to the sizes of the ranges and space proportional to the set size). This is contrary to the golden rule of algos: Don't compute what is not needed.
Of cause I’m not talking about performance. I was talking about what kind of approach comes more naturally.
hmm, another 'comparing ranges' answer: https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d4.clj
obvious in hindsight that parsing things into [[a1 b1] [a2 b2]]
pairs made things less neat!
same solution as above. Only thing interesting was my helper from previous years: (def input (f/read-ranges "2022/d04.txt"))
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d04.clj
(defn parse-assignment [a]
(->> (string/split a #"-|,")
(map #(Integer/parseInt %))
(partition 2)
(map (fn [[a b]] (range a (inc b))))
(map set)))
(defn subset? [[a b]]
(or (clojure.set/subset? a b)
(clojure.set/subset? b a)))
(defn intersection? [[a b]]
(not (empty? (clojure.set/intersection a b))))
(defn day4 []
(let [in (slurp "input/day-4-input-1.txt")
assignments (map parse-assignment (string/split-lines in))
count-assignments #(count (filter true? %))]
{:part1 (count-assignments (map subset? assignments))
:part2 (count-assignments (map intersection? assignments))}))
@thierry572 not-empty would return nil for empty sets. I would have to change my (filter true?) to something else. What's the shortest way of achieving your suggestion?
I would have to change my subset? function to return nil. It would be change for change. I don't see an immediate benefit.
More then one way to reach Rome with Clojure (or any other language for that matter) :rolling_on_the_floor_laughing:
This is one of those days that I'm going to now look at how other people did the overlap and contains and realise my solution is dumb... https://github.com/stuartstein777/clj-advent-of-code/blob/master/src/stuartstein777/2022/day4.clj
I too considered sets, that does feel more natural to me, but then thought it was wasteful to generate all thsoe numbers
This was one of the best solutions i've seen. I always forget that these functions can take more than 2 arities.
(defn fully? [[A B X Y]]
(or (<= A X Y B) (<= X A B Y)))
(defn partially? [[A B X Y]]
(or (<= X A Y) (<= A X B)))
@UK00KCK6D Using not=
(defn intersection? [[a b]]
(not= #{} (set/intersection a b)))
@U013YN3T4DA I started out with sets aswell but ended up using a for loop on the sets with data/diff
https://github.com/mducharm/advent_of_code_2022/blob/main/src/advent_of_code/day_04.clj
I was rereading the solution of a coworker of mine, and I can see now that our overlaps?
or partially-overlaps?
function can actually be simplified to only compare two terms.
(defn overlaps? [[a b c d]]
(and (<= a d) (<= c b)))
seems like that would also return true
for partial overlaps, e.g. (overlaps? [1 3 2 4])
?
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_04_cleanup.clj
https://github.com/Ramblurr/advent-of-code-2022/blob/main/src/aoc/day04.clj#L6-L45 Not very memory efficient, but using range and sets made this day's quite fun
the advent of transducers continues:
(defn count-filtered [data pred]
(count
(sequence
(comp (map #(str/split % #","))
cat
(map #(str/split % #"-"))
cat
(map parse-long)
(partition-all 4)
(filter pred))
data)))
(def input (-> "adventofcode2022/day4.txt"
io/resource
slurp
str/split-lines))
(comment
;; part 1
(count-filtered input (fn [[a b c d]]
(or (<= a c d b)
(<= c a b d))))
;; part 2
(count-filtered input (fn [[a b c d]]
(or (<= a c b)
(<= a d b)
(<= c a d)
(<= c b d)))))
Here is mine: https://github.clerk.garden/formsandlines/aoc2022-clojure/commit/c55225cae5766f5c77a35a0002021c0cb5ca2024/src/advent_of_clerk/day_04.html I made an explorative chart at the end to see if there are any interesting patterns in the intersection data (not really 😕).
https://github.com/nooga/aoc2022/blob/master/day4.lg
(ns day4)
(defn parse [line]
(map #(map parse-long (split % "-")) (split line ",")))
(def data (->> "input/day4.txt" slurp lines (map parse)))
(defn contain? [[a b] [c d]]
(or (and (>= c a) (<= d b)) (and (>= a c) (<= b d))))
(defn in? [a b c] (and (>= b a) (<= b c)))
(defn overlap? [[a b] [c d]]
(or (in? a c b) (in? a d b) (in? c a d) (in? c b d)))
(defn solve [f]
(->> data (map (partial apply f)) (filter identity) count))
(println "1:" (solve contain?))
(println "2:" (solve overlap?))
(ns day-04
(:require [clojure.set :refer [subset?]]))
(defn input []
(for [line (re-seq #".+" (slurp "../day_04.data"))
:let [[a b c d] (map parse-long (re-seq #"\d+" line))]]
[(set (range a (inc b))) (set (range c (inc d)))]))
(defn count-matching [f]
(count (filter #(apply f %) (input))))
(defn solution-1 []
(count-matching #(or (subset? %1 %2) (subset? %2 %1))))
(defn solution-2 []
(count-matching #(or (some %1 %2) (some %2 %1))))
(ns aoc2022.day4
(:require [ :refer [resource]]
[clojure.string :as str]
[clojure.set :refer [intersection]]))
(defn data []
(->> (resource "inputs/day4.txt")
(slurp)
(str/split-lines)))
(defn complete-overlap? [[s1 e1 s2 e2]]
(or (and (<= s1 s2) (>= e1 e2))
(and (<= s2 s1) (>= e2 e1))))
(defn partial-overlap? [[s1 e1 s2 e2]]
(not (or (< e1 s2) (> s1 e2))))
(defn solution [overlap?]
(->> (data)
(map #(str/split % #","))
(map (partial map #(str/split % #"-")))
(map (fn [[[s1 e1] [s2 e2]]]
(map #(Integer/parseInt %) [s1 e1 s2 e2])))
(filter overlap?)
(count)))
(def part1 (partial solution complete-overlap?))
(def part2 (partial solution partial-overlap?))
These are amazing. It takes me longer to understand the question.
First hundred users to get the first star on Day 4:
1) Dec 04 00:00:16 max-sixty (AoC++)
2) Dec 04 00:00:32 Luke M
3) Dec 04 00:00:44 dtinth (AoC++)
4) Dec 04 00:00:55 nim-ka
Mine were 5m6s and 6m21s for the two stars resp. It took me ~2m just to read the question xDD.
I wonder how it is possible to submit the solution in 16s...
Seems almost impossible to do this in 16 seconds, it takes longer to read the questions
Too bad the answer time is counted from release of the questions and not from when you actually start with them. I am still asleep at 6am.
That's not what I'm seeing.
Assuming that getting input-data and submitting is automated to a keybinding, a question-comprehesion time of 10s and typing the solution in 6s seems possible to me. Possible, but extremely impressive of course.
With that little time though, there's no way one can read the whole text. But, here are the example-data and the bold (and glowing) question:
2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8
In how many assignment pairs does one range fully contain the other?
These are enough to understand the question, and it doesn't seem too outrageous this way.Ruby has a cover?
method on Ranges which makes it trivial, but I think for these speeds it’s AI: https://clojurians.slack.com/archives/C0GLTDB2T/p1670047249199679
I checked previous years and there were similar speeds for the 2 rounds.
Indeed @U1Z392WMQ, the leader's GitHub https://github.com/max-sixty/aoc-gpt.
There are some nice writeups from past years from folks who placed highly in the leaderboard
• https://gist.github.com/mcpower/87427528b9ba5cac6f0c679370789661 • https://kevinyap.ca/2019/12/going-fast-in-advent-of-code/ • https://blog.vero.site/post/advent-leaderboard
@coyotesqrl I really like the Clerk-generated pages. What happens if you don't put the visibility metadata before the function definitions? Do you get a list of the vars that are created when you define the function?
Yep. It's not terrible, but seeing the metadata is less noisy to me than seeing the var definitions. I could apply the metadata to the whole namespace and then change on a per-form basis as needed as well. I might do that on some days.
It'll be more useful/interesting if there are any puzzles that lend themselves to interesting accompanying visuals, assuming I can solve them and want to put in the extra effort to create visualizations.
That's cool. It's great having the puzzle text right in line, too. It's certainly making me tempted to explore it as an option.
I am using it this year but until now there was no benefit from it compared to just using the repl. It just took up more screen real estate. I hope some more visual problems will come soon.
no, I lost the motivation after a few hours of custom domains BS. But I'll look at again tonight. Want to get days 3 and 4 out of the way first.
thanks to @tylerw for the basis of the visuals. I did quite some mods but it was good not to have to worry about the correctness of the results 🙏:skin-tone-3:
Asked GPT to create a clojure program. Quite impressive the fact that it can generate something that "looks" correct.
;; define a function that checks if one range fully contains the other
(defn fully-contains [a b]
;; split the two ranges into their start and end points
(let [[a-start a-end] (map #(Integer/parseInt %) (a/split "-"))
[b-start b-end] (map #(Integer/parseInt %) (b/split "-"))]
;; check if the range a fully contains range b
(if (and (<= a-start b-start) (>= a-end b-end))
true
false)))
;; define a list of section assignment pairs
(def pairs ["2-4,6-8" "2-3,4-5" "5-7,7-9" "2-8,3-7" "6-6,4-6" "2-6,4-8"])
;; initialize a counter variable
(def counter 0)
;; iterate over all pairs of section assignments
(doseq [[i j] (for [i (range (count pairs)) j (range (inc i) (count pairs))] [i j])]
;; check if one range fully contains the other
(if (or (fully-contains (nth pairs i) (nth pairs j))
(fully-contains (nth pairs j) (nth pairs i)))
;; if it does, increment the counter variable
(inc counter)))
;; print the number of pairs where one range fully contains the other
(println counter)
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day4/sol.clj
Hey I just want to point out that using read-string
is a really good way to parse most of the input text for these problems.
(def data (-> (slurp "src/adv2022/day4/input.txt")
(string/replace "-" ",")
(read-string)
(->> (partition 2) (partition 2))))
in JS I had a horrible hack for day 1
(->> @data
str/split-lines
(map (fn [s]
(let [n (js/parseInt s)]
(when-not (js/isNaN n) n))))
(partition-by nil?)
(keep #(reduce + %)))
but this works perfectly
(->> @data
str/split-lines
(map edn/read-string)
(partition-by nil?)
(keep #(reduce + %)))
First I place delimiters in the file around the contents
[49-51,31-50
96-99,2-95
2-62,62-98
34-76,10-59
28-83,27-84
...
40-41,41-86]
This reminds me of one of my favorite clojure tricks - write data into edn from another program, then just edn/read-string
it into clojure's happy place
You don’t need to parseInt
or any of these thing just use read-string
for just about everything
I guess I should just be safe and mention the disclaimer that you shouldn’t use clojure.core/read-string
in production apps …
I used a macro for the first 3 days
(defmacro adventreader
[resource]
`(let [data# (with-open
[rdr# (io/reader ~resource)]
(doall (line-seq rdr#)))]
data#))
@bhauman why not use clojure.edn/read-string
, did you need to parse programs? (I haven't looked at the input)
@borkdude I’m just using read-string
because it’s fast and easy and part of clojure.core
. Perfect for hacking data. clojure.edn/read-string
is for real world use cases for certain.
@thierry572 read-string
parses the input returning integers, lists, vectors etc thus you can skip the parsing step
I know, I use it a lot daily, but didnt want to manipulatr the source data first :rolling_on_the_floor_laughing: just lazy, thanks for the tip tho.
I revised my babashka tasks, maybe somebody else will find them useful. Still not library ready, maybe by end of month. Right now hardcoded for my directory structure. Any feedback before make it general?
Changes:
• modernized to Babashka CLI
• tasks take optional -y YYYY -d DD
args, which default to this year and today
• bb download
: saves file locally
• bb badges
: only 1 total call to AOC instead of 1 per year, and now includes Total stars
• bb template
creates src/test stubs from Selmer templates for the day
• bb go
combo: downloads input, creates templates, and opens browser to the day’s pages (on Mac).
https://github.com/tschady/advent-of-code/blob/main/bb.edn
https://github.com/tschady/advent-of-code/blob/main/script/tasks.clj
Awesome, feel free to send a PR to advent-of-babashka under my github name and add the link to "external resources"
I'm new to pods -- tried to run bb badges
and am getting
Message: Cannot run program "/home/piotr/.local/share/.babashka/pods/repository/retrogradeorbit/bootleg/0.1.9/linux/x86_64/bootleg": error=2, No such file or directory
Threre's no bootleg
executable at the location, only manifest.edn
file. Before it crashes, it prints:
Downloading pod retrogradeorbit/bootleg (0.1.9)
Successfully installed pod retrogradeorbit/bootleg (0.1.9)
What am I missing here?@UUAKPEMJ9 Which OS is this?
@borkdude Arch Linux, x86_64
ldd /home/piotr/.local/share/.babashka/pods/repository/retrogradeorbit/bootleg/0.1.9/linux/x86_64/bootleg
?cc @U1QQJJK89 - might be good to provide a fully static musl compiled binary for bootleg
$ ldd /home/piotr/.local/share/.babashka/pods/repository/retrogradeorbit/bootleg/0.1.9/linux/x86_64/bootleg
ldd: /home/piotr/.local/share/.babashka/pods/repository/retrogradeorbit/bootleg/0.1.9/linux/x86_64/bootleg: No such file or directory
Yes, as I said above:
> Threre's no bootleg
executable at the location, only manifest.edn
file. Before it crashes, it prints:
This is what I'm seeing:
$ bb -e "(require '[babashka.pods :as pods]) (pods/load-pod 'retrogradeorbit/bootleg \"0.1.9\")"
Downloading pod retrogradeorbit/bootleg (0.1.9)
Successfully installed pod retrogradeorbit/bootleg (0.1.9)
#:pod{:id "pod.retrogradeorbit.bootleg.glob"}
can you maybe try the above with:
BABASHKA_PODS_DIR=/tmp bb -e "(require '[babashka.pods :as pods]) (pods/load-pod 'retrogradeorbit/bootleg \"0.1.9\")"
Hmm, that worked with /tmp
!
On ubuntu it also worked fine for me. Perhaps you could try to wipe the pods directory and try again
It reproduces the erratic behavior.
you could try to debug locally with https://github.com/babashka/pods - the load call should also work on the JVM
OK, will try, thanks.
(Meanwhile I can hack it with BABASHKA_PODS_DIR
: I have my bb script for AoC, wanted to play with the badges -- thanks @borkdude & @U1Z392WMQ)
@UUAKPEMJ9 I found the problem that caused this. You should be able to remove the workaround with the current master build:
bash <(curl ) --dev-build --dir /tmp
@borkdude Cool! Will have a look.