#2018-12-0322:34borkdudeabout 4x slower roughly speaking#2018-12-0322:573Janethis channel exists, yay! ❤️#2018-12-0323:033Janemaybe not so yay XD#2018-12-0402:12bhaumanand I finally got around to doing day 3 https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day03.clj#2018-12-0408:333JaneDay 4 discussion, with spoilers#2018-12-0408:333Jane[1518-09-19 23:52] Guard #2083 begins shift
[1518-02-25 00:51] wakes up
[1518-02-28 00:34] wakes up
[1518-04-29 00:54] wakes up
#2018-12-0408:353JaneRather sneakily, the example data isn’t in the same format the actual input is.#2018-12-0408:373JaneThey don’t give you any hint of that apart from
> consider the following records, which have already been organized into chronological order#2018-12-0408:43pesterhazyyeah I found the description less than clear#2018-12-0408:43pesterhazybut I guess vague specifications is a real-world programming scenario 🙂#2018-12-0409:06athosIn the description they say:
> While this example listed the entries in chronological order, your entries are in the order you found them. You’ll need to organize them before they can be analyzed.#2018-12-0409:193JaneYeah, you’re right. I missed it because it’s not in the place I expected to find it (task description, rather than input format description)#2018-12-0409:193JaneThat also is a real-world programming scenario: don’t read specs before first coffee :woman-facepalming:#2018-12-0409:45pesterhazyReminds me ☕#2018-12-0415:25ClashTheBunnylol!!#2018-12-0420:54uoslI almost had a heart-attack when I checked out the real data and saw it had multiple "wakes up" in a row, after having written my solution. Then I realized that it just wasn't chronologically ordered. Then sort
came to the rescue 🌸#2018-12-0408:41pesterhazyMy solution to day 4 https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle04.clj#L42#2018-12-0408:42pesterhazySpent around half the time on parsing/understanding the file format#2018-12-0409:09fellshardIt was a key realization that there's only one useful chunk of info per line.
Also, the specific line format they give means you can sort it in standard lexicographic order to get the correct sequence of events right off the bat, no interpretation of the data required. 🙂#2018-12-0409:16pesterhazyI did sort lexicographicallz#2018-12-0409:17pesterhazybut you still need to match guard-ids, interval starts and ends no?#2018-12-0409:53fellshardYep. One piece of info to parse per line: Guard ID or minute.#2018-12-0410:04pesterhazyAnd event type 🙂#2018-12-0410:06fellshardTrue; I attached that as a tag afterwards, though, since you need to know which type it is to parse correctly in the first place#2018-12-0410:14borkdudeSolved day 4: https://github.com/borkdude/advent-of-cljc/tree/master/src/aoc/y2018/d04#2018-12-0410:14borkdudeIn CLJ:
Testing aoc.y2018.d04.borkdude
part-2 took 40.23 msecs
part-1 took 3.80 msecs
#2018-12-0410:44borkdude@pesterhazy It seems our solutions are quite similar#2018-12-0410:47borkdudeWhen reading the puzzle, I thought “strategy 1” was trying to mislead me, since they wrote that there were two strategies and I thought you had to come up with another better strategy 😉#2018-12-0411:27ihabunektook me a while to parse it, but as usual, regex to the rescue 🙂#2018-12-0413:36taylorhere’s my day 4 https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/4.clj reached for clj-time and instaparse b/c why not 🙂#2018-12-0414:22benoitMy solution to day 4 https://github.com/benfle/advent-of-code-2018/blob/master/day4.clj#2018-12-0414:30genmeblogand mine: https://github.com/genmeblog/advent-of-code-2018/blob/master/src/advent_of_code_2018/day04.clj#2018-12-0414:47benoitIf I had time I would have refactored into something like @tsulej. If you have the proper data structure with minute-level stats for each guard, the 2 solutions can be very concise.#2018-12-0414:54genmeblogYes, I think that proper data structure is crucial here. I spent most of my time to find one. The same applies for day 3.#2018-12-0414:56borkdudeoh yeah, I always forget you can give sort-by
another argument like (sort-by val > the-things)
#2018-12-0414:58genmeblogwithout it you can always call (last)
which can be obviously slower#2018-12-0415:01genmeblog(comp - val)
cool hack 🙂#2018-12-0415:18borkdudeyeah I did the comp thing#2018-12-0415:44mfikesDay 4 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_04.cljc#2018-12-0415:48borkdudeof course, (max-key val …)
#2018-12-0415:49borkdudeour add-minutes
solution is quite the same#2018-12-0415:49borkdudeor wait, no, it isn’t 🙂#2018-12-0415:49borkdudeah you save a map of guard -> minutes#2018-12-0415:53taylornice to see another use of max-key
; I rarely ever have a use for it#2018-12-0415:54taylorthe concision of some of these solutions is impressive 👏#2018-12-0415:55potetm@mfikes very nice!#2018-12-0415:56potetmyeah I was surprised at the amount of (first (sort-by ...))
I’ve been seeing.#2018-12-0415:56potetmmax-key
often gets forgotten#2018-12-0415:573JaneI’m not done yet (done 1/2), but took a look at this channel, and max-key instead of sort-by in the existing solution … which slowed things down. Did you find it more performant?#2018-12-0415:58taylorI haven't been concerned with performance for any of the problems yet#2018-12-0415:59taylorlater in the schedule performance becomes more important#2018-12-0416:04fellshardAre you thinking (apply max-key...)
has a heavier cost for, say, a map of minute tallies?#2018-12-0416:053Jane(…actually might have been the effect of something triggering in the background… I need to check again once I’ve got a charger 🙂 )#2018-12-0415:58potetmnah, just what I want#2018-12-0416:02fellshardI looked at it, but passed it by because I thought it wasn't quite what I wanted. I'll take another look to see what I'm missing.#2018-12-0416:26borkdude@fellshard I had the same: max-key passed my mind but then I thought: oh this is for map keys or something#2018-12-0416:26borkdudewhy isn’t it called max-by
#2018-12-0416:27fellshardI think the prospect of (apply max-key...
on 60 elements had me a bit worried, I forget what the rules are for slapping a bunch of arguments in there, even rest-args#2018-12-0416:28borkdudethat works#2018-12-0416:37pesterhazy@fellshard (apply + (repeat 1000000 1))
seems to work ok in CLJ and CLJS, but (apply + (repeat 10000000 1))
is fast in Clojure but very slow in CLJS (at least in Lumo 1.8.0)#2018-12-0416:39pesterhazyIn Java varargs are passed as an array AFAIK so it should be fine. Not sure why it's so slow in CLJS#2018-12-0416:39pesterhazyProbably GC?#2018-12-0416:43pesterhazyMath.max.apply(null, new Array(1000000).fill(0))
blows the stack...#2018-12-0416:57borkdude(apply max (range 100000000000))
works though#2018-12-0417:04mfikes@pesterhazy Update to Lumo 1.9.0. You'll see (apply + (repeat 1000000 1))
a few hundred times faster. Why? This is the result of optimizations made in ClojureScript after last year's Advent of Code. 🙂#2018-12-0417:06borkdudechanged my max-frequency function. I really should use max-key more often. I think I only remember it until Advent of Code comes along again
https://github.com/borkdude/advent-of-cljc/commit/24fa6344c3c64a3fc242d7b2a784df7b73bace8a#2018-12-0417:07mfikesLumo 1.8.0:
cljs.user=> (type (repeat 1000000 1))
cljs.core/LazySeq
Lumo 1.9.0:
cljs.user=> (type (repeat 1000000 1))
cljs.core/Repeat
#2018-12-0417:08mfikesMore info: https://clojurescript.org/news/2018-03-26-release#_reducible_sequence_generators#2018-12-0417:31quollI’ve browsed clojure.core, but keep forgetting about many of the functions in there. I totally forgot about max-key
and rolled my own. That said, I used what I rolled in a couple of other ways, so it wasn’t a waste#2018-12-0418:04pesterhazy@mfikes the advent of code comes full circle!#2018-12-0418:21pesterhazyit's much faster indeed 🎉#2018-12-0418:21pesterhazyalso a good occasion to upgrade lumo#2018-12-0418:22pesterhazynow it's 10x faster than Clojure $ lumo
cljs.user=> (time (apply + (repeat 10000000 1)))
"Elapsed time: 65.706720 msecs"
10000000
$ clj
Clojure 1.9.0
user=> (time (apply + (repeat 10000000 1)))
"Elapsed time: 657.798409 msecs"
10000000
#2018-12-0504:10baritonehandsIs (reduce + ...
any faster?#2018-12-0504:11baritonehandsLooks like yes#2018-12-0504:11baritonehandsuser=> (time (apply + (repeat 10000000 1)))
"Elapsed time: 526.222753 msecs"
10000000
user=> (time (apply + (repeat 10000000 1)))
"Elapsed time: 656.773543 msecs"
10000000
user=> (time (reduce + (repeat 10000000 1)))
"Elapsed time: 178.887459 msecs"
10000000
user=> (time (reduce + (repeat 10000000 1)))
"Elapsed time: 47.995412 msecs"
10000000
user=> (time (reduce + (repeat 10000000 1)))
"Elapsed time: 39.555085 msecs"
10000000
#2018-12-0418:23pesterhazyperformance is weird#2018-12-0418:26mfikesIn this case, Lumo may be running at native speed. See https://www.youtube.com/watch?v=LopU-kMpe8I#2018-12-0418:26adammilleranyone know why (read-string "01")
or (read-string "02")
... all the way up to 07 work just fine but (read-string "08")
and (read-string "09")
throw exceptions saying it is an invalid number? Would assume all would or none would.#2018-12-0418:27mfikes08 is octal#2018-12-0418:27adammillerah#2018-12-0418:27mfikesWell, malformed octal 🙂#2018-12-0418:27lilactownI've used this almost every day so far:
(defn str->int [^String s]
(Integer/parseInt s))
#2018-12-0419:42ClashTheBunnyDoes this work with the positive numbers, like "+5"?#2018-12-0419:44potetmTry it in the REPL!#2018-12-0419:50ClashTheBunnyI thought I tried that and it didn't work. Is fixed by the ^string metadata?#2018-12-0419:50lilactownIt worked for me on day 1 ¯\(ツ)/¯#2018-12-0419:51ClashTheBunnyHmmm.... Dang. Wonder what I had problems with...#2018-12-0419:51ClashTheBunnyMaybe it was just the int
function...#2018-12-0419:52potetmint
is a cast to int#2018-12-0419:53potetmbut yeah, java Long/parseLong
permits + and -: https://docs.oracle.com/javase/7/docs/api/java/lang/Long.html#parseLong(java.lang.String)#2018-12-0420:10quollI’m forever wrapping Long/parseLong in a function. It’s a source of never ending frustration for me that Clojure doesn’t have to-long and to-double#2018-12-0420:30Ben GrabowThe function reader literal syntax is pretty terse: #(Long/parseLong %)
. Much nicer than a top level (defn ...)
form, if that's what you've been using.#2018-12-0501:17quollI disagree#2018-12-0501:17quollyes, it’s terse. It’s not much nicer than a top level defn (or def)#2018-12-0504:06baritonehandsI did this for day 3:
(map (comp #(Integer/parseInt %)
(memfn trim)))
#2018-12-0418:28adammilleryeah, for cljc read-string was just faster, but better not to use it for these scenarios (in real code)#2018-12-0418:28borkdudeis the type annotation really necessary?#2018-12-0418:29borkdude@adammiller not sure if you do advent-of-cljc, but there’s aoc.utils/parse-int
for cross platform#2018-12-0418:29adammilleryes, I saw that. Actually just moved my day 3 solution there yesterday....just locally though.#2018-12-0418:30borkdude@adammiller welcome to submit individual puzzles for any day#2018-12-0418:30adammillerok, i'll see about moving my day 4 and then submit them. Thanks!#2018-12-0419:09lilactown@borkdude it was necessary when I tried it with 1.10-RC2#2018-12-0419:42ClashTheBunnyDoes this work with the positive numbers, like "+5"?#2018-12-0504:08baritonehandsI did this for the padded numbers:
(defn to-int [s]
(Integer/parseInt
(if (= (.charAt s 0) "0")
(.substring s 1)
s)))
#2018-12-0504:08baritonehandssurprised that my char to string comparison worked#2018-12-0504:20athos(= \0 "0") ;=> false
So, your function is equivalent to (Integer/parseInt s)
#2018-12-0504:21baritonehandsgood to know#2018-12-0504:21baritonehands(Integer/parseInt "09")
=> 9
#2018-12-0504:21baritonehandsaccidentally on purpose#2018-12-0506:32potetmAnyone getting subsecond timings on part 1?#2018-12-0511:583Janefwiw (since my result is incorrect) locally my solution works in ~100 msec#2018-12-0512:003JaneTwo string builders acting as stacks.
“Right” initialised to original string, “left” empty.
Action consists of examining heads of stacks and then:
- if reducible, remove both
- if non-reducible, move char from “right” to “left”
Repeat until “right” is empty.#2018-12-0512:153Jane…so yeah, I forgot to trim the input 🙂 now it works.#2018-12-0512:193Jane(it’d probably be even more performant if I was operating at the last element of the “left” sb)#2018-12-0512:32potetmI finally got mine working.#2018-12-0512:33potetmOne string builder - 40ms.#2018-12-0512:423Janedeleting from the middle is efficient?#2018-12-0512:47potetmStringBuilder
is mutable, so it mostly doesn’t matter.#2018-12-0512:513Jane…right, well, it matters how the memory is actually allocated#2018-12-0512:523Janebut it sounds like it works just fine 😄 thanks!#2018-12-0514:17potetmright, if they’re having to shift mem around#2018-12-0514:18potetmSo it’s back by System.arrayCopy
— so towards the start of the string it’s having to do a fair number of (native) copy operations#2018-12-0514:39potetmSo… @U82DUDVMH you should look at @me1740’s solution! More in line with what you were saying.#2018-12-0506:33potetmI’m basically bashing on a StringBuilder
in a loop/recur and coming up w/ ~4 sec.#2018-12-0506:33potetmseriously no idea how I could speed that up#2018-12-0506:33potetmbut I hear of others in the ms range#2018-12-0506:36Mario C.Not having state is making these puzzles really difficult for me. 😅#2018-12-0506:37potetmYou should join the twitch stream! That’s part of why I’m doing it!#2018-12-0506:37potetmalas, I’ve devolved into a PLOP animal to get sweet speed#2018-12-0506:39Mario C.Are the videos saved?#2018-12-0506:39potetmyep!#2018-12-0506:39potetmhttps://www.twitch.tv/timpote/videos#2018-12-0506:39ClashTheBunnyI couldn't get speed this time at all: https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day05.clj Ended up with 845 seconds for all tests on my Pixel Slate.#2018-12-0506:40potetmthat’s some cond
🙂#2018-12-0506:41ClashTheBunnylol, yes!#2018-12-0506:41potetmah atom bashing as well I see#2018-12-0506:41ClashTheBunnyYeah, that shouldn't be needed, but I get a smaller answer without it.#2018-12-0506:41potetmyeah I didn’t know what else to do for this one besides bash some memory around#2018-12-0506:41ClashTheBunnyI'll refine it on the train tomorrow.#2018-12-0507:56rymndhngwow i went through a lot of pain there, i had a newline at the end and I was off by 1 for #5 facepalm
that said, I switched from a functional approach to using an ArrayList to make removal easier, and was able to run the algorithm in < 1s on my mac
https://github.com/rymndhng/advent-of-clojure/blob/master/src/advent_2018/05.clj#2018-12-0508:08pesterhazyElapsed time: 32991.632126 msecs -- https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle05.clj#L43#2018-12-0508:08pesterhazyNot the fastest 🙂#2018-12-0508:09pesterhazyMake it work, make it right, make it fast, right? Except I won't make it right or fast because it's just a kata...#2018-12-0508:10rymndhngtotally haha, it's pretty cool to see the different approaches folks went for#2018-12-0508:10pesterhazyHonestly the main source of ugliness in my solution is the lack of cond-let
in clojure.core#2018-12-0508:11pesterhazyI went for a pure function, which is never going to be super fast for this type of problem#2018-12-0508:13rymndhngi agree with you for the pure functional part -- I ended up going with an arraylist because removing elements by index via subvec + concat is too cumbersome#2018-12-0508:17pesterhazyI ended up setting them to nil and skipping over nils when considering neighbors#2018-12-0508:42heliosthis is my day5 🙂 https://github.com/Heliosmaster/advent-of-code-2018/blob/master/src/adventofcode/2018/day5.clj#2018-12-0508:43heliosit's not super fast but i'm happy i got to use partition-all 😛#2018-12-0510:11genmeblogMy day5: "Elapsed time: 7839.507737 msecs" https://github.com/genmeblog/advent-of-code-2018/blob/master/src/advent_of_code_2018/day05.clj#2018-12-0511:543Janeguys, have you maybe got a regexp that I could check against my results?#2018-12-0511:553Janesomething’s wrong in that I’ve got too many characters, but I can’t tell what. superficial examples seem fine.#2018-12-0512:03rmprescottI really enjoyed reading @mfikes solution for day4. A few things that stuck out:
- the concision of naming a map in the domain space: guard-id->minutes
- learned a new trick: destructuring in a let block when extracting the key and value of interest
- how much this approach reads like a proof#2018-12-0512:10erwinrooijakkersAlso check out the reduce
, reduced
, reductions
for part 2 of day 1 of @bhauman
https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day01.clj#L18#2018-12-0512:153Janetrim :woman-facepalming:#2018-12-0512:36athosMy solution for Day 5 https://github.com/athos/advent-of-code-2018/blob/master/src/advent_of_code_2018/day05.clj#2018-12-0512:36potetmSo I did eventually find a way to get part 1 down to ~40ms.#2018-12-0512:36athosThe combination of sorted-map
and subseq
works very nicely 😃#2018-12-0512:36potetmtook a few minutes tho#2018-12-0512:42borkdudeClojure:
Testing aoc.y2018.d05.borkdude
part-2 took 5546.88 msecs
part-1 took 160.69 msecs
CLJS:
Testing aoc.y2018.d05.borkdude
part-1 took 107.00 msecs
part-2 took 1896.00 msecs
#2018-12-0512:42borkdudefunny enough, Node is faster than the JVM here…#2018-12-0512:44borkdudemy code: https://github.com/borkdude/advent-of-cljc/tree/master/src/aoc/y2018/d05#2018-12-0512:45genmeblog@athos really fast solution... nice#2018-12-0512:46borkdude@athos where can we see the time for your solution?#2018-12-0512:47potetmtil: subseq
#2018-12-0512:49athosOn my MBP:
user=> (time (day05/solve1 (slurp (io/resource "input05.txt"))))
"Elapsed time: 414.086682 msecs"
9238
user=> (time (day05/solve2 (slurp (io/resource "input05.txt"))))
"Elapsed time: 1936.757214 msecs"
4052
#2018-12-0512:50borkdudecool.#2018-12-0512:50borkdudeoh you’re using pmap. no can do in cljs#2018-12-0512:52borkdudewith pmap I get on clj:
Testing aoc.y2018.d05.borkdude
part-2 took 2900.71 msecs
part-1 took 160.96 msecs
#2018-12-0512:52athos👍#2018-12-0512:58borkdudeHmm, I see one of my tests get killed now regularly on CircleCI:
Testing aoc.y2018.d04.dfuenzalida
part-2 took 2706.55 msecs
Killed
Maybe they use some sort of time out?#2018-12-0513:02borkdudecould be a memory issue.#2018-12-0513:06ihabunekAdvent of code 2018, day05
Part 1 "Elapsed time: 107.586455 msecs"
Part 2 "Elapsed time: 2453.459493 msecs"
#2018-12-0513:06ihabunekhttps://git.sr.ht/%7Eihabunek/aoc2018/tree/master/clojure/src/aoc2018/day05.clj#2018-12-0513:07ihabuneknow to look what everyone else did, cause I'm certain this can be faster#2018-12-0513:07ihabuneki'm half tempted to solve it using a transient vector but not sure i want to#2018-12-0513:09borkdude@ihabunek cool, our solutions are almost identical#2018-12-0513:09ihabunekyeah, just wanted to comment 🙂#2018-12-0513:09ihabunekpop and peek would make mine less verbose#2018-12-0513:10ihabuneki first did mine in elixir, and used regex search&replace, but it took 6 minutes for part 2 ^^;#2018-12-0513:13benoitMy solution for Day5. https://github.com/benfle/advent-of-code-2018/blob/master/day5.clj#2018-12-0513:14ihabunekweird... i just tried to optimize by converting the input to list of ints instead of chars which I had
my logic was that i wouldn't have to convert to int when checking if two chars react
but it takes 4 times as long ...#2018-12-0513:14benoit17ms for part 1 and 350 ms for part 2.#2018-12-0513:14ihabuneknice!#2018-12-0513:17benoitI think the key to a fast functional solution is to build the reduced polymer in reverse to make the backtracking faster.#2018-12-0513:18ihabunekah, right#2018-12-0513:18ihabunekwill try it out#2018-12-0513:33pesterhazywhat the devil is subseq?#2018-12-0513:40pesterhazyClojure's API surface is positively huge#2018-12-0513:52athosclojure.core/subseq
([sc test key] [sc start-test start-key end-test end-key])
sc must be a sorted collection, test(s) one of <, <=, > or
>=. Returns a seq of those entries with keys ek for
which (test (.. sc comparator (compare ek key)) 0) is true
#2018-12-0513:52athosI used it to find the greatest key that is less than a certain key in a sorted map.#2018-12-0513:59genmeblogI took @me1740 idea and got 220ms for both using pmap#2018-12-0514:02normanHmm. 17ms/350ms is quite fast. My naive solution was way too slow, (I left it running over night, but it probably ended up finishing after an hour or so). I optimized while it was running and got it down to 500ms/20s. But, I guess I still missed something to get those kinds of speeds#2018-12-0514:04genmeblogwithout pmap I have around 450ms#2018-12-0514:16taylorhttps://www.youtube.com/watch?v=9OfLNCWM_yA day 4 visualized#2018-12-0514:21potetm@me1740 wtf is this black magic???#2018-12-0514:34benoitdivide and conquer + being more careful about data structure when the first approach was too slow#2018-12-0514:40potetmI feel like I just got completely schooled.#2018-12-0514:41potetmMe, a simpleton: “Linked lists aren’t fast.”
@me1740: “Hold my beer.”#2018-12-0514:42potetmSo you can get similar performance w/o having to reverse if you use a vector as your “reduced queue.”#2018-12-0514:44benoitYes but I would have had to make sure all my internal operations return a vec 🙂#2018-12-0514:44benoitBut it's probably better all vec, yes.#2018-12-0514:44potetmnah, pretty much the same#2018-12-0514:45potetmperhaps even faster as a linked list because there’s never a re-allocation#2018-12-0514:45potetm(guessing)#2018-12-0514:46potetmYou can pretty much change that reduced queue at will tho. It’s a local and only uses conj
.#2018-12-0514:48potetmcriterium says that of []
PersistentQueue/EMPTY
and '()
— '()
is between 30-40% faster#2018-12-0514:48potetmfun stuff#2018-12-0514:49potetmThanks @me1740! A valuable lesson was taught today.#2018-12-0514:49benoitBut conj
doesn't behave the same for all those types.#2018-12-0514:49potetmright, so it’s a matter of whether you reverse
at the end or not#2018-12-0514:49benoitok#2018-12-0514:50potetmiiuc#2018-12-0514:51Björn Ebbinghaus@me1740 Are you timing it multiple times?#2018-12-0514:51benoitI think if you switch from list to vec, you will have a few things to change in the code to make sure all the internal ops return vecs for example.#2018-12-0514:51potetmI ran criterium on it: getting an avg of 9ms on my sample in 66 calls#2018-12-0514:52adammillerJust in case anyone else has this issue, there is an extra space (or possibly return char) at the end of their input file. All my tests were working but I was getting the wrong answer and starting to get a bit frustrated before I checked that!#2018-12-0514:52potetm@me1740 ah I did one more thing!#2018-12-0514:52adammillerGuess I should've verified my input!#2018-12-0514:52benoit@mroerni No as soon as I get the result in a "reasonable" amount of time, I'm done.#2018-12-0514:52potetmI changed rest
and first
to pop
and peek
respectively#2018-12-0514:53potetmso everything returns the same data structure#2018-12-0514:53Björn EbbinghausI am getting 6ms/400ms, but only on later runs (https://github.com/MrOerni/advent-of-code-2018/blob/master/src/advent_of_code_2018/day05.clj)#2018-12-0514:53potetm(just on operations on the reduced
variable`)#2018-12-0514:55potetm@mroerni ah so, perhaps because you just return the count instead of allocating a new string?#2018-12-0514:55benoit@potetm good to know#2018-12-0514:55potetmlemme try#2018-12-0514:58potetmnope#2018-12-0514:58potetmit’s just faster#2018-12-0515:08potetmholy moly @mroerni#2018-12-0515:08potetmthe quick-bench of yours is 3ms#2018-12-0515:08Björn EbbinghausUsing pmap for task 2, halved the time. (on a 2/4 Core machine)#2018-12-0515:08potetmvery clever btw#2018-12-0515:09potetmpre-emptive conj on tail, then compare and drop — ensures a single pass across the input#2018-12-0515:09potetmno backtracking#2018-12-0515:10Björn EbbinghausThank you. 🙂#2018-12-0515:15potetm@me1740 and @mroerni I will be mentioning both of you on Friday’s stream. I’ll probably code Björn’s implementation actually.#2018-12-0515:16benoit:thumbsup:#2018-12-0515:19ihabunekslightly offtopic, but this solution in elixir is delightful:
https://gist.github.com/sasa1977/d70f0986bf72bb94048d37843d11b4a4#file-day5-exs-L21-L28#2018-12-0515:19ihabunekpure recursion, no "stepping back", under 1 s including VM startup#2018-12-0515:28potetmI’m surprised that Elixir solution doesn’t blow the stack#2018-12-0515:29potetmI must not understand it. It looks like it recurs to the end of the string and unrolls.#2018-12-0516:00potetmfound a pythonista that did a reduction version of Björn’s algo#2018-12-0516:23pesterhazymaybe it just has a large stack!#2018-12-0516:32ihabunektried doing the same in clojure, but blew the stack#2018-12-0516:32ihabunekso yeah, large stack i guess#2018-12-0516:33ClashTheBunnyTail recursion never blows the stack. Did you try to call the function, or did you recur
?#2018-12-0516:34potetmI don't think this could be TCO#2018-12-0516:34potetmeach stack relies on the result of the next#2018-12-0516:34potetmiiuc#2018-12-0516:40potetmhttps://happi.github.io/theBeamBook/#_working_memory_a_stack_machine_it_is_not#2018-12-0516:41potetmperhaps why^?#2018-12-0516:42potetmhttps://i.imgflip.com/2o8hh1.jpg#2018-12-0516:42heyarnei'm solving day 5 and it's super slow at the moment (part 1 takes ~30 seconds) + it causes a stack overflow error, even though i'm not sure where i even build up such a large stack. if anybody wants to take a look at it I'd appreciate that https://github.com/heyarne/advent-of-code-2018/blob/86360a4/src/day_5.clj#2018-12-0517:21genmeblog@arne-clojurians SO can be caused by concat in your case.#2018-12-0517:24tayloryeah, b/c when you recursively construct sequences with concat
, it keeps building up unrealized "thunks" of the lazy sequences. It's definitely not something that looks obviously problematic#2018-12-0517:39mfikesDay 5 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_05.cljc#2018-12-0517:51mfikesHah. Seeing all the great timings for this one in the backlog. I may revisit my solution (it is dog slow).#2018-12-0517:54taylormy first solution used trampoline
and part 1 took ~9s...#2018-12-0518:12benoit@mfikes The fixed-point thingy is nice. And I found your solution the most readable so far 🙂#2018-12-0518:13benoitBut it means you do multiple pass I believe.#2018-12-0518:14mfikesThanks. I'm sitting here pondering the fundamental algorithm, trying to avoid gleaning anything from the above. But yeah, I'm zeroing in on the concept that I'm making way too many multiple passes, without even any ability to backtrack a little.#2018-12-0518:14benoitOk I shut up 🙂#2018-12-0518:27mfikesMostly, I want to get it to be fast enough to contribute to Advent of CLJC. (Otherwise, it could suck up 5 minutes of CI time.)#2018-12-0518:49potetmMy Day 3: https://github.com/potetm/advent-of-code/blob/master/src/advent_2018/day_3.clj#2018-12-0518:50potetmPosting cause I’m not sure I saw anyone w/ that particular approach.#2018-12-0519:27ClashTheBunnyI'm much happier with my 2nd version of day 5, but it is still very slow and still has a bunch of cond: https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day05.clj#2018-12-0519:55pesterhazy@mfikes my solution ended up very slow as well (33s for part II) - I wouldn't have predicted it#2018-12-0520:27borkdudeTesting aoc.y2018.d05.bgrabow
part-1 took 33.00 msecs
part-2 took 359.00 msecs
Testing aoc.y2018.d05.borkdude
part-1 took 60.00 msecs
part-2 took 3392.00 msecs
Testing aoc.y2018.d05.mfikes
part-1 took 3505.00 msecs
part-2 took 75629.00 msecs
#2018-12-0520:28borkdude(on node)#2018-12-0520:28borkdudeI haven’t looked at bgrabow’s solution yet, but it’s killing all other solutions 😉#2018-12-0520:29borkdudeon JVM:
Testing aoc.y2018.d05.bgrabow
part-2 took 110.05 msecs
part-1 took 12.13 msecs
Testing aoc.y2018.d05.borkdude
part-2 took 4697.16 msecs
part-1 took 166.39 msecs
Testing aoc.y2018.d05.mfikes
part-2 took 24970.50 msecs
part-1 took 1035.49 msecs
#2018-12-0520:33ClashTheBunnyWhat are the specs on the machine that runs that?#2018-12-0520:41Ben Grabow@borkdude Wait, I'm making it faster! Borrowing heavily from the discussion above though.#2018-12-0520:48genmeblogfaster than now? 🙂 wow#2018-12-0520:52borkdude@clashthebunny you can click the CircleCI icon on https://github.com/borkdude/advent-of-cljc#2018-12-0521:04ClashTheBunnyIt just says 4GB of ram and two vCPU.#2018-12-0521:06borkdudethat’s all I know#2018-12-0521:14Ben GrabowI'm trying to introduce parallelism to part 1, but nothing I'm trying is faster than the single-threaded approach. I'm guessing it's because there are some reducible polymer chains that are very long, so they stretch beyond the boundaries of a parallel chunk.#2018-12-0521:16Ben GrabowSo there is quite a bit of work to do in joining the chunks, which must be done serially.#2018-12-0521:44fellshardI'd considered fork-join for this, but yeah, that'd only be suitable if there's a lot of local adjacent pairs throughout the entire polymer.#2018-12-0521:22jduhamel@mfikes So I’m learning clojure by reading the advent of code stuff. Had a question about the “:log” in your day 4. also why {:log []} What does that do?#2018-12-0521:23jduhamelif there is a place you can point me to, that would be great.#2018-12-0521:24mfikesThere's an accumulator in there which essentially holds several things. When it is running the accumulator will have something like:
{:log [{:guard-id 1 :start 5 :end 12} {:guard-id 7 :start 7 :end 13}]
:guard-id 3
:start 12}
#2018-12-0521:25mfikesSo there's a vector under the :log
key that grows#2018-12-0521:25jduhamelgot it, so the first (:log kicks off the key.#2018-12-0521:26jduhamelthe {:log [] } is the arg to the reducer. Thanks a bunch#2018-12-0521:27mfikesYep, it just sets it up with a vector in there#2018-12-0521:29jduhamelThanks back to work on day5.#2018-12-0522:04adammillerI have part 1 around 8ms but part 2 is still up in the 500's....Have some ideas to improve that but not sure if i'll get around to it today.#2018-12-0522:06borkdude@adammiller always welcome to make a PR with improvements, even next year#2018-12-0522:09adammillerlooks like on the latest test it ran part 1 in 7.53ms.... Should definitely be able to improve part 2 since i use part 1 in that.#2018-12-0522:10mfikesHammock time led me to the kernel of single pass idea. That took me a while to see. Presumably others in the backlog are using similar approach. (Will read solns.)
https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_05.cljc#2018-12-0522:36Ben GrabowLove the use of reduce
in react
/`add-unit`.#2018-12-0600:19rymndhngsingle pass is a very elegant solution 😉 definitely the right choice of data structure influences a good solution#2018-12-0602:16ClashTheBunnyI was interested in how you did lower-case before the set, so I benchmarked it a bit and it seems like it is significant to set twice with a lower-case inbetween:
advent-of-code-2018.day05=> (cr/with-progress-reporting (cr/bench (into #{} (map s/lower-case (into #{} (parse input)))) :verbose))
Warming up for JIT optimisations 10000000000 ...
compilation occurred before 1 iterations
compilation occurred before 390 iterations
compilation occurred before 779 iterations
compilation occurred before 1168 iterations
compilation occurred before 1557 iterations
compilation occurred before 1946 iterations
compilation occurred before 2335 iterations
compilation occurred before 2724 iterations
compilation occurred before 4669 iterations
compilation occurred before 5447 iterations
compilation occurred before 5836 iterations
Estimating execution count ...
Sampling ...
Final GC...
Checking GC...
Finding outliers ...
Bootstrapping ...
Checking outlier significance
x86_64 Mac OS X 10.13.6 8 cpu(s)
Java HotSpot(TM) 64-Bit Server VM 25.192-b12
Runtime arguments: -Dfile.encoding=UTF-8 -Xmx8g -Dclojure.compile.path=/Users/ranmason/code/advent-of-code-2017/target/classes -Dadvent-of-code.version=0.1.0-SNAPSHOT -Dclojure.debug=false
Evaluation count : 29640 in 60 samples of 494 calls.
Execution time sample mean : 2.123692 ms
Execution time mean : 2.124454 ms
Execution time sample std-deviation : 96.420077 µs
Execution time std-deviation : 96.989667 µs
Execution time lower quantile : 1.940056 ms ( 2.5%)
Execution time upper quantile : 2.234693 ms (97.5%)
Overhead used : 2.083859 ns
nil
advent-of-code-2018.day05=> (cr/with-progress-reporting (cr/bench (into #{} (map s/lower-case (parse input))) :verbose))
Warming up for JIT optimisations 10000000000 ...
compilation occurred before 154 iterations
compilation occurred before 307 iterations
compilation occurred before 460 iterations
compilation occurred before 1072 iterations
Estimating execution count ...
Sampling ...
Final GC...
Checking GC...
Finding outliers ...
Bootstrapping ...
Checking outlier significance
x86_64 Mac OS X 10.13.6 8 cpu(s)
Java HotSpot(TM) 64-Bit Server VM 25.192-b12
Runtime arguments: -Dfile.encoding=UTF-8 -Xmx8g -Dclojure.compile.path=/Users/ranmason/code/advent-of-code-2017/target/classes -Dadvent-of-code.version=0.1.0-SNAPSHOT -Dclojure.debug=false
Evaluation count : 5040 in 60 samples of 84 calls.
Execution time sample mean : 12.258769 ms
Execution time mean : 12.263469 ms
Execution time sample std-deviation : 437.470024 µs
Execution time std-deviation : 443.078234 µs
Execution time lower quantile : 11.783289 ms ( 2.5%)
Execution time upper quantile : 13.224535 ms (97.5%)
Overhead used : 2.083859 ns
Found 3 outliers in 60 samples (5.0000 %)
low-severe 3 (5.0000 %)
Variance from outliers : 22.2472 % Variance is moderately inflated by outliers
nil
#2018-12-0522:11adammillerinteresting that mine was significantly slower than @borkdude and @ben.grabow on the cljs side though#2018-12-0522:11adammillerthat looks pretty similar to what I had done on part 1 @mfikes#2018-12-1007:00fellshardAlso, is there a 'safe' way to use Quil from CIDER? I ended up hopping over and drawing everything to a PPM instead#2018-12-1007:06taylorsorry, not sure#2018-12-1007:50Average-userI've used quil with cider without problems. What do you think is unsafe?#2018-12-1008:47fellshardNot so much unsafe as acting strangely. When I'd close the opened sketch frame, it would cause the repl to freeze up to the point I had to kill it, because emacs would stutter consistently while editing.#2018-12-1008:47fellshardThere was an error message in the minibuffer, I'll see if I can replicate it later.#2018-12-1007:06taylorwhew… in hindsight I should’ve used an algorithmic approach, wasted a lot of time tinkering with Quil to get scale/speed rate to be able to see the letters#2018-12-1007:06fellshardOh dear, you drew each step in Quil? 😬#2018-12-1007:07tayloryeah but I put in a bunch of logic to control the speed and scale to make it easier to spot the message#2018-12-1007:07taylorso a lot of steps get skipped#2018-12-1007:08fellshardIt would be neat to see the zooming happen, at least, hopefully we get to see the results 😄#2018-12-1007:08tayloryeah, gonna polish it up and put it on YouTube and will post it here. Gotta go to bed soon though 💤#2018-12-1007:54gklijsQuil seems cool to use for the problems, do you use it only for clj, or also cljs. For next year I might want to give that I try, used quil before for both java and javascript.#2018-12-1014:30taylorI’ve only been running these on the JVM, but I’m not using any JVM-specific functionality so I think they should all be easily portable to CLJS#2018-12-1008:40pesterhazyMy day 10: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle10.clj#L65#2018-12-1010:42namenumade an animation for day10. very unattractive. 😖#2018-12-1014:41taylorVery cool! Let me know if you post the code so I can compare approaches#2018-12-1015:16namenu@U3DAE8HMG https://github.com/namenu/advent-of-code-2018/blob/master/src/year2018/day10.clj
I've slightly changed easing fn in repo, still the algorithm is same 😄#2018-12-1015:21taylorThanks, learning some stuff from your approach#2018-12-1015:54taylorI took a totally different approach to easing (knowing next to nothing about animation) https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/10.clj#2018-12-1016:21namenuwow, thanks for your inspiring code!#2018-12-1016:24namenuomg moving things were stars not elves 😱 (not reading a description is a bad habit)#2018-12-1010:45helioswhy unattractive? i actually think it's pretty cool 😄#2018-12-1011:08plexusToday was a great excuse to use a library I've been working on for building console UIs 🙂#2018-12-1011:08plexushttps://github.com/plexus/advent-of-code/blob/master/src/advent2018/day10.clj#2018-12-1011:09plexusstill a bit rough around the edges but you can already do fun things with it: https://github.com/lambdaisland/trikl/#2018-12-1014:22normanThanks. This looks quite amusing. #2018-12-1011:44borkdudeday 10 seems like fun. I’ll save it for later, short on time right now and my priority with AOC lies with keeping advent-of-cljc running#2018-12-1011:44borkdudethere was a memory issue because of the memoized state and delays that were built up in all the testing namespaces. now only new or changed solutions are tested on CI.#2018-12-1011:45borkdudeif anyone knows a neat trick to destroy namespaces after tests are finished to free up memory, I’m all ears#2018-12-1011:53borkdudeis this channel logged somewhere? I’d like to read the discussions after AOC is finished for the ones I didn’t get to yet#2018-12-1011:53borkdude@plexus you had this logging thingy running right?#2018-12-1011:54plexushttps://clojurians-log.clojureverse.org/adventofcode#2018-12-1011:54plexusUpdates once a day I believe#2018-12-1011:58borkdude@plexus I love terminal UIs. I got reagent working with react-blessed once: https://twitter.com/borkdude/status/1002623954320871426#2018-12-1012:10plexusVery nice! I ended up writing Trikl after I got dissatisfied with Lanterna and wanted some in native clojure#2018-12-1012:58benoitMy solution for Day 10 https://github.com/benfle/advent-of-code-2018/blob/master/day10.clj#2018-12-1014:29taylorday 10 visualized w/Quil https://www.youtube.com/watch?v=4YtCXEalgTw#2018-12-1015:55taylorand the code https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/10.clj#2018-12-1014:37pesterhazylooks amazing#2018-12-1014:41taylorThanks! I spent perhaps too long tinkering with it haha#2018-12-1017:47meikemertschI second the original statement. Thanks for making me smile#2018-12-1016:18mfikesDay 10 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_10.cljc#2018-12-1016:22misha> (or (> width 80) (> height 10))))
kappa @mfikes#2018-12-1016:59Average-userDon't remember if it was in 2016 or 2015, but there also was like this one#2018-12-1016:59Average-userLike a grid that said something#2018-12-1017:03taylorit reminded me of one from last year where you had to determine when some points w/velocities were going to stop converging or something, very similar input and algorithm but didn't involve finding a message from the points#2018-12-1017:05Average-userYeah me too#2018-12-1017:06Average-userHow much time takes you part-1?#2018-12-1017:07Average-userAnd also, has someone been able to transform the grid to a string with the word?#2018-12-1019:50Ben GrabowYep, there are two main steps to transforming to a string:
1. Group the stars by character
2. Convert each group into a character
Stars that all belong to the same character will have contiguous x-values. (They will also have contiguous y-values, but characters are taller than they are wide, so it's cheaper to group by x.
Once the stars are grouped, I made a simple stars -> character hashmap, and reverse-engineered what the stars pattern should be for each character. I only had 7 unique characters in my data set, so I only have 7 of 26 characters in my hashmap. Once I get borkdude's data I'll need to reverse engineer again and add some entries to my hashmap for my solution to work automatically with his input.#2018-12-1019:52Ben GrabowHere's my method for grouping by x-position:
(defn left-most-x-neighbor [all-points point]
(let [x-vals (into #{} (map first all-points))]
(loop [x (first point)]
(if (x-vals (dec x))
(recur (dec x))
x))))
(defn group-stars [stars]
(group-by
(partial left-most-x-neighbor stars)
stars))
#2018-12-1019:55Ben GrabowThis group-by pattern is something I've encountered a couple times now. "Start a group by unconditionally taking the first item in a seq. Continue adding to the group as long as (pred group new-item)
is truthy. When it is falsy, start a new group with new-item
instead."#2018-12-1017:09taylorto write the code, or run the visualization? Took me a couple hours to get the answer b/c I immediately went for visualization approach w/Quil instead of finding a heuristic for convergence, and I had a lot to learn about dealing with visualizing big spaces w/Quil and controlling animation speed such that I could read the message which is only legible for a handful of frames. Part 2 was easy b/c I just added a hack atom
to track passage of time in my draw function#2018-12-1017:10misha.
"Elapsed time: 3387.126557 msecs" part1
"Elapsed time: 3091.846753 msecs" part2 (same, but no drawing)#2018-12-1017:15Average-userdon't know what I'm doing wrong, but it takes me 13000 msecs#2018-12-1017:18Average-userI think this would be all you need to know about my code:
Clojure
(defn step [points]
(pmap (fn [[[x y] [vx vy]]] [[(+ x vx) (+ y vy)] [vx vy]])
points))
(defn boundaries [points]
(let [xs (map ffirst points)
ys (map (comp second first) points)
[maxx minx] [(reduce max xs) (reduce min xs)]
[maxy miny] [(reduce max ys) (reduce min ys)]]
[[minx miny] [maxx maxy]]))
(defn area [points]
(let [[[x1 y1] [x2 y2]] (boundaries points)]
(* (- x2 x1) (- y2 y1))))
(defn final-grid []
(->> (parse-input)
(iterate step)
(map vector (range))
(partition 2 1)
(filter (fn [[[s p] [_ p']]] (> (area p') (area p))))
(ffirst)))
#2018-12-1017:19Average-userOhh the problem was pmap
, now takes 5s#2018-12-1017:20mishayou pack/unpack a lot:
(let [[[x1 y1] [x2 y2]] [[minx miny] [maxx maxy]]
;; (boundaries points)]#2018-12-1017:21mishaofftopic: (map vector (range))
can be just (map-indexed vector)
#2018-12-1017:23mishamove velocities out as soon as you parse input. those do not change, and you pay all this packing/destructuring as a result#2018-12-1017:24mishathen you might want to (map area)
before partition
. now you calculate it twice for each frame#2018-12-1017:25mishacalculating maxx/maxy in one iteration will not hurt, now you scan all the points 6 times instead of once#2018-12-1017:25mishamap, map, reduce, reduce, reduce, reduce, instead of 1 tiny-bit-uglier reduce#2018-12-1017:29mishaalso drop-while
might return a bit earlier than filter
#2018-12-1017:31Average-userThanks, calculating areas before partition makes a lot of sense, should have thought of that (hehe). drop-while
instead of filter
probably wont change much but I'll try it out anyway#2018-12-1017:39Average-userAlso, changed step
and area
to
(defn step [{:keys [points velocities] :as data}]
(update data :points #(map (partial mapv +) % velocities)))
(defn bounds [{:keys [points]}]
(let [xs (map first points)
ys (map second points)]
[[(reduce min xs) (reduce min ys)]
[(reduce max xs) (reduce max ys)]]))
And makes the program slower#2018-12-1017:47mishabounds
still scans points 6 times opieop#2018-12-1017:48misha(defn frame [[[x y] & points]]
(reduce
(fn [[x1 x2 y1 y2] [px py]]
[(min x1 px) (max x2 px)
(min y1 py) (max y2 py)])
[x x y y]
points))
#2018-12-1017:49Average-userYeah ,I said that regarding your advice to separate points from velocities#2018-12-1017:50mishaI meant:
(defn tick [velocities points]
(map (partial mapv +) points velocities))
...
(->> points
(iterate (partial tick velocities))
...
#2018-12-1017:52mishabut I doubt it affected performance, rather - readability#2018-12-1017:53Average-userright#2018-12-1017:56potetmfor the interested: https://www.twitch.tv/timpote#2018-12-1017:58Average-userHaven't done day10 yet?#2018-12-1019:44potetmI haven’t 😕 starting to get tired… 😛#2018-12-1018:23Average-userAnyways here is my Day10, thanks @mishafor the insights
https://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day10.clj#2018-12-1019:50Ben Grabow#2018-12-1019:56potetmHave someone already talked about the trick to pre-calculate the time the letters show up?#2018-12-1019:56potetm@quoll Informed me this morning.#2018-12-1019:59taylorI think one heuristic is finding the point when the set of points' X/Y coords shrinks then starts growing again#2018-12-1019:59potetmthere’s a way to know almost for sure (no heuristic)#2018-12-1020:00taylori.e. when the coords are most aligned with each other#2018-12-1020:00quollPart 1: 34.33306 msecs
Part 2: 8.483958 msecs#2018-12-1020:00potetmeven better#2018-12-1020:00potetmanswer in thread? @quoll#2018-12-1020:00mattlyok you've got my curiosity#2018-12-1020:00quollmy part 2 re-calculates everything, but I figure it’s warmed up#2018-12-1020:02quollAfter parsing the file into a seq of lists 4 numbers wide, I start with this:#2018-12-1020:02quoll(let [[[_ y1 _ y1v] [_ y2 _ y2v]] data
estimated-t (Math/abs (long (/ (- (Math/abs (- y1 y2)) 10) (- y1v y2v))))
#2018-12-1020:02Ben GrabowYou can take two points with different velocities and do a closed form arithmetic calculation to find the time at which they pass each other in the x- or y-dimension. That will get you close within a few iterations.#2018-12-1020:02Ben GrabowThe larger the velocity difference, the closer you'll get to the actual time.#2018-12-1020:03quollyou know that the final answer has every y-coordinate within 10 units of each other#2018-12-1020:03mattlyI've been meaning to level up my math#2018-12-1020:03quollit’s literally year 9 algebra (I know, because my son is in year 9, and I’ve been helping him with inequalities in recent weeks)#2018-12-1020:04mattlythey actually didn't specify the height, only implied it from the example#2018-12-1020:04taylorwhy 10 units?#2018-12-1020:04quollthat is true. In fact, the example was 8 high. I started by using an inequality of 8. It still gave a very good estimate#2018-12-1020:05mattlyI got a C in Algebra 30 years ago#2018-12-1020:05mishaI think it's still a magic number#2018-12-1020:05quollbut then I saw that the result was 10 high, so I updated my code to have 10 instead of 8 😄#2018-12-1020:05mishaby all means, use it to get yourself higher on a scoreboard, tho.
but as soon as we are taking time to optimize for speed, – it's a magic number#2018-12-1020:06potetmEvery example I’ve seen was 10. But, yeah, it’s an assumption.#2018-12-1020:06taylorI think that works perfectly fine for this problem but it's not a general solution (which doesn't matter for AoC but y'know)#2018-12-1020:06mfikesThen you skip several thousand iterations?#2018-12-1020:07quollwhen the number was 8, my estimate was 10519. When the height is set to 10, the estimate came in at 10510. The final answer for my data was 10511#2018-12-1020:08mishayou can try to optimize against (+ guess-algo-time wrong-answer-timeout) opieop#2018-12-1020:09Ben GrabowIf you want a solution without a magic number, find the time at which two points pass each other in y, then iterate both backwards and forwards in time until you find the minimum y-height. The algorithm will be entirely based on the input data, no magic numbers.#2018-12-1020:09quollif I presumed that the height was 1, then the estimate was 10508. So my presumed height really didn’t matter#2018-12-1020:09quollLetters cannot be smaller than 1, so that’s reasonable, and does not include a magic number#2018-12-1020:10mishaI think there might be some inputs which would not work, like if text is sideways (since it was probably for human eyes anyways)#2018-12-1020:11Ben Grabow@quoll Is there a way you check that the convergence hasn't already passed?#2018-12-1020:11quollno, but it would make the estimate come in further away from the final result#2018-12-1020:11mishabut yes, min area, or height, etc - is a very good approach, I think#2018-12-1020:12quollI increment the time, and compare the area of the points. If it’s larger, then I start going back in time. If it’s smaller, then I go forward in time. I keep iterating while the area gets smaller. As soon as it starts to get larger again, I’ve found my minimum area#2018-12-1020:12mishaI imagined an input which 1st crosses over itself, and then aligns. that would throw off min-area heuristic a bit#2018-12-1020:13quollI tested by pushing my “estimate” smaller and larger, and it moves in the correct direction each time#2018-12-1020:13mishaI mean 5 4 3 2 1 2 3 result
instead of 5 4 3 2 1 result#2018-12-1020:13mattlyfortunately they didn't throw that at us#2018-12-1020:14mishatrue )#2018-12-1020:14quoll@misha I did consider that it’s possible for it to have a minimum area that wasn’t the solution.#2018-12-1020:14quollBut I cheated, and ran through the renderings by hand before I automated it 😜#2018-12-1020:14mishaI did (consider) too, but when I saw an accepted answer I just chilled kappa#2018-12-1020:15mishabut my rendering is sideways :D#2018-12-1020:16quollIt’s also possible (though unlikely with integer velocities) to have every point occupy a single point at some time#2018-12-1020:17mishaI put points count asserts in each frame, but did not commit it into git eventually#2018-12-1020:18quollTo be honest…. I got my initial estimate by hand#2018-12-1020:21quollwhen I went to bed last night, the puzzle had been published, so I looked it up, then put my phone down and tried to sleep. But then I started thinking about how the final rendering must have all the y-coordinates within a small range (was it just one line? Multiple lines?). Anyway, it was too much for me, and pulled my phone back out, grabbed a couple of numbers from my input, and did the algebra. That gave me the number 10519. That’s the number I started with this morning. And my answer was at 10511#2018-12-1020:21quollI do like it when you can shortcut a whole lot of the work with a little bit of math#2018-12-1020:22quollit makes me feel smart :female-student:🤪#2018-12-1020:22mattlythat's one of the fun things about these puzzles, is how flexible you can be at arriving at the solution#2018-12-1020:23mattlyand it's fun watching the different approaches people take to get there#2018-12-1020:24Average-userI did https://adventofcode.com/2017/day/7 (part1) with the searching feature (ctrl+f) of chrome in a couple of seconds. Sadly I was doing it the day after so I didn't get in the leaderboard#2018-12-1020:26genmeblogMy estimate is like that (long (* 0.99 (/ extent vextent)))
#2018-12-1020:26genmeblogwhere extent
is maximum absolute coordinate value and vextent
same for speed#2018-12-1020:38quolloh, someone just reminded me of another approach that I considered, but am glad I didn’t spend time on…
The roman alphabet has lots of vertical lines (my solution has 16 vertical lines of length 3 or greater. 4x length 3, 1x length 4, 1x length 5, 1x length 8, 9x length 10). My other way of looking was to look for vertical lines in the rendered field. However, unlike the “minimum area” approach, it wouldn’t tell me if I was going in the right direction when I went forward to backward in time. (Not a huge deal, given the accuracy of estimating the time).
Luckily, while looking at the various renderings, I saw the area converging to the minimum, so I didn’t waste time on that#2018-12-1021:13tayloram I remembering correctly last year there was a problem that was possible to solve by equation, but the most obvious solution was simulation#2018-12-1021:14quollthis sounds familiar#2018-12-1021:15quollday 22 was a simulation of a processor with a small instruction set, which was solved by simulation#2018-12-1021:16quollday 23 used the same instruction set, but multiplied 2 large numbers with the multiplication algorithm of:
a*b => if b = 1: a
else: a + a*(b-1)
and
a+b => if b = 0: a
else: (a+1) + (b-1)
#2018-12-1021:17quollI think that was it. Anyway, it just needed you to multiply the numbers. But you had to decode what it was doing before you knew that was what you were attempting#2018-12-1021:18quollsimulating it was going to take years#2018-12-1021:18tayloryeah I'm looking at my solution for that and remembering having to essentially turn the assembler instructions into C-style code so I could write equivalent Clojure before refactoring it https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2017/23.clj#2018-12-1021:22Average-userhave you done year 2016?#2018-12-1021:26taylorlooks like I only did the first few days#2018-12-1021:27taylorhttps://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2016/#2018-12-1021:41magic_bloatI looked at my input numbers, and noticed that all the ones around with coords at 50000 had velocities at -5, and so on for 40000, -4 and 30000, -3 etc.#2018-12-1021:41magic_bloatSo I fast forwarded to 10000 seconds and ran the visualization from there.#2018-12-1021:43mfikesYeah, it also appears that all of our answers are 10,000 + n where n is in the range of a few hundred#2018-12-1023:02mfikesIf you are solving these problems in ClojureScript (and in particularly via Advent of CLJC), there are a couple of new utilities, nth’
and count’
that you might find useful for lack of locals clearing.
This makes a difference of 200 MB vs 3 GB for today’s solution (at least in the way I did it.)#2018-12-1023:39Ben GrabowSomeone is compiling layout of known characters for d10. Useful if you want to do programmatic identification of your message.
https://www.reddit.com/r/adventofcode/comments/a4tbfl/trying_to_collect_all_used_letters_for_character/
https://gist.github.com/usbpc/5fa0be48ad7b4b0594b3b8b029bc47b4#2018-12-1023:53benoit🙂#2018-12-1102:30mfikesThis is an interesting way to calculate the “convergence time”: https://blog.jle.im/entry/shifting-the-stars.html#2018-12-1117:16potetm😂 it’s…. it’s beautiful#2018-12-1105:39mattlyeff, I had ann off-by-one in my initial pass for part 1 of day11#2018-12-1106:33quollI’m brute forcing part 2, which always makes me feel iffy. Maybe it’s because it’s late and I should have done this in the morning, but I’m not getting any sense of intuition that there’s a faster way (except for memoizing the power value for grid points)#2018-12-1106:35baritonehandsI just printed when the max changes, and eventually it sat at the same value for awhile#2018-12-1106:35baritonehandsit was correct when I entered it#2018-12-1106:35baritonehandsDidn't bother to wait until it was all done#2018-12-1106:36taylorI’m melting my laptop while trying to come up with a way to reuse calculated regions from previous sizes#2018-12-1106:40quolloh, I like that!#2018-12-1106:41quollso, size 10 at x,y is the same as size 9 at x,y, with another 19 values#2018-12-1106:43normanI just did brute force with shared computations too. Is it was running, I did notice that after a certain size, the larger squares always decreased the power#2018-12-1106:43normanSo in retrospect, I could have used that to figure out the likely answer more quickly.#2018-12-1106:43tayloryeah, I noticed the same when trying sizes in decreasing order#2018-12-1106:47taylorI’m going to start using massive EC2 instances so I can brute force all the remaining problems 🙂#2018-12-1106:48Average-userwhats EC2?#2018-12-1106:50tayloryou can rent big computers from AWS#2018-12-1106:48Average-userI limited to calculate squares of maximum size 20x20, and it worked#2018-12-1106:49taylorI just got my answer using same approach as baritonehands, way faster than my brute force solution would’ve ever reached#2018-12-1106:50Average-userHow much time takes part1?#2018-12-1106:51norman“Elapsed time: 2553.747123 msecs”#2018-12-1106:52taylorI’m getting ~350ms for part 1#2018-12-1106:53taylorI pre-calculate the grid into a map where the key is the X coord, and the value is a vector of the cell powers indexed by Y coord, then do calcs in a loop and use max-key
to find largest#2018-12-1107:05quollmemoizing the power function should be similar, right?#2018-12-1107:06tayloryeah I think so#2018-12-1107:06taylorjust two different ways of storing the same info in memory I guess#2018-12-1106:54taylorthis problem felt way easier than the past few days’ problems, and I’m glad b/c now I can go to sleep 💤#2018-12-1106:58normanI thought yesterday (stars) was much easier than today, but by far that day 9 marble was the slowest for me.#2018-12-1107:09quollyay… divide and conquer#2018-12-1107:10quollThank you @taylor. That helped me a lot#2018-12-1107:17quollI continue with squares of 3 or less as I was. But for anything larger, if it was an odd size, I recursed on the (dec size)
and then added the numbers around the bottom and right edges, and if it was even, I split it into 4, and recursed on each of the quadrants, adding the results#2018-12-1107:18quolleverything is memoized, so it gets those smaller squares from earlier#2018-12-1107:21quollWith memoization when calculating those smaller squares, it’s like they say on TV: “Here’s one we did earlier”
https://www.youtube.com/watch?v=K_zpdyBz3VM#2018-12-1107:23quollpart 1: 932.224412 msecs
part 2: 389148.15998 msecs (6min 29sec)#2018-12-1107:23quollnot brilliant, but it gets me to bed! 🙂#2018-12-1108:21heliosi'm also brute forcing it to start#2018-12-1108:21heliosand when i'll get the right answer, i'll optimize#2018-12-1108:21helios(unless getting the answer takes longer than a few minutes 😄 )#2018-12-1108:24fellshardMemory management is vital.#2018-12-1108:56borkdudeMy CLJ solution works, but the CLJS one is crapping slow#2018-12-1109:01pesterhazyBrute-forcing is really slow - 8s for square size 20 (never mind 100)#2018-12-1109:02pesterhazyAdding up numbers is not Clojure's forte#2018-12-1109:03pesterhazyMy terrible attempt (but I'm too impatient): https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle11.clj#L61#2018-12-1110:14borkdudeAdded two test metadata options to advent-cljc:
https://github.com/borkdude/advent-of-cljc/blob/master/README.md#tests#2018-12-1111:42ihabunekspoilers#2018-12-1111:42ihabunekOne fast approach is using https://en.wikipedia.org/wiki/Summed-area_table#2018-12-1111:43ihabuneki also bruteforced the solution and later found this on reddit#2018-12-1112:00borkdudeI have an idea how to optimize. already brought it down significantly, but need some time to generalize it#2018-12-1112:57magic_bloatThis is my day 11, every (except the first) square is calculated from an adjacent (overlapping) neighbour. Its not fast, but did all 300 square sizes in less than the time it took me to eat lunch 🙂 https://github.com/bloat/aoc2018/blob/master/src/net/slothrop/aoc2018/day11.clj#2018-12-1114:30helios@pesterhazy did you also set unchecked math when doing operations?#2018-12-1114:30heliosi understood that it has quite a big impact#2018-12-1114:31heliosps: I rembered about the seldom used pmap
, I think in this case can be very helpful 😄 (but my solution is still slow AF)#2018-12-1114:32heliosnow i wish i was using a desktop with a nice AMD threadripper 😆#2018-12-1114:55benoitUsing summed-area tables (as suggested by @ihabunek) https://github.com/benfle/advent-of-code-2018/blob/master/day11.clj
Got me to 8s for part two.#2018-12-1114:59benoitI tried first to improve the brute force approach with a dynamic programming algorithm but that was still very slow.#2018-12-1115:05pesterhazy@helios yeah I did, no dice#2018-12-1115:19borkdudeI get this time now:
Testing aoc.y2018.d11.borkdude
part-2 took 75854.05 msecs
part-1 took 0.46 msecs
I’ll leave it at that#2018-12-1115:22borkdudeThe approach I took was to memoize divisions and when you need a bigger area, you cut it in parts that you already calculated#2018-12-1115:36mishayeah, adding rows to (dec n)
for "prime" n
s is slow as f#2018-12-1115:37genmeblogfinally done day 9 part 2 in 6-7 seconds 😕#2018-12-1115:38mishabut the "total sum stops to grow at some point" feels like a guess to me. good enough to submit an answer, but not ok for "learning purposes", unless there is a known math behind it#2018-12-1115:48tayloryeah I think it's dependent on the distribution of negative powers#2018-12-1116:08namenuhttps://github.com/namenu/advent-of-code-2018/blob/master/src/year2018/day11.clj#L17
I've used memoize
for summarized-table which is having a closure, and now I have to reload my REPL every time when I change the binding (`grid-serial`)... 😓
Can anyone give me an advise to cache my table without reloading?#2018-12-1116:10borkdude@namenu when I want to refresh the memoized fn I simple evaluate the whole namespace#2018-12-1116:12borkdudenot sure what you mean actually#2018-12-1116:18namenuWhat if I want to memoize a function like,
(def efficient-f
(memoize (fn [x] (+ x y))))
with various y
?
Is it possible ?#2018-12-1116:22borkdudeNo, but you can memoize (fn foo [x y] (+ x y))
#2018-12-1116:23borkdudeyou have to pass down the argument that varies#2018-12-1116:30namenuyes, i'll have to do that. maybe I can curry out y
. thanks!#2018-12-1116:31borkdudeyou can never curry out something from the right#2018-12-1116:31borkdudeso maybe a good reason to move the serial to the first position#2018-12-1116:31borkdudeI did exactly that#2018-12-1116:31borkdude(although I didn’t make use of it eventually)#2018-12-1116:32Ben GrabowYou guys thought of it while I was testing it out. Seems to work fine if you swap the arg order and use partial
.
(def memo-test
(memoize (fn [y x]
(do (Thread/sleep 1000)
(+ x y)))))
(def par-y (partial memo-test 10))
(par-y 5) ; => (wait 1 sec) 15
(par-y 5) ; => (no wait) 15
#2018-12-1117:32namenuOkay, I found super interesting idea called Y combinator and switched to it. 😊
https://blog.klipse.tech/lambda/2016/08/07/pure-y-combinator-clojure.html#2018-12-1116:18misha"Elapsed time: 2826829.717059 msecs"
tatatananana#2018-12-1117:18potetmI know day 10 has come and gone#2018-12-1117:18potetmbut that link @mfikes posted has haunted me: https://blog.jle.im/entry/shifting-the-stars.html#2018-12-1117:18potetmSo here’s the solution in clojure#2018-12-1117:18potetm(defn centralize [pnts]
(matrix/sub pnts
(matrix/div (reduce matrix/add
pnts)
(count pnts))))
(defn sum-of-dots [xs ys]
(reduce +
(map matrix/dot
xs
ys)))
(defn the-t [stars]
(let [vs (centralize (map :vel stars))
xs (centralize (map :pos stars))]
(long (- (/ (sum-of-dots xs vs)
(sum-of-dots vs vs))))))
#2018-12-1117:19potetm(expects a list of {:pos [x y], :vel [x y]}
#2018-12-1117:43helios@misha only 50 minutes!? 😄#2018-12-1117:56ccannwould anyone be willing to take a look at my day 11 part 2 solution and tell me why it’s so SLOW?
https://gist.github.com/ccann/fe69ba05140566e5a04855a5c96380ba#2018-12-1117:57potetmfor the interested: https://www.twitch.tv/timpote#2018-12-1118:09pesterhazyHere's my Day 11: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle11.clj#L40 Elapsed time: 186939.868152 msecs
#2018-12-1118:09pesterhazyI ended up pre-calculating "hblocks", all blocks of size 1x1, 2x1, 3x1, etc.. up to 100x1#2018-12-1121:18fellshardOooh, that's another good way to break it down#2018-12-1118:10mfikesDay 11: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_11.cljc#2018-12-1118:11misha@helios kappa did not cache pairs, only rectangles, so "prime"-width squares calculation was killing me. did not bother to rewrite again yet.#2018-12-1118:14misha@pesterhazy that's what I'd do next, or may be precalculate row/col triplets.
another idea is to use subtraction, rather than only addition. but that requires to think through order of calculation, so when you calc 19x19, you have not only 18x18 + row + col, but 20x20 as well, from which you ca subtract 18x18-and-change#2018-12-1118:18pesterhazy@mfikes how long does your solution take with or without pmap?#2018-12-1118:19mfikesWith pmap
about 80 seconds, but I have a dual hexacore. I haven’t done it without that, but am letting the ClojureScript version run now.#2018-12-1118:19pesterhazyI'm running your code right now and my laptop it sounding like the Concorde#2018-12-1118:19mishafuture is now#2018-12-1118:20borkdudeI have a version that does it in 76 seconds without pmap on a Macbook Pro, but it’s heavily memoized#2018-12-1118:21borkdudeoh yours computes all solutions, that’s impressive#2018-12-1118:21pesterhazythe (->> (for []...) (apply max-key first))
idiom comes up quite often#2018-12-1118:21pesterhazye.g. https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle11.clj#L60#2018-12-1118:23pesterhazythat can't be efficient but .. hm maybe (reduce #(max-key first a b))
is better#2018-12-1118:24borkdude@pesterhazy https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_11.cljc#L8#2018-12-1118:24pesterhazyeven better would be if I didn't have to create a vector on each iteration#2018-12-1118:25mfikesI had a version that pre-calculated everything as vectors. It was only marginally faster for some reason.#2018-12-1118:26pesterhazymy hblocks version is definitely faster than brute forcing#2018-12-1118:28heliosMy pmap version just outputs "Davide, do we "#2018-12-1119:35pesterhazyOnce again Reddit knows the real solution: https://en.m.wikipedia.org/wiki/Summed-area_table#2018-12-1119:42Average-user@me1740 Uploaded a version using summed-area table#2018-12-1120:00pesterhazyNice.#2018-12-1120:02Average-userI'm gonna try to implement my own version now#2018-12-1120:10pesterhazyi'd really like to see a comparison to Java#2018-12-1120:13pesterhazyThe 8s for the Clojure version seem way too slow#2018-12-1120:13pesterhazyThis c++ version runs in 58ms for me: https://www.reddit.com/r/adventofcode/comments/a53r6i/2018_day_11_solutions/ebjogd7/#2018-12-1120:24benoitYeah numerical methods in Clojure is not my forte 🙂 I would love to see improvements on this approach.#2018-12-1120:43gklijsI don't even going to try porting my current java solution to java, part 2 is done in 200ms now, will probably be 20 seconds in clojure..#2018-12-1120:54Average-userAnd btw, your 8s solution takes 35s to me#2018-12-1120:54Average-useradventofcode-clj-2018.day11> (time (part-1))
"Elapsed time: 645.790007 msecs"
[[[243 16] 3] 31]
adventofcode-clj-2018.day11> (time (part-2))
"Elapsed time: 36696.154969 msecs"
[[[231 227] 14] 129]
This is what I managed to do so far#2018-12-1120:55Average-userwhich is about the same times that takes @me1740s solution to me#2018-12-1123:45fellshardThinking back on my solution again, and I think you could optimize it by keeping track of the last two 'layers' only - so at size 10, you only need sizes 9 and 8.
Add: <x,y>, <x+1,y>, <x,y+1>, <x+1,y+1> in layer 9
Subtract: 3 * <x+1,y+1> in layer 8
Currently I hold onto way too many old layers, because I keep track of my unit-size squares and floor(size/2)
squares on up, hence my memory management problem.
(This is definitely a standard 'convolution' problem, and I can't help but wonder if there's some tools to be drawn from that world...)
And now thinking on this, this is pretty much one step removed from the summed-area listed above, which uses a constant amount of memory... now I need to dig deeper!#2018-12-1200:02Ben GrabowThere's some really beautiful symmetry in creating the summed area table:
(defn summed-area-table [colls]
(->> colls
(map #(reductions + %))
(reductions #(map + %1 %2))))
#2018-12-1202:26Average-userwhat would it colls
be here?#2018-12-1202:30Ben Grabow(for [y ys]
(for [x xs]
(f x y)))
Rows nested in columns, basically.#2018-12-1202:31Ben GrabowOn mobile right now so apologies for any errors in that code.#2018-12-1205:06minikomishit.. forgot this was going on hahaha#2018-12-1205:07minikomihaving fun everyone?#2018-12-1205:48mattlyanyone have a strategy for part 2? 😄#2018-12-1205:49mattlycrap, there are people who've done it already#2018-12-1205:49mattlythere must be some super-efficient algorithm for this#2018-12-1205:58mattlyah, apparently the pattern stabilizes#2018-12-1206:09taylorjust started on this one and I don’t understand how to handle the negative range?#2018-12-1206:09mattlyheh#2018-12-1206:09mattlythat#2018-12-1206:09taylordoes it go on forever?#2018-12-1206:09mattlygot me really good#2018-12-1206:09mattlyyes#2018-12-1206:09mattlyat least in theory#2018-12-1206:10taylorso in both directions, you have to find when the pattern stops producing new plants or something?#2018-12-1206:10mattlyyep#2018-12-1206:11taylornot very well described problem#2018-12-1206:11mattlyit could have been clearer#2018-12-1206:18fellshardIt's weirder than 'stops producing new plants...' at least with my input#2018-12-1206:18mattlyso, part 2 asks you to solve for 50 billion iterations#2018-12-1206:19mattlyi'm "cheating" for the first time and checking reddit#2018-12-1206:19mattlyand#2018-12-1206:19mattlymost people aren't simulating it#2018-12-1206:21Average-userlast year there was a similar problem, where the solution was to find a cycle#2018-12-1206:22mattlyyeah#2018-12-1206:29mattlyyeah, indeed#2018-12-1206:31normanugghh.. done.. I disliked this problem a lott#2018-12-1206:32Average-userhow did you do it?#2018-12-1206:35norman.. in a very non-robust manner. At first I storing the prior states looking for a repeat. No exact state repeated, but it when I normalized (removed the leading/trailing dots) it repeated with a cycle length of one.#2018-12-1206:36fellshardThanks for the tip, mattly ^^#2019-12-0504:52dpsuttonhttps://github.com/dpsutton/advent/blob/master/2019/src/advent/04.clj did it in core.logic. would love people more familiar with it to critique. i know there has to be some more clever bits#2019-12-0505:24fingertoeWell, the new one is going to take some study… 😉#2019-12-0505:34kenjI’m really digging the build-a-cpu aspect of it#2019-12-0505:37mpcjanssenI guess I reached the limit of doable on phone today.#2019-12-0506:50mishawhoever complained about puzzle description yesterday, how do you like it now? lol#2019-12-0507:04mishaespecially the compare it to the value 8
bit. wtf is that about?#2019-12-0507:30genmeblogI can't find it in the text... (in part 1)#2019-12-0507:45fellshardThose are sample programs, as he notes. You can try running them / stepping through them to get the behaviour he says it will have (in this case, comparing numbers to 8 in various ways). Use them as test cases for your implementation before trying to run your full program.#2019-12-0508:00mishathat is some unnecessary complication/indirection for test cases, which is useless, unless your implementation fits. instead of just "this (much shorter) input returns x", which is implementation agnostic, although more blackboxy#2019-12-0508:16fellshardSure, he could have made some shorter. You can always test each instruction in isolation if you want. He's giving slightly larger test cases that make for 'full programs', though, from input to output; call them integration tests.#2019-12-0508:57yendaI didn't even read the tests lol, just added the 4 new instructions#2019-12-0508:57yendathere was too much text today 😄#2019-12-0509:09fellshardYou ain't seen nothin' until you've solved 2018-15. https://adventofcode.com/2018/day/15
(That problem gained quite a bit of infamy for being very fiddly to solve, and taking a whole bunch of space to thoroughly explain to boot)#2019-12-0510:17mishaI think I just printed output to figure it out, then#2019-12-0510:18mishayenda, i read tests when description is unclear, so tests screwed me over even more today opieop#2019-12-0507:09mishaand shouldn't this
Parameters that an instruction writes to will never be in immediate mode.
be
Parameters that an instruction writes to will never be in position mode.
?#2019-12-0507:44fellshardBasically, ignore the mode for that parameter - always treat the parameter's value as the address to output to.#2019-12-0507:56mishathe thing is, my code works only for opposite: when it is literal v
:
1 (recur idx* output (assoc state c (+ A B)))
instead of
1 (recur idx* output (assoc state (state c) (+ A B)))
#2019-12-0507:57mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2019/day05.clj#L40-L47#2019-12-0507:58mishaI lost like 40 minutes chasing this#2019-12-0508:20fellshardCorrect, that's position mode by definition.#2019-12-0508:20fellshardposition mode = 'the value in the cell is an address' (whether for input or output)
immediate mode = 'the value in the cell is a concrete value' (for input only)
You're assuming 'position mode' also means 'get the value from the addressed cell and use that as the address to output to', which is stretching the definition of 'position mode' one step too far. The mode only tells you how the parameter's value is to be interpreted: the action you take with the parameter depends entirely on the command's context. For positional inputs, you read from the address. For positional outputs, you write to the address.#2019-12-0508:28mishaall I can say – I don't interpret the description as unambiguously as you do.#2019-12-0508:31misha(given context, which is load of text from both day 5 and day 2)#2019-12-0508:36pesterhazypositional: "interpret v as a pointer"
intermediate: "interpret v as a value"#2019-12-0508:37pesterhazyyou can only write to a pointer, a mutable container; you cannot conceptually write to an immutable value#2019-12-0507:25genmeblogIt should be in position mode. It writes to the address. So it's ok.#2019-12-0508:07mishayes, but the value of address to write to is always in immediate mode (for my input anyway).
maybe I am confusing myself by thinking about it as:
in immediate: (f x) => (f x)
in position: (f x) => (f (get state x))
but in my solution, I never do
(update state (get state x) ...)
, instead all of instruction do:
(update state x ...)
, which is pretty immediate
to me#2019-12-0508:07misha(where state is a mutable puzzle-input vector)#2019-12-0508:45genmeblogfrom this perspective, yes, I have to agree.#2019-12-0507:25genmeblogI don't get this sentence: Non-zero outputs mean that a function is not working correctly; check the instructions that were run before the output instruction to see which one failed.#2019-12-0507:26genmeblogWhat the 'check' means here?#2019-12-0507:27genmeblogAnd how to make to get 0's for all test outputs?#2019-12-0507:34fellshardSimilar to what he made for the Synacor challenge#2019-12-0507:35fellshardtl;dr the program's first section checks for specific bugs in your implementation. For each of those tests, if it passes, it spits out a 0
in the output.#2019-12-0507:35fellshardSo a successful run of the first part should be 0 0 0 0 0 0 ... 0 0 <diagnostic code>
#2019-12-0507:36fellshardIf something did go wrong in your implementation, you could use the output to help you pin down where it's going sideways#2019-12-0507:36fellshardBut it'd take some doing#2019-12-0507:36fellshardVisualization for day 5: http://quil.info/sketches/show/e73e5daea052772c66ae391140ede3fd1c0ff6ebe950476b8e85bb10f0769980#2019-12-0507:39genmeblogAaah... I understood this checks provided code not my implementation. Clear now.#2019-12-0507:51Jett DurhamYeah, this confused me too at first. Made me think we might have to modify the instructions in our code! 😅 To me, it seems unlikely that you’d actually have a solution that yields non-zero intermediate results and actually executes all the way to the terminating opcode.#2019-12-0508:08fellshardThat part wasn't the clearest stated. I only caught on because I've seen him use it before. 🙂#2019-12-0508:38pesterhazyToday was smooth sailing, mostly reading comprehension (again in Typescript: https://github.com/pesterhazy/advent2019/blob/master/typescript/src/puzzle05.ts)#2019-12-0508:58mpcjanssenJust soldiered through on phone. Day 5 done#2019-12-0508:59mpcjanssenTricky part was the targets are never in immediate mode part#2019-12-0509:02mpcjanssenAgain the key was to make small fns#2019-12-0509:03pesterhazyOn phone? I can’t even..#2019-12-0509:18mpcjanssenI was planning to stop today#2019-12-0509:18mpcjanssenBut with small enough steps it was doable#2019-12-0509:21mpcjanssenhttps://github.com/mpcjanssen/aoc2019/blob/master/day05.ipynb#2019-12-0509:33mchampineOof. That was rough. Completed Day 5, but my code is too ugly to share. My “program step” function consisted mostly of “case opcode” statements to update the program and calculate the next instruction offset. I think if I refactored it, I’d have a single function per opcode that would return the altered program and next program counter.#2019-12-0521:58rjrayThat's basically what I did: https://github.com/rjray/advent-2019-clojure/blob/master/src/advent_2019/day05.clj#2019-12-0521:58rjrayIf we add many more instructions to this VM, though, I'll probably move the dispatch to a vector.#2019-12-0509:45mpcjanssenI pass around a state map with mem, input, output, ip and halted keys.#2019-12-0509:46mpcjanssenSo the opcode handlers can update the ip.#2019-12-0509:46mpcjanssenAlready made that choice on day2 and it worked well today#2019-12-0511:36dmarjenburghHere’s my take. Rather stateful code :man-gesturing-no::skin-tone-3: https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L80-121#2019-12-0512:25uoslafter some cleanup it actually became quite readable [=
https://github.com/uosl/advent-of-code/blob/master/src/aoc2019/05.clj#2019-12-0518:11jrwdunhamNice! I like the use of reduce
and the (format "%04d" code)
to unify the calculation of the positional vs. immediate values. I used a recursive strategy: https://github.com/jrwdunham/aoc2019/blob/master/src/dec05/core.clj#L19-L60#2019-12-0519:21uoslThanks. Apart from those two differences (and you keeping track of input
) our solutions are pretty similar!#2019-12-0515:22mpcjanssenThe drop off in completed answers for today is huge#2019-12-0516:08James AdamYea, I looked at the problem description early this morning and decided I'd tackle it after work tonight 🙂#2019-12-0516:45Mario C.Day 5 description wasn't bad. I had to rewrite the intcode program though. Didn't like my day 2 solution. Day 5 part 2 was easy so long as what you wrote for part 1 was 'extendable' for a lack of a better term#2019-12-0516:47Mario C.Most functions were repeated code. So I could have probably had a wrapper that passed in the operation function while keeping the rest the same.#2019-12-0516:49Mario C.Day5 problem reminds me of my class on automata in college. Where you create DFA's and NFA's and there was the one where you have a tape. and you can move left or right#2019-12-0516:52fellshardYeah, mostly because the data here is sitting in the same space as the instructions, and under theory he could build programs that mutate their own code on the fly.#2019-12-0516:53Mario C.turing machine#2019-12-0520:12roman01laHere’s my 5th day https://gist.github.com/roman01la/875d7c0c3cc8b75267730559b5d96251#2019-12-0520:19roman01laThe part about always treating write location as a pointer instead of a value could be indeed confusing from implementation standpoint.
Here https://gist.github.com/roman01la/875d7c0c3cc8b75267730559b5d96251#file-day5-clj-L9-L10 in writable instructions 1, 2, 3, 7 and 8 I’m treating location as a value (“immediate” mode or 1
) because it allows to keep parameter interpretation code simpler https://gist.github.com/roman01la/875d7c0c3cc8b75267730559b5d96251#file-day5-clj-L30-L35#2019-12-0520:26roman01lamy understanding is that you want to interpret write location as a value instead of a pointer, because the value is used to assoc something onto memory object, otherwise you’d first have to retrieve the value of the pointer and then use that value to assoc onto the memory, which is incorrect#2019-12-0520:57fellshardYeah, your first instinct is to use the same logic as you would for position-mode input, but that's inevitably not right. I did the same at first, then realized I needed to just excise output parameters entirely and not pass them through the mode filter.#2019-12-0521:32ChaseCan someone help me refactor this function from day 1 into using reduce
or something more idiomatic? I still can't break myself off of immediately going to loop/recur
#2019-12-0521:32Chase(defn total-fuel-mass [mass]
(loop [remaining mass
total 0]
(let [mass (fuel-mass remaining)]
(if (pos? mass)
(recur mass (+ total mass))
total))))
#2019-12-0521:34fellshardI'd recommend looking into iterate
. When there isn't an explicit sequence to reduce over, and when creating one doesn't make sense either, iterate
gives similar mechanics. I use it a lot in AoC, where many problems are run until you reach a fixed point.#2019-12-0521:38ChaseWill do! Thanks#2019-12-0521:46ChaseI think I'm close already! But I'm missing something crucial because I'm getting an answer that is too high.#2019-12-0521:46Chase(defn total-fuel-mass [mass]
(reduce + (take-while pos? (iterate fuel-mass mass))))
#2019-12-0521:48Chaseformatting looks funky here from my copy and paste but it's lined up correctly in my editor.#2019-12-0521:48tschadyskip the first element#2019-12-0521:49tschady(defn total-fuel
"Return the fuel units required to launch a module of given `mass`,
including the mass of the fuel carried."
[mass]
(->> mass
(iterate mass->fuel)
rest
(take-while pos?)
(reduce +)))
#2019-12-0521:50tschadyfirst run through iterate
is the mass of the ship, which you don’t need#2019-12-0521:50Chaseahhh! I should have spotted that when I was exploring it in the repl.#2019-12-0521:50Chasethanks folks!#2019-12-0521:58rjrayThat's basically what I did: https://github.com/rjray/advent-2019-clojure/blob/master/src/advent_2019/day05.clj#2019-12-0521:58rjrayIf we add many more instructions to this VM, though, I'll probably move the dispatch to a vector.#2019-12-0522:01rjray(Funny side-note: I mis-read the bit about only being allowed one private leaderboard, to mean that I could only BE on one private leaderboard at a time. So I hadn't joined the channel's leaderboard as I was already on a private one for fellow AoC enthusiasts within my company. Just joined, and thrilled to see I'm in 3rd place!)#2019-12-0522:40Average-userhttps://github.com/Average-user/adventofcode-clj-2019/blob/master/src/adventofcode_clj_2019/day05.clj#2019-12-0523:05chrisblomI was getting behind, did 3,4 and 5 today: https://github.com/ChrisBlom/advent-of-code/tree/master/src/adventofcode/2019#2019-12-0600:43erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day5.clj#2019-12-0602:11lilactownI’m getting a position of -80
in my input#2019-12-0602:11lilactowndid anyone else encounter this?#2019-12-0602:35mpcjanssenYes I got invalid positions when my implementation was wrong 😉#2019-12-0602:39mpcjanssenAre you always interpreting the target parameter as the address value without looking up the value st the address? That was my error#2019-12-0603:31fellshardI may actually expand my visualization to serve as a diagnostic panel if this machine continues expanding in the future.#2019-12-0603:31fellshardMakes for easier debugging of issues like that if you can also expose intermediary steps, like the mode-interpreted values.#2019-12-0603:37fellshardHmm. You could even time-travel it by storing a stack of state-diffs...#2019-12-0604:00potetmhttps://github.com/potetm/advent-of-code/blob/master/src/advent_2019/day_5.clj#2019-12-0604:00potetmugh gotta stop checking in my puzzle inputs#2019-12-0604:02potetmsomehow mine’s the first non-loop-recur solution I’ve seen#2019-12-0604:04potetmah just saw uosl’s#2019-12-0604:05potetmbasically the exact same approach#2019-12-0604:06Ben Grabowiterate
is just a great general purpose way to unroll a loop-recur#2019-12-0604:06Ben GrabowSo much easier to inspect the result and compose it with other data#2019-12-0604:06potetmuse iterate, pull out all your immediate/position vals, and case
it#2019-12-0604:07potetmyeah.. well#2019-12-0604:07potetminspecting output wasn’t super duper for this problem#2019-12-0604:07potetmbig long list of numbers#2019-12-0604:07potetmbut ordinarily, yeah#2019-12-0604:08potetmReally, for me, I reach for it because it’s easier to think about a single input/output than to think about flow control.#2019-12-0604:08Ben GrabowI think I resisted iterate
for day 5 because checking the terminate condition requires unpacking the step function a little#2019-12-0604:08potetmunpacking?#2019-12-0604:09Ben GrabowEr, breaking the pattern. Like you used ::halt
as your return value#2019-12-0604:09potetmright, sig term#2019-12-0604:09Ben GrabowNormally I like to write my iterate step function so it "could" run forever, and it's the consumer's decision when to stop it#2019-12-0604:10potetmyeah I considered returning the same input#2019-12-0604:10Ben GrabowI couldn't think up an obvious way to do that here so I went the fn-recur route#2019-12-0604:10potetmthen I was like, “What are you some kind of zealot?”#2019-12-0604:10Ben Grabowyeah you could return a fixed point#2019-12-0604:10Ben Grabowlol#2019-12-0604:11potetmwhat nobody sees don’t hurt em I figure#2019-12-0604:11Ben GrabowRich Hickey is watching you code#2019-12-0604:11potetmiow implementation detail#2019-12-0604:11potetmyou ain’t read a lot of rich’s code#2019-12-0604:11potetmapparently#2019-12-0604:11potetm😄#2019-12-0604:12Ben Grabowhaha, sometimes I wonder wtf happened when I peek into a core function's implementation#2019-12-0604:12potetmdude do it#2019-12-0604:12potetmI do all the time#2019-12-0604:12Ben GrabowIt's like the least lispy, most complicated thing internally#2019-12-0604:12Ben Grabowbut outside it's a beautiful flower#2019-12-0604:12potetmyeah, consider volatile
#2019-12-0604:13Ben Grabowcan I not#2019-12-0604:13potetmDO YOU WANT SIMPLE OR COMPLECTED???#2019-12-0604:14potetmreally, it’s, like, a pragmatists view#2019-12-0606:15mishawell, core should be fast so that userspace could afford to be readable#2019-12-0604:14potetm“Simple is nice. Working is better.”#2019-12-0604:14Ben GrabowI can respect the person who hands me a gun when I say I want to shoot myself in the foot#2019-12-0604:14potetmexactly#2019-12-0604:14potetmhow very… American#2019-12-0604:15potetmugh, I only just finished day 5#2019-12-0604:15potetmand day 6 is out in 45min#2019-12-0605:06lilactown> Parameters that an instruction writes to will never be in immediate mode.
this is the part I think my solution fails at#2019-12-0605:07lilactownwhat is that supposed to mean?#2019-12-0605:11potetmyou always write to the position that the param says#2019-12-0605:11potetmyou never dereference the param and then write#2019-12-0605:12potetmwhere write means “update the program state”#2019-12-0605:19kenjWell day 6 problem description got vague at the end #2019-12-0606:15mishawell, core should be fast so that userspace could afford to be readable#2019-12-0606:18mishavisuals made it instantly obvious what's required, to me.#2019-12-0606:33fellshardGraphViz to the rescue!#2019-12-0607:09mchampineDay 6, was way easier than day 5 thank goodness. Part 1. Get the list of nodes by putting all the node names into a set, then follow the chain of orbits back to “COM” and sum all the chain lengths. Part 2. Find the first common node in the chains from “YOU” and “SAN” to back to “COM” and count the links to that common node.#2019-12-0608:10yendapart 1 what do you mean by putting all the node names into a set? I put them into a map to follow the chain of orbits back to COM
part 2 I put both chain of orbits into a set, count the diff, add both counts minus diff#2019-12-0608:29mishaI replaced my transducers solution with a sets one, and it went from 1.5ms to 3.5ms :)
https://github.com/akovantsev/adventofcode/commit/c3b234ecaacd2014d360c4e20ee946086e6b5e73#2019-12-0610:49yendaTry set/intersection of p1 and p2 instead then sum of both counts - 2 diff#2019-12-0611:10mishanah, not as readable#2019-12-0616:49Ben Grabow(defn set-symmetric-difference [s1 s2]
(set/difference (set/union s1 s2) (set/intersection s1 s2)))
(count (set-symmetric-difference p1 p2))
#2019-12-0607:31mpcjanssenmain thing is to make a a orbits b data structure not b is orbited by a as it is in de data#2019-12-0608:41dmarjenburghToday was easier than yesterday. Solution for both in 7 lines total:
https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L123-129#2019-12-0609:50uoslThat iterate with a map as the first argument is awesome#2019-12-0609:26fellshardElegant! Good call that you don't need to find the least common ancestor - any ancestor will do#2019-12-0609:43uoslI can't be the only one who found make-hierarchy
perfect for day 6?#2019-12-0610:49erwinrooijakkersI looked at this before solving it. I will try! 😄#2019-12-0610:49erwinrooijakkersNever used it#2019-12-0611:45erwinrooijakkers(def input
(->> (-> (io/resource "2019/day6.txt")
slurp
(string/replace #"\)" "\n")
(string/split-lines))
(map keyword)))
(def universe
(atom (make-hierarchy)))
(defn add-orbit! [p1 p2]
(swap! universe derive p1 p2))
(defn add-orbits! [input]
(doseq [[p1 p2] (partition 2 input)]
(add-orbit! p1 p2)))
(defn count-orbits [p]
(let [ps (parents @universe p)]
(if (zero? (count ps))
0
(apply + (count (ancestors @universe p)) (map count-orbits ps)))))
;; Part 1
(add-orbits! input)
(count-orbits :COM)
StackOverFlow error 😉#2019-12-0611:49uoslThe hierarchy doesn't need to be in an atom, just pass it around like a first-class citizen.
You might have to forgo tree recursion as well to avoid the overflow.
If you want to see how I solved it: https://github.com/uosl/advent-of-code/blob/master/src/aoc2019/06.clj#2019-12-0611:51erwinrooijakkersThis works:#2019-12-0611:51erwinrooijakkers(defn count-orbits [planets]
(apply + (map (comp count (partial ancestors @universe)) planets)))
#2019-12-0611:51erwinrooijakkersWhere planets set of the planets#2019-12-0611:52erwinrooijakkersI’ll check your answer later puzzle around for 2 first 😉#2019-12-0611:53uoslGood luck [=#2019-12-0611:59erwinrooijakkersAh I changed it without the atom, just the global hierarchy 😉#2019-12-0611:59erwinrooijakkersHehe#2019-12-0612:27erwinrooijakkersNice use of reduce
!#2019-12-0611:50roman01lafinished my day 6 https://gist.github.com/roman01la/eba8c713949f4e115c50488eecf0e3e8#2019-12-0612:41erwinrooijakkersInspired by the make-hierarchy
comment of @regen I decided to misuse the global hierarchy: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day6.clj#2019-12-0612:45chrisblomnice, that is a clever hack#2019-12-0613:18tschadyyou can do the last bit with just set operations.
(defn part-2 [input]
(let [orbits (make-hier (map parse-rel input))
ys (ancestors orbits :YOU)
ss (ancestors orbits :SAN)]
(count (set/difference (set/union ys ss) (set/intersection ys ss)))))
#2019-12-0613:18tschady(same make-hierarchy as the last few, i did not know about that core function!)#2019-12-0615:21erwinrooijakkersI see. Why does that work? 😛#2019-12-0615:30erwinrooijakkersAaaahh#2019-12-0615:30erwinrooijakkersnice#2019-12-0616:26potetmbroke down and finally learned ubergraph this year
https://github.com/potetm/advent-of-code/blob/master/src/advent_2019/day_6.clj#2019-12-0616:29erwinrooijakkersNice#2019-12-0619:53Mario C.Damn didn't even know make-hierarchy
existed. That basically did all the work lol#2019-12-0620:41erwinrooijakkersDid you look at @potetm? ubergraph
does even more 😛
(let [g (graph (parse s))]
(- (uga/cost-of-path (uga/shortest-path g "YOU" "SAN"))
2)))
#2019-12-0622:21fellshardI may have to see about swapping my usual JGraphT dependency for Ubergraph...#2019-12-0622:21fellshardit works pretty well with Clojure, but staying in purely idiomatic Clojure would be nice.#2019-12-0622:27Average-userI did it just with a Map. I think it worked out okay
<https://github.com/Average-user/adventofcode-clj-2019/blob/master/src/adventofcode_clj_2019/day06.clj>#2019-12-0704:06jrwdunhamWhoah, pretty much all the solutions to Dec6/pt1 saw that you could just add all of the distances from each node to the root. I didn't see that so I added each node's orbiter count multiplied by the depth of the node—about an order of magnitude less efficient, but still works:#2019-12-0704:06jrwdunham(defn count-orbits
([orbits] (count-orbits orbits 1 :o-COM))
([orbits depth node]
(let [orbiters (get-orbiters-of node orbits)] ;; (:o-A :o-X)
(if (seq orbiters)
(+ (* depth (count orbiters))
(->> orbiters
(map (fn [orbiter] (count-orbits orbits (inc depth) orbiter)))
(reduce +)))
0))))
#2019-12-0706:12fellshardPart 2 is a doozy and I love it.#2019-12-0706:13fellshardI have no idea how I'm gonna visualize this, though, hahahah#2019-12-0706:26fellshardSeriously, though, twists like this are what make me love these challenges. And I'm glad he's steadily building on the same machine this year.#2019-12-0706:41meikemertschI have real trouble understanding how part 2 is supposed to work… 😢#2019-12-0706:44meikemertschCan anyone explain part2 without spoilers?#2019-12-0706:54fellshard• Each amplifier is given their phase as their first input, just like in part 1.
• Amplifier A receives input '0'.
• Amplifier A runs and emits 1 or more elements to output.
• Amplifier A tries to read an input, but has no input to read yet, and so we'll hold off on evaluating it further for now.
• Amplifier B consumes A's outputs as its new inputs.
• Amplifier B runs and consumes its inputs until it runs out, emitting outputs for C to consume
• ...
• Etc., until E emits outputs for A to consume as inputs.
• ...
• Eventually, all the machines will formally halt (opcode 99), and when the last machine does, its output is the output of the array as a whole.#2019-12-0706:54fellshard(This is just a rephrasing of the information as it exists in part 2)#2019-12-0706:55meikemertschOOOOOOHHHHH!#2019-12-0706:56meikemertsch“so we’ll hold off on evaluating it further for now”
THAT!#2019-12-0706:56meikemertschI think I get it now… Thanks#2019-12-0706:56meikemertschNow I just have to figure out how to do this 😂#2019-12-0710:24pesterhazyThey key is to understand that there are multiple VMs running now, each yielding to the next while keeping state (never need to reset now)#2019-12-0713:12uoslI'm very confused. Aren't the amplifiers only supposed to send the thruster signal to the next amp, each amp in turn increasing this number?
Or do all of the amplifiers have their own thruster signal state, which only that specific amp increases, only to be added up when it finally halts? (And then communicating with the other amps via in/out signals that don't hold the actual thruster signal.)#2019-12-0713:40yendaWhen you hold off evaluating further because you have no more inputs, do you keep the offset and resume from where you suspended in the next iteration?#2019-12-0714:02fellshard@UCW9TUDNK Each amplifier consumes inputs and generates outputs; those outputs are fed as inputs to the next amp in the chain, as shown in the pictures.#2019-12-0714:03fellshard@U0DB715GU Correct. You can think of it as 'the amp is still running, but it's waiting for the 'in' operation to complete'. Similar to a CPU idling until data arrives from disk.#2019-12-0710:25pesterhazy> And I'm glad he's steadily building on the same machine this year.
Yes but... I had a bug apparently in my previous code (of the "why did this work before" variety) so that took me a while to debug.#2019-12-0712:23uoslugh. today's part 2 is going to eat my whole weekend#2019-12-0712:49erwinrooijakkers+1#2019-12-0713:25yendaMy part 2 is working for examples but doesnt halt with puzzle input :/#2019-12-0713:40mpcjanssenfinally finished part 2. solution is horrible though#2019-12-0713:43mpcjanssenNote to self: don't try to print infinite lazy seqs#2019-12-0805:59misha(set! *print-length* 20)
=> 20
(println (range))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...)
=> nil
#2019-12-0713:44mpcjanssenSeemed it wasn't halting actually was trying to print a lazy seq#2019-12-0714:04fellshardI can't tell you the number of times I've had to kill cider because I did that in AoC.#2019-12-0714:15mpcjanssenHaskell does that better#2019-12-0714:16mpcjanssenI did run a bit into nested data structure confusion this round. Curious to see how others did it.#2019-12-0714:32enforserI always make sure to set https://clojuredocs.org/clojure.core/*print-length* and https://clojuredocs.org/clojure.core/*print-level* if I’m printing off large/lazy structures#2019-12-0715:08mpcjanssenAnd TIL#2019-12-0715:27erwinrooijakkersSolution using core.async:
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day7.clj#2019-12-0719:02fellshardI was wondering if someone would use channels :)#2019-12-0800:28Average-userI did something very similar. Just quite messier#2019-12-0801:14DannyI also did something similar, but I didn't use a go-loop... then had to deal with blocking IO. Argh!
Should definitely have used a go-loop! Great job#2019-12-0802:56namenuwow, great idea!#2019-12-1016:09erwinrooijakkersI see the comments now. Thanks! 🙂 I didn’t see a way to solve the problem by passing state, but it is clearly possible looking at other solutions. I am also curious about ideas with other constructs that pass data from one process to another.#2019-12-1017:20fellshardIn this case, you can basically do it by forcing the asynchronous system to be fully synchronous; you impose some global order of execution across all amplifiers, and hop from one to the other as needed. It certainly feels kludgier, though. :)#2019-12-0716:22pesterhazyInteresting @erwinrooijakkers, though it feels core.async is not an exact fit for the problem, as asynchronous operations is not necessary to solve it#2019-12-0716:23pesterhazyPython generators (or ES6 generators in JS) are a better fit - do these have an implementation in Clojure?#2019-12-0716:54mpcjanssenJust exhausting all input and continue running tje next amp works also but that is basically a manual yield#2019-12-0717:33dmarjenburghUgh, got part 1 pretty quickly, but for part 2 I had to refactor a large part of the intcode machine. I used core.async too. Will share later.#2019-12-0717:34pastafariHallo Clojurians - for Day 7, I am trying to figure out how can I feed input to the amplifiers.
Context, my Intcode interpreter uses (read-line)
for opcode 3 which reads from IN (ps: please read this as "star in star", Slack turns it into bold!).
I've been exploring binding IN to a Reader that will successively return phase and input on each call to read-line. The default impl. of IN is a LineNumberingPushbackReader that wraps System/in.
I want to make my own LineNumberingPushbackReader that closes over phase and input and returns them on succesive calls to read-line.
My Clojure is a bit rusty, so I'm not exactly sure about the best way to proceed. Any tips?#2019-12-0717:37dmarjenburghLike this?
(with-in-str "line1\nline2"
[(read-line) (read-line)])
; => ["line1", "line2"]
#2019-12-0717:38pastafariSuper!#2019-12-0717:39pastafariThanks much 🙂#2019-12-0717:40pastafariI knew about with-out-str , never searched for with-in-str!#2019-12-0717:53meikemertschIn the end I am pretty happy with my solution. I always am if I can use the same code for part 1 and 2 (I realize that my code is rather a beginner level… but in the end I get it somehow done 😆). Thanks to @fellshard for the explanation so I could finally understand what was going on! 🙏 <https://github.com/MeikeMertsch/AoC_2019/blob/master/src/christmas/day07.clj>#2019-12-0719:44dmarjenburghhttps://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L144-181#2019-12-0722:26lilactownI am still really struggling with day5#2019-12-0722:26lilactownI keep running up against this instruction:
("101" "-80" "224" "224")
#2019-12-0722:26lilactownthis seems to be saying "read position -80" which doesn't make sense#2019-12-0722:27lilactownI've completely rewritten my code a couple times now. my intcode computer passes day2 and and all test cases I've found so far#2019-12-0722:43lilactownall of my diagnostic codes come back 0#2019-12-0722:45uoslDoesn't "101" mean read 1st parameter in immediate mode, so -80 should be interpreted as a value?#2019-12-0722:48lilactownAFAICT "101" would be padded to "00101"?#2019-12-0722:49lilactownoh foo#2019-12-0722:49lilactown> read right-to-left from the opcode#2019-12-0722:51pastafari@lilactown I struggled with something similar, and then found a line in the instructions "Parameters that an instruction writes to will never be in immediate mode." - this line seems contradictory to me, but that was the problem with my code!#2019-12-0723:01potetmhttps://github.com/potetm/advent-of-code/blob/b9b3758ef83dcea200eb93b62e3cbeb7efb4a3b1/src/advent_2019/day_7.clj#2019-12-0723:07lilactownyeah I misread the problem, I was reading the modes left-to-right 😵#2019-12-0723:07lilactownvery frustrating#2019-12-0805:59misha(set! *print-length* 20)
=> 20
(println (range))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...)
=> nil
#2019-12-0801:46mpcjanssenMy messy iterative solution https://github.com/mpcjanssen/aoc2019/blob/master/day07.ipynb#2019-12-0802:50Average-userI was looking to some clever solutions using Haskells lazy evaluation:
amplify program [a,b,c,d,e] = last oute
where outa = intcode (a:0:oute) program 0
outb = intcode (b:outa) program 0
outc = intcode (c:outb) program 0
outd = intcode (d:outc) program 0
oute = intcode (e:outd) program 0
#2019-12-0802:50Average-userWould something like that possible in Clojure?#2019-12-0802:58potetm@lucaspolymeris you have a link to the full program?#2019-12-0802:59Average-userYep, give ma sec. But anyway, intcode is just the regular function from day5#2019-12-0802:59Average-userhttps://github.com/bblum/aoc/blob/master/day07/Day07-lazy.hs#L49#2019-12-0803:12potetmthat’s super cool#2019-12-0805:16fellshardToday's is downright trivial in Clojure. :)#2019-12-0805:20Average-useryup#2019-12-0805:21Average-userUnless you would want to read the output for part-2#2019-12-0805:23fellshardEven that is pretty straightforward, minus a bit of forcing eagerness + string munging.#2019-12-0805:23fellshardVisualization for this one is practically obvious, so I'm gonna take Quil for another spin#2019-12-0805:24fellshard(As a total aside, since I discovered the 'fancy symbols' mode in Spacemacs' Clojure layer, I've used partial
so much more)#2019-12-0812:21erwinrooijakkersWhat is it? I do see prettify-symbols-mode
that changes lambda to a symbol, but what do you mean? 🙂#2019-12-0813:21fellshardThat's the mode, yeah. It does a similar transformation for partial
into a... fancy P
, I guess?#2019-12-0805:24Average-userI meant, making the computer read it, and return the word as a string (not a grid)#2019-12-0805:24fellshardOhhh#2019-12-0805:24fellshardYeah, that'd be a headache 😅#2019-12-0806:03mishathis pissed me off really hard in day5 for day7:
(defn next-input [input]
;; reuse last input if all consumed
(or (next input) input))
#2019-12-0806:04mishaw/o it had nullpointers in few init combinations for part 2#2019-12-0806:14mpcjanssenToday was some welcome relief indeed#2019-12-0806:33mchampineYep. Easy in Clojure. I wound up with 3 lines of code for part 1, 5 for part 2. Not exactly pretty though. I used “ascii art” for the image, which was fastest and good enough.#2019-12-0806:34fellshardhttp://quil.info/sketches/show/66648043ce20f4ae77390dbc6c628f743e8540e33fcb5535f4305c473fc8d30c#2019-12-0806:35fellshard(The non-graphical solution is much cleaner, but boy is this more fun. 🙂 )#2019-12-0806:38mchampineThat’s pretty neat. If there was extra credit you’d earn a bunch. 🙂#2019-12-0806:44meikemertschearlier experience showed that weekend riddles are harder. Not this year. I’m glad 😆 It was a fun one today#2019-12-0809:42pesterhazyyes I was relieved too 🙂#2019-12-0812:37erwinrooijakkersMy Saturday was consumed by day 7 though 🙂#2019-12-0806:45lilactownI'm still working on day 7, but day 8 gave me something to work on while taking a break 🙂#2019-12-0806:57mpcjanssen@fellshard I assumw thats from de lowest layer to thw front?#2019-12-0807:16fellshardCorrect. 🙂#2019-12-0807:17fellshardThe 'actual solution' does it front to back, though.#2019-12-0808:04fingertoeI am pretty sure I re-wrote some magic core function that merges sets of vectors of that nature.. Got it done though. I have been struggling for motivation on the op-code puzzles.#2019-12-0808:04mpcjanssenThe protocol elf should have a stern talk#2019-12-0808:10gbouvierI'm happy with my day7 solution, but I'm wondering how I can make my code more idiomatic:
https://gitlab.com/gmbouvier/2019-aoc/blob/master/src/day7.clj
I'm only a hobby clojurist but thinking about sharpening my skills for possible Clojure work so any feedback/conversation is appreciated 🙂#2019-12-0808:41misha(defn arity [opcode]
(get {1 3, 2 3, 3 1, 4 1, 5 2, 6 2, 7 3, 8 3, 99 0} opcode))
->
(def arity {1 3, 2 3, 3 1, 4 1, 5 2, 6 2, 7 3, 8 3, 99 0})
#2019-12-0808:42misha{program :program pointer :pointer output :output} state
->
{:keys [program pointer output]} state
#2019-12-0808:43misha(cond
(= 1 opcode) ...
->
(case opcode
1 ...
or
(condp = opcode
1 ...
#2019-12-0808:45mishayou have a lot of fn indirection, which is hard to follow, like:
((-> {:program input :pointer 0}
(next-cont-state)
(:contfn)) i))
and
#((:m %))
and
((:i (last argslist)))
#2019-12-0808:47mishausing last
too much, working with vectors and using peek
instead would be more performant (maybe not that much in this case)#2019-12-0808:51misha(comp not zero?)
->
(complement zero?)
#2019-12-0808:52misha(fn [& args] :done)
->
(constantly :done)
#2019-12-0808:58mishaafter looking through all that, you begin to see things like: scanning op-code-seq multiple times:
(take-last 2)
and then
(reverse) (drop 2)
inside fn on the next line.
etc.#2019-12-0809:01misha(filter #(fn? (:contfn %)))
probably can be just
(filter :contfn)
since this key either mapped to fn or absent#2019-12-0809:03mishathis can be faster with
(last (map last (map :output amps)))
->
(last (:output (last amps)))
but it is way too many last
s#2019-12-0809:08misha(recur (concat (rest amps) [current-amp])
(last (:output current-amp)))))))))
this loop would be faster and without that many last
s if you put amps
in a queue, and then pop
and conj
it instead of first
and concat
:
(loop [amps (into PersistentQueue/EMPTY amps) ...
and in the end of the loop:
(-> amps vec peek ...)
instead of (... (last amps))
#2019-12-0810:00gbouvierThanks! Those are all useful points.
As far as function indirection, would it be better if I assign the relevant fn in a let
? Possibly more verbose but could add clarity...
Or is there an issue in general with using fns as values in hash-maps?#2019-12-0811:04mishain this particular case - it inhibits readablity for me, and feels like several unnecessary extra layers#2019-12-0808:49dmarjenburghI kept submitting the list of 0's and 1's as answer, haha 😅 https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L183-198#2019-12-1306:56fellshardIt's advent of code, you're not putting it into production; messy is OK 😛#2019-12-1307:05mishathis is how I feel when someone mentions "but this is universal solution", where universal means "more than 3 coordinate axes" rather "for anyone's input"#2019-12-1308:33roman01laThis is next level https://twitter.com/vcazacov/status/1205261123244695552?s=09#2019-12-1313:22dmarjenburghToday is lots of fun 😄#2019-12-1313:25dmarjenburghIt might crash at the end, but not before it prints the score. https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L317-363#2019-12-1317:42rjrayThis is weird. I'm still stuck on part 1, as my output is nothing but an infinite stream of 0's.#2019-12-1317:42rjrayGotta be something wrong in my intcode machine, but it's worked for every previous day.#2019-12-1318:18mpcjanssen@rjray i had the same. Are you sure you determine the score correctly?#2019-12-1318:18rjrayNot the score-- just running the program, the output stream is nothing but zeroes and an (apparently) infinite number of them.#2019-12-1318:19mpcjanssenAh misunderstood#2019-12-1318:19rjrayI'm trying to debug the intcode, but having just extracted it into a separate module it's proving harder to instrument for debugging than it was before.#2019-12-1318:24rjray(For example, a series of println
calls seem to be overwriting each other despite the program being single-threaded.)#2019-12-1318:27rjrayScratch that last comment-- was confusing Clojure's join
with Perl's. >_<#2019-12-1318:28pastafariFor the hull painting robot I reused the amplifier with a phase of either BLACK or WHITE 🙂#2019-12-1318:50rjrayUgh, I finally got debugging fixed and (naturally) immediately saw the source of my problem. So part 1 is done.#2019-12-1318:52rjrayNow I'm looking at part 2, and I'm kind of annoyed. Are we supposed to just inherently know the "rules" for how the ball moves, interacts with the paddle, etc.?#2019-12-1318:52rjrayI mean, I'm old-enough to have played Breakout in actual arcades, but still...#2019-12-1318:53rjrayOr scoring, for that matter...#2019-12-1318:54rjrayScratch that, I guess the scoring is just based on the output instruction.#2019-12-1322:00rjrayYay. The game loads, initializes the screen, and immediately hits a 99 and halts.#2019-12-1322:05fellshardDid you insert quarters?#2019-12-1322:05rjrayYes-- I've set memory loc 0 to 2, as instructed.#2019-12-1322:05fellshardDid you pass it an input it doesn't know how to read?#2019-12-1322:05fellshard(I had that issue early on when I was using keyboard bindings)#2019-12-1322:07rjrayIt never reads an input value, that I can tell. (I have a debug line for when input it read.)#2019-12-1322:07rjrayLet me double-check that...#2019-12-1322:08rjrayWell now. I seem to be (currently) storing input wonky. Thanks.#2019-12-1322:10fellshard🙂 Good luck!#2019-12-1322:51pastafariPart 1 of Day 13 was super quick. Part 2 made me 😱#2019-12-1322:56pastafariDay 13 Part 2 -> "Beat the game by breaking all the blocks" ! Wut! I'm going to sleep on it 💤#2019-12-1323:42rjrayFuck me. Got part 2 right on the first submission. Once I debugged and traced the holy hell out of my code, of course...#2019-12-1410:10misha@pastafari print it out, and you'll immediately know what's up#2019-12-1410:11mishawhen in doubt – print it out! opieop#2019-12-1410:13mishaday 14
"Elapsed time: 2.936473 msecs"
"Elapsed time: 84.136665 msecs"#2019-12-1421:42fellshardHmm. Got a solution, really want to figure out how to reliably solve it. Probably a binary / other more informed search method to seek the boundary. As it is, I refined it by hand until it was close enough to solve by just injecting fuel.#2019-12-1421:43fellshardGot to it late due to family time - not sure how I want to visualize this one, either. I saw some neat diagrams in Reddit.#2019-12-1422:37dmarjenburghMy submission for day 14. I was afraid part 2 would be very computationally slow, but it executes in ~ 30ms simple_smile https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L397-443#2019-12-1423:01fellshardThat bisect functionality is exactly what I need to steal replicate.#2019-12-1508:57mishaI did split stash and spendings too, but then just allowed negatives in spendings. made it noticeably more readable#2019-12-1509:03mishabut something else runs 3 times slower opieop#2019-12-1518:55fellshardNegative spending - you just make incremental passes to sweep through and request more stock for those entries?#2019-12-1519:06mishanot sure what you mean, but if you need to "buy" 7x but recipe is 10x for 10y, your cost map would be {:y +10 :x -3}
where :x -3
is a surplus from transaction you will might use in future transactions#2019-12-1519:07mishaat first I tried to track 2 maps: cost and surplus: {:y 10}, {:x 3}
, but merging those after each transaction was a chore and slow#2019-12-1519:10mishanot terribly readable, but line 48 makes it clear(er)
https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2019/day14.clj#L43-L54#2019-12-1519:10misha(< n amount) (assoc cost x (- n amount))
#2019-12-1507:02fellshardDay 15's definitely a sketcher. I'll try it tomorrow if I have the time - which I should, I think.#2019-12-1507:02fellshardNote to self: generic BFS grid implementation, because it aaaaalways shows up.#2019-12-1512:02dmarjenburghGot it with depth first search + backtracking. I already had an a*-algorithm in a util namespace from previous AoC’s that I could use ::blush: https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L445-490#2019-12-1512:08mishawow, why core-sync?#2019-12-1515:53dmarjenburghMy intcode machine implementation uses core.async ever since the amplifiers puzzle. Inputs and outputs are delivered through channels. It may be overkill, but I wasn't sure how to make a generic machine that can work with any number of inputs and any number of outputs in any order. Running it is a bit messy and deadlocks are annoying during development, but I haven't really had to tweak the implementation since the last three puzzles that used it#2019-12-1519:03mishalegacy code, ok opieop#2019-12-1513:46namenuhttps://github.com/namenu/advent-of-code/blob/master/src/graph.clj
thanks to last year's me, i could reuse my version of bfs.#2019-12-1518:47yuhanIt was so tempting to try and solve day 14 using an integer linear programming library - just convert the problem statement and plug into a solver!
But unfortunately the domain seemed to be too large to handle in reasonable time#2019-12-1521:38spfeifferIf you think you are smarter than Eric, you are not…#2019-12-1522:05fellshardTime to make pretty pictures. 🎨#2019-12-1605:47namenu...is today's pt2 something to do with DFT? facepalm#2019-12-1606:36rjrayPart 2 definitely involves some number-theory-level stuff that I'm not getting...#2019-12-1606:36rjrayPart 1 was almost trivial with Clojure's support for lazy sequences.#2019-12-1606:38mishaI think p2 is about this#2019-12-1606:38mishahttps://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/SmithChartLineLength.svg/700px-SmithChartLineLength.svg.png#2019-12-1607:09rjrayPart 2 done. Found an algorithm I could adapt. Turned out to be scarily fast, much faster than the computation of part 1 had been.#2019-12-1609:43mpcjanssenAny hints?#2019-12-1618:07rjrayUgh... I thought I still had the tabs open from my searching, but I don't. And it was pretty late when I finished last night and my memory is a little hazy. I'll see if I can find the original algorithm I saw.#2019-12-1619:29mishasee how far to the right your message offset is, and think about how expanded cycled [0 1 0 -1] pattern would look like that far right into the input list.#2019-12-1607:48fellshardDay 15 Viz - Exploration Phase http://quil.info/sketches/show/f4932cfba1834c15f9778ccbfa2f6e31cef89ebef27e45b16c3663cf6015bee8#2019-12-1609:33erwinrooijakkersI am a bit behind because of birthday parties, but cannot get day 12 to work. This is what I have now:
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day12.clj
Based on reddit/r/adventofcode information I can check when first state recurs (since the problem is such that the beginning state wil recur):
(defn idx-back-to-initial-state [states]
(first
(keep-indexed
(fn [i state] (when (= state (first states)) (inc i)))
(rest states))))
(defn period [moon-name]
(->> moons
(iterate gravity)
(map (comp first (partial filter (comp #{moon-name} :name))))
idx-back-to-initial-state))
(reduce lcm (map period (range 4)))
#2019-12-1609:33erwinrooijakkersThis works on example first input#2019-12-1609:33erwinrooijakkersBut with second input and my question input I get this exception:#2019-12-1609:33erwinrooijakkers1. Caused by java.lang.OutOfMemoryError
GC overhead limit exceeded
#2019-12-1609:34erwinrooijakkersI added the flag :jvm-opts ["-Xmx8g"]
but still after about 2 hours#2019-12-1609:34erwinrooijakkersAny suggestions?#2019-12-1611:29yuhanhint: The point of Day 12 Part 2 is for you to examine the problem more deeply and gain some insight which lets you solve it far more efficiently than brute force#2019-12-1621:11erwinrooijakkersThanks. Even more efficient than looking at the periods of the individual moons and taking the lcm?#2019-12-1621:17baritonehandsYeah, that was the trick suggested on Reddit. But in my case, I was using the wrong overload of Math/abs
so it was truncating the integers#2019-12-1621:34erwinrooijakkersAh 🙂#2019-12-1621:35erwinrooijakkersI also see a suggestion to only look at periods in x y or z#2019-12-1621:35erwinrooijakkersFor every planet indivually#2019-12-1621:35erwinrooijakkersI’ll try that#2019-12-1621:35erwinrooijakkersI use numeric-tower/abs#2019-12-1609:37erwinrooijakkersOh and (iterate gravity moons)
looks like this:
({:name 0,
:positions {:x -7, :y -8, :z 0},
:velocities {:x -3, :y 1, :z 3}}
{:name 1,
:positions {:x -14, :y -8, :z 1},
:velocities {:x -1, :y 3, :z 1}}
{:name 2,
:positions {:x -14, :y -8, :z 12},
:velocities {:x 3, :y -1, :z -3}}
{:name 3,
:positions {:x -15, :y 1, :z 1},
:velocities {:x 1, :y -3, :z -1}}
...)
#2019-12-1612:30yuhansolving Day 15 without any explicit backtracking was one of the most satisfying parts of doing AOC in Clojure so far :)#2019-12-1612:34yuhan(bfs robot) := (apply medley/interleave-all (for [dir [1 2 3 4]] (bfs (move robot dir)))
#2019-12-1612:44mishawell, at least I understand the p2 solution today, but did not quite came up with it myself harold#2019-12-1618:21dmarjenburghThe first thing coming to mind is to diagonalise the pattern matrix, but that ‘taking the last digit’ operation makes it nonlinear…#2019-12-1618:22dmarjenburghIf only it was mod 10, it would be easier#2019-12-1619:00mpcjanssenmy day 16 input was changes and I lost the first star (puzzled)#2019-12-1620:30fellshardAre you still logged in? Could be they found a bug in the input, or someone reported a bug in that input#2019-12-1620:46mpcjanssenyep still logged in. Anyway resubmitted part one. Now struggling with part 2#2019-12-1623:14Mario C.I feel like after Day10 all these problems require that you recognize some computer-science/math theory.#2019-12-1623:19fellshardSome math, some creative pattern recognition.#2019-12-1623:33dmarjenburghWow, finally got day 16. https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L492-509 A lot of pen-and-paper and little bit of coding. How does Eric come up with these things 🤓#2019-12-1704:35Mario C.I am working on Day 16 right now and created a function that essentially returns the repeating patterns.
(defn sn
[a n]
(let [f (/ (* n Math/PI) (inc a))
r (Math/sin f)]
(Math/round r)))
(doseq [n (range 0 10)]
(println (str (inc n) ": ") (sn 1 n))) => 0 1 0 -1 0 1 0 -1 ... etc
#2019-12-1704:35Mario C.But I can't get the zero's repeating.#2019-12-1704:36Mario C.I am grasping at straws here lol#2019-12-1706:34namenuactually i didn't go with trigonometry. but here's my sequence function.
`(defn pattern [phase]
(->> (mapcat #(repeat phase %) [0 1 0 -1])
(cycle)
(drop 1)))`#2019-12-1707:20mishayou can define all (∞) patterns once:
(defn pattern [idx]
(->> [0 1 0 -1]
(mapcat (partial repeat (inc idx)))
(cycle)
(rest)))
(def patterns (map pattern (range)))
#2019-12-1708:10mpcjanssenI created a function which returns three mth value of the pattern for digit m#2019-12-1708:10mpcjanssenDigit n#2019-12-1708:11mpcjanssen(defn pattern [n m]
;; (println (str n ":" m))
(let [base [0, 1, 0, -1]
idx (base (mod (quot m n) 4))]
idx))
#2019-12-1717:31Mario C.I originally did it with the cycle
mapcat
and repeat
(Such constructs is why I love clojure lol) but I figured to speed stuff up for part two I need to create some sine function that I can pass in parameters to change the freq and then a nth digit to pull from that. If that makes sense. I think @U0E2P47B7 what did is what I was trying to go for#2019-12-1718:01mishathe part 2 solution is not about speeding up though#2019-12-1718:23Mario C.😯 I think maybe I misunderstood part 2#2019-12-1718:26Mario C.When it says the real input signal is the signal repeated 10000 times does it mean that if my input was "abcd" and it was repeated 3 times then my real signal would be "abcdabcdabcd"?#2019-12-1718:27Mario C.Or does it mean run the FFT program at 100 phases. Then use that result in another 100 phase run. And repeat 1000 times?#2019-12-1718:31misha"abcd" -> "abcdabcdabcd", yes
but usually in late adventofcode puzzles part 2 uses repeated 10000 times
or similar exaggeration to hint that solution is not to brute force it. Especially if you are not solving using c, rust, etc.#2019-12-1718:32Mario C.Yea thats what I meant by speeding things up#2019-12-1718:33mishabut I did get few stars for previous years leaving laptop to heat up for 40+ minutes few times, yes opieop#2019-12-1718:33Mario C.A star is a star xD#2019-12-1708:26fellshardTook me way too long today. Got fixated on an incorrect set of core instructions, had to restart from the ground-up with different tactics to shake that faulty assumption.#2019-12-1708:34misha03:30 is not "too long" kappa#2019-12-1716:30dmarjenburghDay 17: https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L505-539#2019-12-1719:02rjrayJust finished part 2. Like you, I "encoded" things by hand ahead of time. I'm def gonna go back to this when I have time and try to derive an algorithm for that.#2019-12-1719:10rjrayFrom looking at your code, I clearly need to learn how to use channels. My mechanism for I/O is... clunky to say the least.#2019-12-1720:34mishaI implemented shortest path, but did not have time to implement path partition#2019-12-1803:46Mario C.For day 16 I thought I was noticing a pattern but it doesn't seem consistent.#2019-12-1803:47Mario C.The last number stays the same. The number before the last number is "driven" by whatever that last number was.#2019-12-1803:48Mario C.Then after I am not sure how its working. Sometimes the 3rd number from the last, is moving by what the second number was and other times its a sum of the previous rows, n - 1
numbers.#2019-12-1803:48Mario C.I can't even focus at work anymore lol#2019-12-1803:48Mario C.I have a secret repl open and everything#2019-12-1803:49Mario C.It always day 14ish where I flunk out of AoC#2019-12-1803:52Mario C.I dont like asking for help because I feel that that the star wasnt earned but i think its time for some reddit help#2019-12-1804:41fellshardYou have the right observation. I'd recommend looking at the pattern of the sums leading to it, as well, starting from that last number.#2019-12-1822:10dmarjenburghDay 18: https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L505-539#2019-12-1908:13fellshardI'm an idiot and made today's far harder for myself on accident#2019-12-1908:14fellshardThen I went to describe the logic in a comment and realized I could have done things a chunk faster and far earlier, and with far easier to follow logic. Ah well.#2019-12-1908:14fellshardNow the solution is practically instant. Heh.#2019-12-1908:15fellshardDropping this here just to show how convoluted it was.#2019-12-1908:16fellshardtl;dr, I was tracing the top and the bottom, thinking I needed to check the bounds from an earlier bad assumption about what was needed to solve the problem.#2019-12-1908:29fellshardAlso goofed: I ran it first time for a ship of size 1000, not 100; amazingly, it completed without taking too long.#2019-12-1910:02mishahow instant is "practically instant"?#2019-12-1916:48fellshard2.5s (measured by hand, w/o benchmark)#2019-12-1916:49fellshardCompared to... maybe 10-20s the other way?#2019-12-1917:32namenui tried to get tangents of both edges then find the corner with simple math. but no luck because errors were so significant...#2019-12-1921:38mishawent with trigonometry at first too, but was too imprecise.#2019-12-1921:45rjrayI am still hitting a brick wall on day 18. Nothing I do to my code is reducing the search-space enough.#2019-12-1921:46rjrayAt this point, my code is so long and convoluted I'm tempted to start over from square 0.#2019-12-1921:47mishasame here, lest 1 cache idea for tomorrow. Already have like 500 lines of code for different bfs/dfs/a*/dj combinations harold#2019-12-2003:44namenuum, dj means dijkstra?#2019-12-2011:47mishayes#2019-12-1921:48mishawhich solve samples with times like: 2,7,7,∞,30 msec kappa#2019-12-1921:50mishaand even if you do find 1 path early - still need to +- exhaust the rest of the space "just in case"#2019-12-2000:18fellshardKey simplifications you can make (in thread to hide spoilers)#2019-12-2000:21fellshard1. Seal up dead-ends (including doors that lead to dead ends)
2. Remove trivial key-door pairs, I think every puzzle set has a series of these in one path
3. Remove keys for which there are A. no doors and B. which are automatically retrieved en route to another key
I suspect you should reduce the mazy to a dependency graph - the obvious route for mine can be worked out by hand and a couple of assisting tools (distance between points); I just haven't had the time yet.
Of these, the first is the biggest aid to visualizing the shape of the data you've been given and understanding its quirks.#2019-12-2006:33dmarjenburghOne key optimization I used is that the state after getting keys a,b,c and b,a,c are the same. So if you have a fn shortest-path(curpos, collectedkeys) you can memoize it.#2019-12-2006:37dmarjenburghThe second one is that I created a map from key/entrancepoint to the possible other keys with their distance and doors in between. You can compute this map once and use it to efficiently get the next possible steps given your current position(s) and collected keys#2019-12-2008:02fellshardThere's a whole path in mine that has nothing but keys; you can fetch each of them with optimal efficiency with a thorough traversal, and that unlocks the next dependency in the graph as well given which ones are placed in there. I'm presuming based on what I saw in other inputs that each maze is very similar in logical layout.#2019-12-2005:20namenugetting heavier, and I don't feel like i'm enjoying anymore 😢#2019-12-2006:31fellshardThese last few days get pretty hefty#2019-12-2008:00fellshardWell, took long enough. Spent way too much time parsing by hand which probably could have been spent manually encoding the maze coordinates.
... And that's just part one. Part two will have to come later, but I'm intrigued.#2019-12-2013:49dmarjenburghThat parsing was annoying. My first version had a bug because it read labels in the order away from the maze point .
. But all labels read left-to-right or up-to-down.#2019-12-2008:30fellshardI lied, finished it. It was too interesting to resist. The changes aren't that significant between phases.#2019-12-2011:53mishathat was fast.
I wasted time debugging because of bug in outer-portal?
fn, which I wrote first, and assumed it fails last kappa#2019-12-2019:11fellshardMy first answer was off because I mis-counted where the bottom/right inner portals were placed; converting that to a calculated value instead of a hand-measured one was more robust for using the sample scenarios to test, anyway#2019-12-2008:32fellshardSketching this one could be interesting... depends how many layers deep it goes.#2019-12-2011:49mishatoday's is easier though. probably just because search space is#2019-12-2011:51mishaa tube, and you obviously have to use BFS, or you risk chasing infinity on very first path walk#2019-12-2013:46dmarjenburghGot behind a bit due to travel. Caught up today:
Day 19 https://gitlab.com/dmarjenburgh/adventofcode/blob/a159992a5123919594d95471ed7fae0fd2afdbc8/src/adventofcode/year_2019.clj#L587-617
Day 20 https://gitlab.com/dmarjenburgh/adventofcode/blob/a159992a5123919594d95471ed7fae0fd2afdbc8/src/adventofcode/year_2019.clj#L619-663
Again searching on a grid, finding neighbours above,below,left and right. I’ve written that code so many times I’m wondering if I should find a way to reuse it 😄#2019-12-2014:37dmarjenburghI used to feel Clojure is not the best language for things like AoC, but in many situations it is and in others I now feel it probably requires a different way of approaching the problem. With the right solution, I think the Clojure code is always fast enough. For day 19 with the tractor beam, I wrote an infinite lazy-sequence that gets more of the beam with each item (the beam points for the next y-coordinate). Then the stopping condition was a separate fn and I could use take-while
. It decouples generating the next iteration from calculating the stopping condition (square), the lazy-sequence could be used for both part 1 and 2. In in imperative loop, these things would have been coupled.#2019-12-2015:19mishayou can just find first bottom-left corner for which all 4 corners will be within beam. even no need for lazy seqs there#2019-12-2015:21mishawill be faster, because everything you drop-while
is still calculated#2019-12-2015:43dmarjenburghDoesn’t that amount to the same amount of calculations? You iterate until you can fit the square#2019-12-2016:23mishatbh your code is hard to glance over with all the inline fns with nested inline destructuring, so maybe you did exactly what I wrote.#2019-12-2016:26misha(defn beam? [cpu x y]
(when (-> cpu (assoc ::cpu/input [x y]) cpu/step ::cpu/output (= 1))
[x y]))
(defn score [x y]
(-> x (* 10000) (+ y)))
(defn f2 [input size]
(let [cpu (make input)
size (dec size)]
(loop [x1 0
y2 size]
(if-not (beam? cpu x1 y2) ;;left bottom corner
(recur (inc x1) y2)
(let [x2 (+ x1 size)
y1 (- y2 size)]
(if (and
(beam? cpu x2 y2) ;;right bottom corner
(beam? cpu x2 y1)) ;;right top corner
(score x1 y1)
(recur x1 (inc y2))))))))
#2019-12-2020:03dmarjenburghIt’s the same in going down increasing y per iteration and stopping when the square fits. I have some optimization based on the assumption that the min-x/max-x coords of the beam change by 1 unit at most (which held true). Therefore I run the intcode program twice per y coordinate.#2019-12-2014:45mishait depends on what you consider "fast enough". seconds? yes. But c++ and rust people start to cringe if stuff takes 10ms+ to run#2019-12-2015:03dmarjenburghI’d rather save on development time d#2019-12-2015:04mishasame opieop#2019-12-2015:05mishaaltho, some of the python/c aoc solutions are just 2-3variables and 2-4 nested loops, for 7-10 lines total, less characters than my usual parse-input fn#2019-12-2015:07mishaI doubt anyone ever got global top100 gold star with clojure for any mid month-ish puzzle#2019-12-2111:51yuhanI got global top-100 stars for some of the intcode problems in pure clojure 🙂#2019-12-2111:53yuhanI feel like part of the reason was the instant RDD feedback and being able to directly get a feel of the shape of the data and manipulate it, definitely makes up for some of the verbosity#2019-12-2017:10ghadidunno @misha, your Day 10 solution got a gold star from me#2019-12-2017:10ghadiway more elegant than any imperative mess#2019-12-2017:47mishaawww opieop#2019-12-2017:49mishabut elegance is just one of dimensions, and is rarely a top1 one would consider while solving puzzles under time limit#2019-12-2017:49ghadiyeah true#2019-12-2017:49ghadineed a speed hammock#2019-12-2022:55rjrayI find my Clojure solutions at least feel more elegant. Granted, I'm not a code-golfer so I'm writing meaningful variable/function names (most of the time). And I'm not even trying to compete on the main leaderboard.#2019-12-2023:13rjrayMeanwhile, having finally gotten day 18 done (after stopping to do 19 when it unlocked) I am now looking at day 20. Parsing this input will be tricky. Hell, it would be tricky even in a language like Perl that lives for stuff like this...#2019-12-2101:02fellshardI'd like to think my parsing for it ended up fairly clean. The different arities of map are major helps in this.#2019-12-2105:40fellshardthe heck#2019-12-2105:40fellshardMy second program ended up being absurdly easy - I went with a very dumb initial heuristic thinking it would show me the next failed test, but nope, that was it#2019-12-2109:44mishalow level mutability eew#2019-12-2112:10mishatrying to write fn to translate sexpressions line (and a (not b))
into AND A J...
and those 2 mutable registers are a world of pain#2019-12-2112:11mishaeither api forces you to frame sexp from particular point of view, or infinite pain#2019-12-2116:09Ben GrabowYou can translate boolean expressions...#2019-12-2116:10Ben Grabowusing de morgan's laws to change (and (not x) (not y))
to (not (or x y))
to save register space#2019-12-2116:12Ben GrabowAny expression that has more than one non-trivial operand is going to take up both of your registers#2019-12-2116:16Ben GrabowSo simplify the operands of any binary op until at least one of them is a trivial register. Unary ops can be computed with a single mutable register.#2019-12-2117:03mishaall of this is true. I wanted user not to worry about shape of the tree. But reshaping a tree with a bunch of substitution rules is not an easy task as well.
but yeah, can be done for sure.#2019-12-2120:57Alper CugunI read half the book and threw this together: https://github.com/alper/aoc2019/blob/master/3.clj
It’s a bit slow so suggestions of how to speed it up are very much welcome.#2019-12-2122:45Alper CugunIt turns out that all time is spent in generate_points_from_steps
.If anybody has a solution for this I can take a look at that would also be appreciated.#2019-12-2207:24misha(defn generate-points-from-steps
"For a vector of steps of the form [\"R\" 10] etc.,
generates a vector of points starting from origin."
[steps]
(reduce
(fn [path step]
(into []
(concat path (loc-from-loc (last path) step))))
[origin]
steps))
can be just
(reduce
(fn [path step]
(into path
(loc-from-loc (peek path) step)))
[origin]
steps)
with 2 key improvements:
1)`peek` is constant time lookup of last element in vector (`last` is linear time)
2) into
directly into path vector bypasses concat
and scans only new lock-from-loc
segment. Where concat
does not scan for concatting, but then scans entire seq: both old path
and new lock-from-lock
to put them into empty []
.#2019-12-2207:31mishaso in your code - each next iteration you scan old path
segment twice: for last and after concat, instead of nonce#2019-12-2207:39mishaI think this:
(first (sort
(fn [p1 p2] (< (dist-to-origin p1) (dist-to-origin p2))
points)))
can be this:
(->> points
(sort-by dist-to-origin <)
(first))
#2019-12-2207:49misha(defn loc-from-loc
"Loc is a hash with :x and :y, step is a vector with a direction string and an integer. Returns a list of locations that have been stepped over."
[loc step]
(case (first step)
"R" (map (fn [step] (update loc :x + step)) (range 1 (+ (second step) 1)))
"L" (map (fn [step] (update loc :x - step)) (range 1 (+ (second step) 1)))
"U" (map (fn [step] (update loc :y + step)) (range 1 (+ (second step) 1)))
"D" (map (fn [step] (update loc :y - step)) (range 1 (+ (second step) 1)))))
can be shorter with destructuring:
(defn loc-from-loc
"Loc is a hash with :x and :y, step is a vector with a direction string and an integer.
Returns a list of locations that have been stepped over."
[loc [dir len]]
(let [offsets (range 1 (+ 1 len))]
(case dir
"R" (map (fn [step] (update loc :x + step)) offsets)
"L" (map (fn [step] (update loc :x - step)) offsets)
"U" (map (fn [step] (update loc :y + step)) offsets)
"D" (map (fn [step] (update loc :y - step)) offsets))))
#2019-12-2220:05Alper CugunJust removing last
and concat
resulted in a 20x speed gain:#2019-12-2220:06Alper CugunElapsed time: 7390.580613 msecs
Elapsed time: 372.936439 msecs#2019-12-2220:06Alper CugunThanks for that and the other hints.#2019-12-2212:47dmarjenburghAnyone have any tips for day 22 part 2? I think I need to revisit my algebra courses. Put possible spoilers in thread.#2019-12-2212:49dmarjenburghIn noticed both the number of cards in the deck and the number of times you repeat the shuffle process are prime numbers.#2019-12-2214:06mishahttps://en.wikipedia.org/wiki/Modular_arithmetic#2019-12-2221:15Alper CugunI hope nobody minds me posting AoC as far back as this but after the rough start on part 1, assembling the part 2 solution from its components was a breeze.#2019-12-2221:44dmarjenburghPhew, finally solved today. Spent so much time going in wrong directions… I put the explanation in a comment https://gitlab.com/dmarjenburgh/adventofcode/blob/c7b250a5e60733fef2c6c01c5099125ef29d9c48/src/adventofcode/year_2019.clj#L732-776#2019-12-2401:40namenuthanks. i wasn't aware of modular inverse and that's why my division made the different answer..#2019-12-2411:43dmarjenburghToday was a breeze. Did not expect 😌#2019-12-2418:17rjrayStruggled a bit with part 2 of today, as I wasn’t handling edge-cases of the recursion quite right.#2019-12-2418:18rjrayFinally caught up completely, just waiting for the last day to unlock.#2019-12-2422:27Mario C.So tempted to use the solution "by-hand" for day 17 part 2 xD#2019-12-2503:52rjrayI basically “hand-compressed” the path after hand-encoding it.#2019-12-2422:41erwinrooijakkersPlaying catch up. Here’s my day 13: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day13.clj
Looking back visualization was not necessary, just keep the bat underneath the ball. :)#2019-12-2503:52rjrayI basically “hand-compressed” the path after hand-encoding it.#2019-12-2507:04rjrayDay 25 done. All done.#2019-12-2507:05rjrayNot sharing the general enthusiasm for the first half of day 25.#2019-12-2507:05rjrayPeople on reddit seemed to relish it, I found it tedious.#2019-12-2511:48dmarjenburghDone as well. I didn’t mind too much, but my wife is glad AoC is over 😅#2019-12-2516:58Alper CugunDay 4 is made a lot easier if you’re aware of this particular idiom: https://github.com/Sose/advent-of-code-2019/blob/master/src/aoc/day04.clj#L15 (browsing solutions pinned to the reddit)#2020-12-3023:15Alper CugunCompleted day 6-2 with relative ease and then 8-1 proved to be really easy in clojure. Looks like I’m getting comfortable with the language.#2020-12-3023:16Alper Cugunhttps://github.com/alper/aoc2019/blob/master/src/aoc/day6.clj#L131#2020-12-3023:16Alper Cugunhttps://github.com/alper/aoc2019/blob/master/src/aoc/day8.clj#L22#2020-12-3102:55erwinrooijakkersNice 🙂 Happy to see I’m not the only one still doing puzzles. I liked this tip someone gave me earlier:
(let [ys (descendants ::YOU)
ss (descendants ::SAN)]
(count
(set/difference
(set/union ys ss)
(set/intersection ys ss))))
#2020-12-3102:56erwinrooijakkersI think your part 2 can also be shortened using set operations only#2020-12-3107:02Alper CugunYeah, I’m plugging away to get comfortable with the language. That’s going pretty well by now.#2020-12-3107:03Alper CugunI’m skipping the intcode ones because I originally started this in Haskell and I’m not sure whether I want to port my intcode computer to Clojure.#2020-12-3102:59erwinrooijakkersCan unfortunately not see the history for day 15 here nor on clojureverse, but here’s mine:
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day15.clj#2020-01-0322:47borkdudeYou can see the history of this channel in zulip#2020-01-0322:47borkdudeGo the channel slack archive and topic adventofcode#2020-12-3115:19Alper CugunLooks like I’m not going to get around porting my Haskell intcode computer to Clojure since every other assignment seems to be using that.#2020-12-3115:22Alper CugunFor day 10 I saw one solution with some floating point arithmetic, but wouldn’t the cleaner way be to sieve out?#2020-12-3115:23Alper CugunIf from a position, there is an asteroid at +2,+1, then all multiples of that position would be occluded so: +4,+2, +6,+3 etc.#2020-12-3115:25Alper Cugun(Doesn’t work for right angles unfortunately. An asteroid at +2,+0 also occludes one at +3,+0.)#2020-01-0101:13namenuyes, so you need to store both angle AND distance. (from nearest to fartest)#2020-01-0108:55mishayou can use clojure's ratios for angles, or proper tan/atan from java's Math#2020-01-0109:44Alper CugunA native ratio type is nice.
But the approach I saw was to calculate the angle to all others asteroids and then count only the uniques since if any number of asteroids are on the same angle, only one of them will be visible. #2020-01-0109:45Alper CugunThe the only thing left is to calculate an angle on 2PI with ratios (or to munge floats after all).#2020-01-0109:46Alper CugunI’ll have to pick up my trig to see whether this is possible. #2020-01-0111:17namenuFor error-proof method, you can sort every asteroids clockwise (or counter clockwise) using cross product. It only requires integer arithmetics.#2020-01-0321:13Alper CugunWhat’s the cross product quality that I would be exploiting here? I’ve never had a good feeling for it.#2020-01-0417:58mishaints sum and multiplication, no fractions and floating point rounding errors#2020-01-0108:55misha🎄#2020-11-2806:09fingertoeWho all is playing this year?#2020-11-2811:29nbardiukI usually use AOC to practice something new. I've used it to practice Haskell, Clojure, Rust, Vim, TDD. This year I don't have new things to practice. The only things that come to my mind is to try REPL driven development instead of TDD, maybe macros, transducers, ClojureScript, core.async.#2020-11-2811:29nbardiukDo you have a personal challenge this year?#2020-11-2813:05raicotopFor me it's Clojure in general + REPL driven development#2020-11-3015:01erwinrooijakkersI will participate and goal is to enjoy the challenges and learn about computer science concepts#2020-11-3015:02erwinrooijakkersAnd perhaps use some Clojure capabilities I’m not using as much yet#2020-11-3022:46rjrayI am struggling with whether to participate this year... I'm in the middle of an intense personal side-project, and starting a MSCS program in January. I'll almost certainly have to skip AoC the next two years, so passing on it this year is hard to consider.#2020-12-0109:00mishaaoc starts me going in the morning. the trick is to stop when puzzles start to take more time and attention than you can afford to spare.#2020-12-0105:01kenjthe AOC server is struggling tonight#2020-12-0105:35rjrayYeah, I was getting alternating 502/503 errors within the first minute or so.#2020-12-0105:58rjrayPer reddit thread (https://www.reddit.com/r/adventofcode/comments/k4ejjz/2020_day_1_unlock_crash_postmortem/), the downtime was due to overloading their configured AWS instances. They'll be canceling leaderboard points for the first day.#2020-12-0107:44fingertoeGot day 1 done.. My question 2 answer came up too easily.. I might have to mix up my data to make it work on more universal data..#2020-12-0108:59erwinrooijakkersDay 1 with math.combinatorics
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day1.clj#2020-12-0215:33rmprescottCurious: why use set membership rather than `(= 2020 ...)#2020-12-0310:04erwinrooijakkersthis case it would be (partial = 2020)
I think#2020-12-0310:04erwinrooijakkersIt’s this recommendation from the style guide https://github.com/bbatsov/clojure-style-guide#set-as-predicate#2020-12-0310:04erwinrooijakkers;; good
(remove #{1} [0 1 2 3 4 5])
;; bad
(remove #(= % 1) [0 1 2 3 4 5])
;; good
(count (filter #{\a \e \i \o \u} "mary had a little lamb"))
;; bad
(count (filter #(or (= % \a)
(= % \e)
(= % \i)
(= % \o)
(= % \u))
"mary had a little lamb"))
#2020-12-0109:28nbardiukoh, cool TIL about math.combinatorics
I had to roll my own inefficient combinations function https://github.com/nbardiuk/adventofcode/blob/0955796f728c9d73376ba480003994db902c6b21/2020/src/day01.clj#2020-12-0110:08misha(defn find-first [p xs]
(->> xs (filter p) first))
there is more efficient some
instead
(some pred xs)
#2020-12-0110:22nbardiukthat is interesting
(defn find-first [p xs]
(some #(when (p %) %) xs))
some returns first truthy value, so I had to wrap it into when, and it is slightly slower now#2020-12-0110:34spfeifferYes, the combinatorics namespace has been very valuable for many AoC Puzzles in the past.#2020-12-0110:36mishaah, yes, should have mentioned: you'd have to change predicate too.#2020-12-0111:09mishain the worst case filter
walks extra 31 element after first
is ready to go:
(->> (range 100)
(filter #(do (println %) (even? %)))
(first))
0
1
,,,
30
31
=> 0
#2020-12-0111:13nbardiukoh, that is valid point, it is dangerous in case of side effects inside filter#2020-12-0111:16nbardiukI am still curious why in my case some
was not visibly faster, maybe it is related with chunking?
(chunked-seq? (range 100)) ; true
(chunked-seq? (combinations 2 [1 2 3])) ; false
#2020-12-0111:39mishaI think so, yes:
(defn- -unchunk [sek]
(when sek
(lazy-seq
(cons (first sek)
(-unchunk (next sek))))))
(defn unchunked-seq
"converts coll into seq which will be realized 1 element at a time,
and not in chunks, like e.g. 32 for (range 40)."
[coll]
(let [xs (seq coll)]
(if (chunked-seq? xs)
(-unchunk xs)
xs)))
(->> (range 100)
(unchunked-seq)
(filter #(do (println %) (even? %)))
(first))
0
=> 0
#2020-12-0109:34zackteobut I guess @nbardiuk that might be a good exercise haha. I did
(require '[clojure.math.combinatorics :as combo])
(->> (combo/combinations data 2)
(filter #(= (apply + %) 2020))
(apply reduce *))
#2020-12-0109:35zackteoMaybe I should create a repo for advent of code hmmmm#2020-12-0109:35mishano deps, little waste, part 2 "Elapsed time: 2.362157 msecs"#2020-12-0109:35misha(time
(let [xs (->> input (str/split-lines) (map read-string) (sort <))
vecs (for [x xs
y xs
:while (< (+ x y) 2020)
z xs
:let [s (+ y x z)]
:while (<= s 2020)
:when (= s 2020)]
[x y z])]
(some->> vecs first (apply *))))
"Elapsed time: 2.362157 msecs"
#2020-12-0109:51zackteoso the first while is a pre-filtering. And xs is the sequential list of numbers?#2020-12-0109:56misha(for [x [1 2 3]
y [1 2 3]]
{:x x :y y})
=>
({:x 1, :y 1}
{:x 1, :y 2}
{:x 1, :y 3}
{:x 2, :y 1}
{:x 2, :y 2}
,,,
(for [x [1 2 3]
:when (< x 2)
y [1 2 3]]
{:x x :y y})
=>
({:x 1, :y 1}
{:x 1, :y 2}
{:x 1, :y 3})
#2020-12-0109:58mishaxs
is parsed puzzle input, seq of ints, yes#2020-12-0111:25erwinrooijakkersWhy the while
?#2020-12-0111:33mishanotice, input ints are sorted ascending. while
makes sure for
does not iterate over combinations which are already known to be useless.
even though xs are sorted, combinations of [x y z] - are not, and as soon as y
or z
becomes large enough to disqualify [x y z] - while
makes for
abandon iteration over the rest of y
or z
, and takes next x
(or y
respectively) instead#2020-12-0111:36mishaif all combinations would be sorted by sum
, you'd be able to just (->> combos (drop-while <2020) first)
. but combinations are not sorted, so need to terminate "branch" early another way: while
.#2020-12-0114:27erwinrooijakkersah I see smart 🙂#2020-12-0119:07erwinrooijakkersI updated to similar to you 🙂
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day1.clj#2020-12-0119:07erwinrooijakkers25ms then#2020-12-0119:11erwinrooijakkersDid not look for edge cases (like adding same number) and was not necessary for my input#2020-12-0119:12erwinrooijakkersAh your while is one step earlier#2020-12-0119:13erwinrooijakkersThen 3ms#2020-12-0109:37misha@zackteo your example gives me "Elapsed time: 1095.922251 msecs" for part2#2020-12-0109:45zackteo@misha right >< yeah was thinking it isn't optimal but at least is a start hahaha 🙂 I usually don't get these challenges done#2020-12-0110:38oxalorg (Mitesh)I used a different apporach to solve this problem here: https://nextjournal.com/oxalorg/advent-of-clojure-01
The runtime complexity here is O(n) for part1 and O(n^2) for part 2#2020-12-0110:46Björn EbbinghausI made use of some
in combination with set lookup. I find it quite simple.
Task 1: ~ 0.25 msecs
Task 2: ~30 msecs
When executed with babashka
https://github.com/MrEbbinghaus/advent-of-code/blob/master/2020/day01.clj#2020-12-0111:23Björn EbbinghausWhen I use a sorted-set
as input I go down to 0.08ms and 0.09ms.
But I think my input list favors this heavily as just 7 numbers are smaller than 2020 / 2
..#2020-12-0112:54nbardiukright! I also have noticed that sorting input improves almost any solution I've tried#2020-12-0111:28juniusfree👋Newbie coder. Trying my first AoC. Any helpful feedback is welcome! https://twitter.com/juniusfree/status/1333727767658053632 https://github.com/juniusfree/advent-code-2020/tree/master/day01#2020-12-0111:36Björn EbbinghausHave look at recur
for tail-recursion.
https://clojuredocs.org/clojure.core/recur
https://clojure.org/about/functional_programming#_recursive_looping
Check this out
(defn check-second
[fst rst]
(cond
(nil? (first rst)) nil
(= 2020 (+ fst (first rst))) (* fst (first rst))
:else (recur fst (rest rst))))
And: Are abbreviated parameters worth it?
I have no idea what you mean with loe
#2020-12-0111:59juniusfree@U4VT24ZM3 Thanks for checking. loe
just means list of expenses. I'll definitely look into recur
#2020-12-0112:01Björn EbbinghausAnd it looks like you are still in the “thinking in loops”-phase (every functional programming beginner starts there when they come from python, java, … whatever
In functional programming you would not “iterate” over things..
You apply functions to collections.
Like so:
(defn check-second [fst rst]
(when-let [snd (some (fn [possible-snd] (when (= 2020 (+ fst possible-snd)) possible-snd)) rst)]
(* fst snd)))
(`(some pred coll)` returns the first “truthy” value when pred is applied to every element in item.)#2020-12-0112:09Björn EbbinghausOr maybe easier to understand:
(when-let [snd (first (filter #(= 2020 (+ fst %)) rst))]
(* fst snd))
#2020-12-0112:17juniusfree@U4VT24ZM3 You're right. I haven't develop the intuition yet on the application of functions on collections. Any tips or resources for that?
And thanks for providing the revised code. I'll definitely study this.#2020-12-0112:22erwinrooijakkers(cond (seq x) (blabla)
:else 0)
;; is the same as:
(if (seq x)
(blabla)
0)
#2020-12-0112:22erwinrooijakkersand you can use some sequential destructuring (https://clojure.org/guides/destructuring#_sequential_destructuring) instead of doing first and rest amybe#2020-12-0112:22erwinrooijakkers(defn report-repair
[loe]
(cond
(empty? loe) 0
:else (or
(check-second (first loe) (rest loe))
(report-repair (rest loe)))))
#2020-12-0112:22erwinrooijakkers=#2020-12-0112:23erwinrooijakkers(defn report-repair
[[x & xs :as expenses]]
(cond
(empty? expenses) 0
:else (or
(check-second x xs)
(report-repair xs))))
#2020-12-0112:23erwinrooijakkers=#2020-12-0112:24erwinrooijakkers(defn report-repair [[x & xs :as expenses]]
(if (seq expenses)
(or (check-second x xs)
(report-repair xs))
0))
#2020-12-0112:25Björn Ebbinghaus@U013R0P5ZJT
Maybe have a look at Clojure for the Brave and True https://www.braveclojure.com/clojure-for-the-brave-and-true/
But what I told you makes the difference between “Learning the clojure syntax” and “Learning functional programming”#2020-12-0118:41erwinrooijakkers@U4VT24ZM3 in my eyes it’s quite a functional solution already because of the use of recursion. But yes there are possibly functions that encapsulate these recursive patterns in names (like map
, filter
, reduce
and for
-comprehension). I 100% agree with not using abbreviations.#2020-12-0119:22Björn EbbinghausI think this use of recursion is symptom of this “loop” thinking.
And not an “apply function to collection” mindset.
Recursion doesn’t make it functional.
You can think of it that way:
Does the decision whether a value in the input has a partner to sum to 2020 or not depend on prior values in the input?
Does the order matter?
No.
So why a recursion? In a recursion you do one thing after another.#2020-12-0121:36juniusfree@U4VT24ZM3 @U2PGHFU5U Thanks for your feedback. I'll take some time to study these things.
I have a question though. Please correct me if I'm wrong. Doesn't map
,`filter`, etc. uses recursion under the hood?#2020-12-0121:44Björn EbbinghausMaybe, maybe not. 🙂 But this shouldn’t be your concern, it is a layer of abstraction.#2020-12-0122:27juniusfree@U4VT24ZM3 OK. 😅#2020-12-0212:40erwinrooijakkers@U4VT24ZM3 my definition of functional programming is “pure functions (that always return same output with same input) and no use of mutable variables”. By that definition the solution was already functional. Perhaps you mean something different, like using higher order functions with well known names (see below)?
@U013R0P5ZJT indeed map
and filter
are implemented using recursion. I think it’s instructive to look at and they have similar patterns to your solution, the gist of it (clojure.core one also uses lazy-seq
to delay evaluation of recursive call making them lazy, and chunked sequences to increase performance):
(defn map* [f coll]
(when (seq coll)
(cons (f (first coll)) (map* f (rest coll)))))
(map* inc [1 2 3])
;; => (2 3 4)
reduce
can also be implemented recursively and you can implemented map
and filter
also in terms of reduce
.
Some examples are given in https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-15.html#%_sec_2.2 (`reduce` is called accumulate
there and is used to implement other higher order functions).
It states in SICP:
> In effect, map
helps establish an abstraction barrier that isolates the implementation of procedures that transform lists from the details of how the elements of the list are extracted and combined
The recursive definitions you defined yourself probably already exist, or can be written in, terms of higher order functions with well known names, thus making us think differently and perhaps arguably more functionally.#2020-12-0220:13juniusfree@U2PGHFU5U Correct. There are a lot of built-in functions in Clojure that I still have to explore!#2020-12-0115:04fingertoehttps://github.com/jreighley/aoc2020/blob/master/src/prb1.clj#2020-12-0115:13fingertoe(time (reduce * (find-pair data 2020)))
“Elapsed time: 0.646178 msecs”
=> 786811
(time (reduce * (find-triple data 2020)))
“Elapsed time: 1.553634 msecs”#2020-12-0115:17fingertoeThat doesn’t count the slurp or sort though.. using sorted data made my first answer right.#2020-12-0119:13mchampine(def inp (map #(Integer/parseInt %) (str/split-lines (slurp "day1.data"))))
(first (for [a inp b inp :when (= 2020 (+ a b))] (* a b))) ;; part 1
(first (for [a inp b inp c inp :when (= 2020 (+ a b c))] (* a b c))) ;; part 2
#2020-12-0123:59skykanin#2020-12-0200:05kenjDid anyone else use reduce
/`reduced`? It feels dirty but I can’t figure out how to get the same efficiency without it. My other solution was to use some
but created the whole set of inputs before hand.
(defn find-ints-summing-to-target [coll]
(reduce (fn [seen-set n]
(let [diff (- target-sum n)]
(if (seen-set diff)
(reduced #{n diff})
(conj seen-set n))))
#{}
coll))
#2020-12-0202:00potetmreduced
is totally fine and normal. You use it in exactly this sort of situation: You want to short-circuit evaluation because you’re done.#2020-12-0216:51Mario C.Hey are you going to be doing a video series this year for AoC? @U07S8JGF7#2020-12-0218:19potetmugh I made the mistake of trying it in rust this year#2020-12-0218:19potetmno one wants to see that 😄#2020-12-0219:55Mario C.I liked how you broke down the problem in the videos regardless of language used. If you do decide to make them, I would take a look#2020-12-0200:05kenjit also returns the whole set if a pair isn’t found which is a terrible result in the negative find case#2020-12-0200:09kenjah looks like skykanin did something similar above in a cleaner fashion#2020-12-0200:18drowsyToday I just threw core.logic with finite domain at it, which worked out quite nice: https://github.com/IamDrowsy/aoc-2020/blob/master/clojure/src/advent_of_code/d01.clj#2020-12-0209:38erwinrooijakkersNice 🙂#2020-12-0206:13mchampineDay 2, not bad, most of the work was processing the input into usable form. E.g.
{:lb 1, :ub 3, :ch \a, :pw "abcde"}
..which took as many loc as my solutions. Here are my pw test functions. Filter input with them and count the results:
(defn pwgood? [{:keys [lb ub ch pw]}]
(<= lb (get (frequencies pw) ch 0) ub))
(defn pwgood2? [{:keys [lb ub ch pw]}]
(= 1 (count (filter #(= ch %)
[(nth pw (dec lb)) (nth pw (dec ub))]))))
#2020-12-0209:47pezThat is beautiful!#2020-12-0209:53pezMine:
(defn checks? [{:keys [p1 p2 ch pwd]}]
(as-> pwd $
(filter #(= ch %) $)
(count $)
(<= p1 $ p2)))
(defn checks2? [{:keys [p1 p2 ch pwd]}]
(let [p1 (dec p1)
p2 (dec p2)]
(as-> pwd $
(seq $)
(vec $)
(not= (= ($ p1) ch) (= ($ p2) ch)))))
(I didn’t bother to update the parser between the two 😃 )#2020-12-0209:54pezNeither did you, I now realize. Haha.#2020-12-0207:38nbardiukI am curious what did you you use to parse data for Day 2. Have you used regexp or some nice parser combinator library?#2020-12-0215:42mchampineA small regex. I simply split each line with #(str/split % #“[- :]“) and then converted the strings to numbers and chars as appropriate.#2020-12-0306:01pezI also used a regex, but with groups. I should have splitted instead, had I thought about it. 😀#2020-12-0208:00plexusMy solution for day 2 https://youtu.be/rghUu4z5MdM#2020-12-0208:28nbardiukalways forget about slurp and barf, I like how some edits are more fluent with them#2020-12-0305:49Vincent CantinI mapped my forward/backward slurp/barf in a positional way on my keyboard, to forget their names and remember what they do.#2020-12-0306:21pezWatched it now. Super nice. You are so fluent in both how you talk and how you code, making it a pleasant experience. #2020-12-0306:53plexusThank you 😊#2020-12-0209:38erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day2.clj#2020-12-0214:04StuartMy day 2 part 1 was pretty similar to yours
(defn parse-line [s]
(let [splits (rest (re-find #"(\d+)-(\d+)\s(.):\s(.+)" s))]
{:range [(Integer/parseInt (first splits)) (Integer/parseInt (second splits))]
:char (first (nth splits 2))
:password (last splits)}))
;; check valid for part 1
(defn valid-password? [{:keys [range char password]}]
(let [[min max] range
freq (frequencies password)
char-count (freq char 0)]
(<= min char-count max)))
;; check valid for part 1
(defn valid-password? [{:keys [range char password]}]
(let [p1 (nth password (dec (first range)) \_)
p2 (nth password (dec (second range)) \_)]
(or (and (= char p1) (not= char p2))
(and (not= char p1) (= char p2)))))
(->> (slurp "input.txt")
(str/split-lines)
(map parse-line)
(filter valid-password?)
(count))
#2020-12-0214:06StuartI like your solution for part2!#2020-12-0214:38erwinrooijakkers🙂 i did same as yours initially but then realized clojure had no xor
#2020-12-0209:45pezHas someone figured out a way to slurp the input data directly from the site? I’m lazy, so if someone has this solved in a nice module, I’d love to have it. 😃 I’m also not lazy, so if this is not done by someone, I might try to do it, if someone here does not tell me it is probably very hard. And I’m the sharing type. Haha.#2020-12-0209:46erwinrooijakkersThere is some Python program somewhere#2020-12-0209:47erwinrooijakkershttps://github.com/wimglenn/advent-of-code-data#2020-12-0209:47erwinrooijakkersaocd > input.txt # saves today's data
aocd 13 2018 > day13.txt # save some other day's data
#2020-12-0209:55pezIf I end up rolling this, I’ll have use for that to see what is involved.#2020-12-0209:57zackteoWas attempting to do so yesterday, then I realised authentication is required#2020-12-0210:00plexuslazy way I think would be doing it first from the browser, "copy as cURL" so that it has your cookie headers in there, then you can adjust that curl line to download the other ones as long as your session remains valid#2020-12-0210:00erwinrooijakkersIn the Python aocd
tool you can add the value of the session
cookie in the AOC_SESSION
env var or ~/.config/aocd/token
file#2020-12-0210:08namenuWow as always it’s fascinating to watch Clojurians solution in this channel.
This year I’m using ReasonML(family of OCaml) since my company has chosen it.
https://github.com/namenu/advent-of-reason/blob/master/src/Year2020/Year2020_Day01.res
Yes, it’s typed, I miss Clojure so badly.#2020-12-0210:14erwinrooijakkersI remember a talk from Clojure Vienna 2016 on ReasonML’s Unikernels and also transforming Clojure to ReasonML: https://youtu.be/tB705w4w6H0#2020-12-0210:16namenuWow thats... cursed #2020-12-0210:16erwinrooijakkershaha#2020-12-0210:18erwinrooijakkersWas pretty interesting stuff. Booting up a unikernel faster than the time it takes to do a TCP handshake#2020-12-0210:18erwinrooijakkersNot sure what the status is of it now#2020-12-0715:26erwinrooijakkers@U7JHWBCS0 lol your ReasonML is gone? In favour of https://github.com/namenu/advent-of-code/tree/master/src? 😄#2020-12-0715:27erwinrooijakkersaah I see it’s still Reason 🙂#2020-12-0715:27erwinrooijakkersnice#2020-12-0715:27erwinrooijakkerslooks pretty clean#2020-12-0801:00namenuoh yes I merged the ReasonML repo with Clojure's to contrast them#2020-12-0801:00namenuI found ML language interesting in a way that
more lengthy code makes a program safer, because compiler is very very smart.
In my experience, this wasn't true in Clojure.
I always prefer brevity in my code, because more code means more bugs!#2020-12-0801:01namenuI use ReasonML and Clojure both for living, and they are both great in very different ways#2020-12-0210:09erwinrooijakkersMaybe a program can login via the GitHub SSH key so that you don’t need the session#2020-12-0210:09erwinrooijakkersIf you use GitHub to login#2020-12-0210:09erwinrooijakkersNot sure if that’s possible#2020-12-0211:49plexus@pez https://github.com/lambdaisland/aoc_2020/blob/main/bin/fetch_input#2020-12-0211:49plexusjust need to find the session id with devtools and put a export AOC_SESSION=...
in your shell profile#2020-12-0211:58drowsyAnd in the same way, it's also pretty easy to get the input via clojure (I just store the session in a file)
https://github.com/IamDrowsy/aoc-2020/blob/581097350d2dc7865304ffc9eddaf6a479406ca1/clojure/src/advent_of_code/util.clj#L9:L13#2020-12-0217:20pezNeat! Found this a bit late, but I did exactly that. 😃#2020-12-0217:13pezDecided to go the easy path that @plexus pointed out. Copy as cURL from the problem page when I start reading it-> Grab the session cookie there -> (set-fetch-cookie! "<cookie>")
-> Hack away until I need the input -> (util/fetch-input <day>)
(ns pez.aoc2020.util
(:require [clj-http.client :as client]))
(def ^:dynamic *fetch-cookie* "")
(defn set-fetch-cookie! [cookie]
(alter-var-root #'*fetch-cookie* (constantly cookie)))
(defn fetch-input [day]
(if (seq *fetch-cookie*)
(try
(:body (client/get
(str "" day "/input")
{:cookies {"session" {:value *fetch-cookie*}}}))
(catch Exception e
(println "Ho, ho, ho! Did you forget to `set-fetch-cookie!`?")
(throw e)))
(throw (Exception. "Ho, ho, ho! You forgot to `set-fetch-cookie!` first."))))
Like so:
(comment
(def input
"1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc")
(util/set-fetch-cookie! "retracted")
(def input (util/fetch-input 2))
(->> input
(parse)
(filter checks2?)
(map :pwd)
(count)))
Not sure how long the cookie lives, but it should live long enough even for my slow solution pace. And if not, accept that I suck and grab a new session cookie. I’ll see in 11 hours and 47 minutes how much I like this workflow. 😃#2020-12-0217:34drowsyLast year the session never changed.#2020-12-0217:41nbardiukI've just checked that cookie expiration is set for 10 years 😁#2020-12-0217:49pezEven I should be able to solve the puzzles in that time!#2020-12-0217:56spfeifferI am stuck in 2016 somewhere, not sure 10 years will cut it for me 😉#2020-12-0217:40Ben Listnothing fancy but my day 02 solution
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/02.clj#2020-12-0218:19kenjmy also not fancy day 2… I like how declarative it came out looking https://gist.github.com/KennyMonster/eb6ea22eaba1a1a1201820ef1bddc1cf#2020-12-0218:28pezI put my input-slurper into a gist: https://gist.github.com/PEZ/bcd23b9bc099b8b21a41c8c9de78a0f4#2020-12-0219:47Vincent Cantinhi there. Here is my day 1 "theorically fast" solution
https://github.com/green-coder/advent-of-code-2020/blob/801ebdeb9afa3904c1a5e31aeb9386e30e950c78/src/aoc/day_1.clj#L34#2020-12-0220:08Jeff Evansthis is probably more a #beginners question, but figured I’d ask here since it’s related to the Advent of Code stuff I’m trying
why isn’t this working? I copied problem 1's input file to a file called input
in resources
(in a Leinengen app
template project)
(slurp (io/resource "input"))
when run via lein exec my_script.clj
, I get java.lang.IllegalArgumentException: Cannot open <nil> as a Reader
. however, doing the exact same thing in lein repl
works fine#2020-12-0220:31nbardiukI don't use the exec plugin, but looks like it has -p
flag that runs the script in project CLASSPATH, wich is required to resolve the resources#2020-12-0220:32nbardiukhttps://github.com/kumarshantanu/lein-exec
-p indicates the script should be evaluated in project (with classpath)
#2020-12-0220:44Jeff Evansthank you! that was it#2020-12-0220:46kpavha, funny seeing you here @U0183EZCD0D#2020-12-0220:46Jeff Evanstrying to get my day1 and day2 solutions finished and pushed#2020-12-0220:46kpavI am learning clojure too, trying to do AOC with it#2020-12-0220:46Jeff Evanssweet! let’s keep each other accountable#2020-12-0220:49kpavIve got my solutions here, finished day 1 and 2! https://github.com/kwpav/advent-of-code-2020#2020-12-0222:09Jeff Evansnice! I’m a bit behind, only got day 1 done so far: https://github.com/jeff303/advent-of-code-2020#2020-12-0222:09Jeff Evansgonna try to finish day 2 before I look at yours#2020-12-0222:34kpavday 2 was fun#2020-12-0222:56Jeff Evansyeah, almost seems easier, especially with Clojure. though I’m sure part 2 will throw some kind of wrench into it#2020-12-0300:53st3fanSpoiler alert - https://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day2.clj#2020-12-0301:40st3fanIn anticipation of another int computer showing up I rewrite my Python solution from last year in Clojure#2020-12-0301:40st3fanI’m kind of surprised that I am starting to get a feeling for this style of programming#2020-12-0301:41st3fanAnyone interested in taking a peek? It is Day 2 of 2019#2020-12-0302:42st3fanhttps://gist.github.com/st3fan/4c5335a92750f84d62e43fa595fbd906#2020-12-0303:53Vincent CantinI just saw that there is a leaderboard code for this year in the topic: 217019-4a55b8eb
#2020-12-0304:44solfAny libraries you usually use for AoC, besides combinatorics?#2020-12-0304:59Vincent Cantinpriority-map#2020-12-0305:30Vincent Cantinand Regal (https://github.com/lambdaisland/regal)#2020-12-0305:46Vincent Cantinalso this one: https://github.com/Engelberg/ubergraph#2020-12-0305:47Vincent Cantinthis one might become handy in some situation too: https://github.com/clojure/core.logic#2020-12-0306:00fingertoeIt’s always nice when you solve the first problem adaptively enough that the second problem just works.#2020-12-0306:34mchampineAgreed. Mine didn’t “just work” but with a small tweak my part2 function also solved part 1 so I could toss out the first version. I’m ok with that. 🙂. 8 lines total! (not that they’re nice to look at..)#2020-12-0306:53nbardiukmy solution for part 1 was not flexible enough to support variable vertical step, had to refactor first#2020-12-0307:04mchampineSame. I actually started with a more general solution that would have covered both parts, then ‘realized’ it was wasted effort for the first one. My simpler first version + tweak for part 2 was still much less work than the fully general solution I abandoned.#2020-12-0307:27Vincent Cantin> When in doubt, fork your snippets.#2020-12-0306:02fingertoe@dromar56 I usually try to do it without libs.. Most of the time you don’t need them..#2020-12-0306:05solfNone of them needs librairies, it's only if you're trying to go for speed#2020-12-0306:10fingertoeI do tend to create a util namespace as I go and put a lot of code I am likely to re-use there-- Usually as you go, there is a lot of backtracking, and its handy to re-use the stuff you are going to re-use frequently..#2020-12-0306:55plexusSolution for day 3 (spoilers ahead :)) https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle03.clj#2020-12-0306:56plexusRecording of the live stream is available on https://youtube.com/c/LambdaIsland#2020-12-0306:57plexuslook for past live streams or wait until I re-upload a full quality version#2020-12-0307:29Vincent CantinI found myself wasting a lot of time reading the problem’s text.#2020-12-0307:35kenjMy Day 3 solution: https://gist.github.com/KennyMonster/2cdb391d0f45105b8ab38dab58923063#file-day_3-clj-L11#2020-12-0307:44erwinrooijakkersNice. Did not know of take-nth
#2020-12-0309:01Alekshaha, mine is very similar#2020-12-0307:37kenjAnyone have any suggestions on how I can make my (reduce)
more readable? I feel like if I came back even a week from now and read the reduce there, it would take me awhile. At the same time, reducing while updating multiple variables seems like a fairly common thing (at least something I do in Python a lot) and I’m wondering if there’s a better way.#2020-12-0307:45Vincent Cantina loop / recur has similar effect as a reduce, with less destructuring#2020-12-0307:52erwinrooijakkersI’ll take a look, one first suggestion is using #{\#}
instead of #(= \# %)
. See clojure-style-guide: https://github.com/bbatsov/clojure-style-guide#set-as-predicate#2020-12-0307:53erwinrooijakkers;; good
(remove #{1} [0 1 2 3 4 5])
;; bad
(remove #(= % 1) [0 1 2 3 4 5])
#2020-12-0307:56erwinrooijakkersdrop 1
= rest
#2020-12-0308:03kenjThanks for the advice!
I rewrote using loop
and it’s cleaner IMO, though a bit longer
(defn path [dx dy data]
(loop [result-vec []
row-index 0
data (take-nth dy data)]
(if (seq data)
(recur
(conj result-vec (nth (cycle (first data)) row-index))
(+ row-index dx)
(rest data))
result-vec)))
Also thanks for the style guide link Erwin, I updated to use a set predicate as well.#2020-12-0308:04kenjRe drop 1
vs rest
, I thought drop 1
conveyed intentionality a bit more… like for whatever reason this problem doesn’t care about the tree that may or may not exist at your starting point, so drop it :man-shrugging:#2020-12-0308:04erwinrooijakkersi see#2020-12-0308:05erwinrooijakkersAnother way is like this:
(defn path [dx dy data]
(map (fn [row row-index] (nth (cycle row) row-index))
(take-nth dy data)
(iterate (partial + dx) 0)))
#2020-12-0308:06erwinrooijakkersSo use map with two colls, where first coll has the rows, and second coll is lazy seq of x-indices#2020-12-0308:11kenjohhhh that’s clever!#2020-12-0308:12kenjvery concise while still being understandable#2020-12-0308:16erwinrooijakkers🙂#2020-12-0307:42erwinrooijakkersMine: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day3.clj#2020-12-0307:48erwinrooijakkersI was looking for a take-while
that does not return a lazy sequence of the original value up to (pred item)
, but a lazy sequence of the results of (pred item)
. So not
(take-while pos? [2 3 -1]) ;; => (2 3)
but:
(*** pos? [2 3 -1]) ;; => (true true)
does this exist? I implemented a keep-while
by modifing take-while
to do just that, but maybe something exists already#2020-12-0307:50plexus(comp (partial take-while identity) map)
#2020-12-0309:22erwinrooijakkersIt does go up to two times over the collection this way#2020-12-0309:23erwinrooijakkersmap and then take-while, I hoped for a solution that goes over it once#2020-12-0310:17plexusthey're lazy sequences though, sure you'll realize at least a chunk but it won't necessarily map over the whole collection. If you really want to do it single pass then I guess transducers are the way to go
(comp (map your-fn) (take-while identity))
#2020-12-0310:49erwinrooijakkerstrue 🙂 thanks!#2020-12-0307:56Vincent CantinCursive users be like “WHAAAAAAAT????!!!!” (time in the video 21:37~22:37)
https://youtu.be/wXVDfzxeZ-o?t=1297#2020-12-0307:58plexused(1) users be like, pfff no sweat#2020-12-0308:09erwinrooijakkershaha impressive 🙂#2020-12-0308:09erwinrooijakkersI use multiple cursors for those#2020-12-0308:10plexusyeah I went through an mc
phase but don't really use them any more. In the past I would have used emacs macros for these.#2020-12-0308:12erwinrooijakkers#2020-12-0308:13erwinrooijakkersbit more archaic#2020-12-0308:13erwinrooijakkersregex has more flair#2020-12-0308:16plexusif only emacs regexes weren't so terrible#2020-12-0308:17erwinrooijakkerswhy did you stop using mc
?#2020-12-0308:20plexusnot sure it was really a conscious choice. Might have happened when I switched to vim-style bindings#2020-12-0920:52pezVS Code + Calva Paredit.#2020-12-0920:58pezUnfortunately I haven’t had the focused time I need to make Paredit multi cursor. I miss it every day.#2020-12-0307:59Vincent CantinMy solution (mostly inline code) https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_3.clj#L21-L35#2020-12-0308:00Vincent Cantinno named function --> no problem choosing and learning the names#2020-12-0308:01plexusnice and compact!#2020-12-0308:19nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day03.clj - inetersting how part1 is just a smaller example for part2#2020-12-0308:23plexusinteresting! I like how you make a separate sequence of xs and ys and then use multi-arity map!#2020-12-0308:27nbardiukI had to be careful to keep one of the sequences finite 😁#2020-12-0308:50AleksHere is my solution, firstly I used cycle
, but it’s a bit slow, so I replaced it with mod
.
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_03.clj#2020-12-0309:54StuartI tried to solve day 3, I got both parts solved with a rubbish solution here
(let [input (->> (slurp "input.txt")
(str/split-lines))]
(loop [x 0
y 0
trees 0]
(if (>= y (count input))
trees
(let [cur (nth (nth input y) x)]
(if (= cur \#)
(recur (mod (+ 1 x) 31) (+ 2 y) (inc trees))
(recur (mod (+ 1 x) 31) (+ 2 y) trees))))))
But then I tried to rewrite it using iterate, but I'm having two issues.
(defn is-tree [i x _]
(= \# (nth i (mod x 31))))
(let [input (->> (slurp "input.txt")
(str/split-lines))
x-step 7
y-step 1]
(->> (take-nth y-step input)
(map is-tree input (iterate #(+ x-step %) 0))
(filter true?)
(count)))
1. Why is is-tree wanting 3 parameters here? I thought it would want 2 inputs, line from input
and value from my iterate
2. it breaks when y is 2. I should get 30
on my input but I get 32
It works for (1,1), (3,1), (5,1), (7,1) but not (1, 2)#2020-12-0309:56genmeblog[i x _]
<--- you have defined 3 parameters (`_` is also a name for parameter)#2020-12-0309:57Stuartyeah, if i remove that parameter I get an error that I'm passing wrong number of parameters.#2020-12-0309:58genmeblogOk, I see, threading last adds another third sequence to your map.#2020-12-0309:58genmeblogsou you have:
1. input
2. iterate...
3. take-nth... as a thrid#2020-12-0309:58genmeblogjust remove input
#2020-12-0309:58Stuartoh yeah! of course! Thanks#2020-12-0310:01genmeblogAnd this should fix the second problem I suppose#2020-12-0310:02Stuartyes, it did 😄 Thanks for your help!#2020-12-0310:02Stuartsometimes you stare at code and dont see a problem, then someone else spots it in a second!#2020-12-0310:03genmeblogYeah, that's common 🙂#2020-12-0311:21misha(defn trees [lines [dx dy]]
(let [width (->> lines first count)
nextx (fn [x] (mod (+ x dx) width))]
(->> (map get
(take-nth dy lines)
(iterate nextx 0))
(keep #{\#})
(count))))
#2020-12-0311:27genmeblogcool, concise#2020-12-0311:27genmeblogI used map-indexed
in my solution: https://github.com/genmeblog/advent-of-code-2020/blob/master/src/advent_of_code_2020/day03.clj#L11#2020-12-0312:15benoitHi everyone. A little late on the advent of code this year.#2020-12-0312:16benoitMy solution for day3. https://github.com/benfle/advent-of-code-2020/blob/main/day3.clj
I went for readable code (as opposed to concise).#2020-12-0312:16pezNot sure what you peeps have agreed upon before I joined, but I would like if we could post our solutions in threads. So, a post saying things like “here’s my solution for day X”, but then the code/description is in a reply. But if that’s not something others would want too, I’m fine with not opening this channel until I have my own solution.#2020-12-0314:19Vincent CantinThat's a great suggestion. I will abide.#2020-12-0312:36mishaEach day at least one solution will be posted out in the open by somebody who did not get the memo/does not care/does not think it matters/forgot/mis-clicked/etc.
It is hard to coordinate 300+ people without moderation and ban-hammer (like in reddit thread).
So I just don't read the channel until I stuck or have a solution. And when I do, and want to see how to improve it – browsing all the threads often becomes tiresome.
On the other hand, in a week or so solutions will be too large to be spoilers at a glance, so meh ¯\(ツ)/¯#2020-12-0313:17plexusI do think it's good etiquette to not just post solutions directly as code in the chat. If you just consistently remind people in a friendly way then most people will have gotten the message within a day or two. That way people can also edit their post to hide the spoiler. A hint in the channel topic would also be good, though I'm aware that far from everyone actually reads that.#2020-12-0313:19plexusbut also yes, if you really don't want to be spoilt then it's probably best to avoid this place until you've done the puzzle. Sometimes it's just a matter of discovering the right type of data structure or something like that, where it's not so much seeing the code but just seeing people talk about what they used to solve it.#2020-12-0313:27mishaI agree with you on "good etiquette", but still forecast "at least one open solution per day", now with additional ignored "guys, please post in threads" messages on top of that opieop#2020-12-0314:23Vincent CantinIf most people agree, we admins can delete the spoilers and copy/paste a short what-to-do notice.#2020-12-0314:21Joehttps://redpenguin101.github.io/posts/2020_12_03_aoc2020_day3.html#2020-12-0314:23Vincent CantinIf most people agree, we admins can delete the spoilers and copy/paste a short what-to-do notice.#2020-12-0314:26Vincent CantinBut I won't be watching the chan before I finish my solutions.#2020-12-0316:51mishaI don't see any value in pursuing this:
• it is extra work for moderators, and deleting others' messages is not justified at all.
• moderation will always be late, and spoilers will have time to spoil.
• the spoiling window closes fast even without moderation, and by the end of the same day open code snippets become more convenient to browse than drilling down the threads (where code formatting sucks: not even 80 chars wide! )
• daily answers thread is horrible solution, because there is no nesting thread-in-tread. But with top level link or code - thread can have related dedicated discussion
#2020-12-0318:13pezAgree we do not need to use moderators for this. We can encourage each other. It’s not the end of the world if I see spoilers, just would be nice if most solutions were a click away.#2020-12-0318:49erwinrooijakkersAgreed as well#2020-12-0318:49erwinrooijakkersYou can expect to see spoilers if you come here, same for https://old.reddit.com/r/adventofcode#2020-12-0319:12mishait is "would be nice if most solutions were not a click away" for me though d
I'd settle on "click to expand away" :)
but generally, the key to disappointment is expectations:
If 1) you expect this channel to be moderated, 2) someone new or not-caring posts spoiler code 3) moderator is busy solving, and is late to moderate, but 4) comes and deletes spoiler:
• you are upset you saw a spoiler
• moderator is upset there were spoilers to moderate
• poster is upset their message is deleted#2020-12-0319:13mishaExtra work, but everybody is still upset. Not worth it, imo.#2020-12-0320:48pezNot sure what tree you are barking up agains, @U051HUZLD. No-one expects to have a spoilerfree environment. I am just asking if people could consider putting their spoilers in a reply. Now and then someone new will not notice this practice. That’s how it is.#2020-12-0320:55misha"barking", ok#2020-12-0323:37pezI’m sorry. Didn’t mean it literally and didn’t mean to be rude.#2020-12-0315:52st3fanDay 3 https://gist.github.com/st3fan/2308d8a849fe47b0b31e2d3108870660#2020-12-0315:52st3fanI should put part3 in a loop instead of separate calls#2020-12-0315:52erwinrooijakkersYou should put your answer in a thread 😛#2020-12-0315:55plexusposting links is fine, right? 🙂#2020-12-0315:55pezYeah, posting links is fine, me thinks.#2020-12-0315:55plexusnot sure if you were joking, I guess the 😛 is tongue in cheek#2020-12-0315:59erwinrooijakkersyes it was a medium joke#2020-12-0316:00erwinrooijakkersthat way of posting is fine indeed there’s no code visible. although i think if you don’t want spoilers and hints don’t go here. i use this channel to check for nice solutions.#2020-12-0316:01st3fanwill someone pin a daily answers thread then?#2020-12-0316:01st3fani can't find the right thread#2020-12-0316:02st3fanDay 3 Answers Thread .. Post your answers here#2020-12-0316:03st3fanhttps://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day3.clj#2020-12-0316:04nbardiukhttps://clojurians.slack.com/archives/C0GLTDB2T/p1606983569135300#2020-12-0316:15Stuarthttps://gist.github.com/stuartstein777/b9e34125f48d3c7791c2e08e7c41e576#2020-12-0316:21plexushttps://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle03.clj#2020-12-0316:28Joehttps://redpenguin101.github.io/posts/2020_12_03_aoc2020_day3.html#2020-12-0318:54Ben Listhttps://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/03.clj#2020-12-0401:20mchampine(def raw-input (str/split-lines (slurp "resources/day03.data")))
(defn trees [inp [x y]]
(let [expinp (map #(apply str (repeat 80 %)) inp)
lines (rest (take-nth y expinp))]
(count (filter #{\#} (map #(nth % %2) lines (range x 2300 x))))))
(trees raw-input [3 1]) ;; part 1
(apply * (map (partial trees raw-input) [[1 1] [3 1] [5 1] [7 1] [1 2]])) ;; part 2
#2020-12-0418:11Lars Nilssonhttps://github.com/chamaeleon/aoc2020-clj/blob/master/src/aoc2020/day03.clj#2020-12-0423:06pezWith some pointers from @U051HUZLD (gaining me x200 speed!):
(ns pez.aoc2020.day-3
(:require [clojure.string :as s]
[pez.aoc2020.util :as util]))
(defn line-landing [dx line]
(-> line
(nth (mod dx (count line)))))
(defn count-trees [[dx dy] woods]
(->> woods
(take-nth dy)
(map line-landing (take-nth dx (range)))
(filter #{\#})
(count)))
(comment
(def input (util/fetch-input 3))
(time
(as-> input $
(s/split-lines $)
(map #(count-trees % $) [[1 1] [3 1] [5 1] [7 1] [1 2]])
(apply * $)))
;; "Elapsed time: 1.75155 msecs"
;; => 3316272960
)
#2020-12-0316:02st3fanDay 4 Answers Thread .. Post your answers here#2020-12-0406:34djbluehttps://github.com/djblue/advent-of-code/blob/master/src/advent_of_code/core_2020.clj#L106#2020-12-0414:23mchampineMy part 1
(def processed-input
(->> (str/split-lines (slurp "resources/day04.data"))
(partition-by empty?)
(take-nth 2)
(map #(apply str %))))
(defn allkeys? [l]
(every? #(str/includes? l %)
["ecl:" "pid:" "byr:" "eyr:" "hcl:" "hgt:" "iyr:"]))
(count (filter allkeys? processed-input))
#2020-12-0417:59st3fanhttps://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day4.clj#2020-12-0418:07Lars Nilssonhttps://github.com/chamaeleon/aoc2020-clj/blob/master/src/aoc2020/day04.clj#2020-12-0421:57rjrayThis is my cleaned-up day 4 code: https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day04bis.clj. I don't know why I struggled with this one, or why the first pass at it was so cluttered.#2020-12-0422:09pezOh, a day 4 solutions thread. Nice! https://gist.github.com/PEZ/42375289c032e43ee6dd8cd40b3c1b42#2020-12-0500:13neeasademany good solutions here. adding mine https://github.com/neeasade/AdventOfCode/blob/66cdb6073b37ce854f3d102575040f786395355c/src/aoc/2020.clj#L64-L116#2020-12-0316:06st3fanI started to build a utils with some things like (load-input day tranformer-fn)
to make things simpler#2020-12-0316:16StuartThe leaderboard is crazy, it takes me longer to read the puzzle description and parse what i've actually to do than it takes some people to solve part 1#2020-12-0316:19Vincent CantinI upgraded my deps.edn with more dependencies, just in case.
https://github.com/green-coder/advent-of-code-2020/blob/master/deps.edn#2020-12-0316:24Vincent CantinI noticed that it is possible to read the time at which people got their stars in the JSON file following the [API] link.#2020-12-0316:28Vincent CantinI mean in the Clojurian leaderboard.#2020-12-0316:28Vincent CantinToday, the fastest was about 16 minutes (5:16 a.m. UTC)#2020-12-0316:25natein the past there has been a github repo with a list of links to individual repos with advent solutions, has anyone started that yet this year?#2020-12-0316:37plexusthere's one in the channel topic, but it only mentions 2017 and 2018, although it did just get a commit#2020-12-0316:40nateah cool#2020-12-0316:51mishaI don't see any value in pursuing this:
• it is extra work for moderators, and deleting others' messages is not justified at all.
• moderation will always be late, and spoilers will have time to spoil.
• the spoiling window closes fast even without moderation, and by the end of the same day open code snippets become more convenient to browse than drilling down the threads (where code formatting sucks: not even 80 chars wide! )
• daily answers thread is horrible solution, because there is no nesting thread-in-tread. But with top level link or code - thread can have related dedicated discussion
#2020-12-0316:58plexusSo what you're saying is you actually prefer people to post their answers directly inline?#2020-12-0317:03mishainline is fine with me. And it is way better than any moderation fuzz around it (which is 70% of today's messages). There are plenty of places where moderation is organic, and, more importantly, expected. I don't think it fits here, specifically because gains are so tiny, but cost is not.#2020-12-0317:45st3fan@qmstuart i've given up on the leader board .. also because I'm in EST I would have to stay up till midnight and then start hacking on a solution. So instead I am fine collecting stars and just writing nice solutions. I'm more than happy if I am actually able to solve these with my current Clojure skills. And learn a few new tricks from others.#2020-12-0317:46Stuart@st3fan yeah, puzzle go live at 5am my time. No way am I getting out of bed that early!#2020-12-0317:46st3fan5am I could do! 🙂#2020-12-0318:01plexushere it's 6am, which somehow because of the pandemic is later than when I usually get up 🙂#2020-12-0318:47erwinrooijakkers6am i made today and hopefully tomorrow again 🙂 really nice to see the clock ticking#2020-12-0318:53erwinrooijakkers#2020-12-0319:47Jeff Evansdoes everyone get different inputs?#2020-12-0319:47Jeff Evansah, yes. opening incognito reveals this: Puzzle inputs differ by user. Please log in to get your puzzle input.
#2020-12-0321:33st3fanYup no cheating!#2020-12-0322:29Jeff Evansnot cheating, just curious 🙂#2020-12-0322:51Jeff EvansI checked the FAQ but couldn’t figure it out… is there a day limit to finish the last problem? Not planning to actually tackle the last one on Christmas day…#2020-12-0323:16rjrayNo day limit on any of the problems (people often go back to previous years as practice). But you won't get a positional ranking for any solution that takes more than 24 hours.#2020-12-0400:52pezI spent a lot of time counting all the trees passed vertically for when the sled goes 1 right, 2 down. I don’t know why I started to think I should do that when I didn’t do it horizontally… Anyway, if someone ever needs a sequence of x-deltas for a instructions like “x right, y down, forever”, here goes:
(defn dxs [dx' dy']
(map (fn [line dx dy]
(* (+ line dy) dx))
(range)
(repeat dx')
(cycle (range dy'))))
¯\(ツ)/¯#2020-12-0401:57pezI’m a bit stuck on day 3, step 2. I get the right answer for the sample data, but too low for the real input. Not sure how I should go about debugging it. My solution looks like so, so far. (In the reply.)#2020-12-0401:57pez(defn landing [dx line]
(->> line
(seq)
(repeat)
(flatten)
(drop dx)
(first)))
(defn count-trees [[dx dy] woods]
(->> woods
(take-nth dy)
(map landing (map #(* % dx) (range))) ; is (take-nth dx (range)) better?
(filter #{\#})
(count)))
(comment
(def input (util/fetch-input 3))
(as-> input $
(s/split-lines $)
(map #(count-trees % $) [[1 2] [3 1] [5 1] [7 1] [1 2]])
(apply * $)))
#2020-12-0402:15pezFound it! I fed it [1 2]
instead of [1 1]
for the first slope….#2020-12-0402:24pezIt takes about half a sec on my pretty fast MacBook.#2020-12-0405:37misha1. replace
(repeat)
(flatten)
with (cycle) for probably x2 speedup
2. replace (cycle) with (mod dx line-len) for next x5-x10 speedup#2020-12-0405:40misha3. replace drop, first with nth for 3rd speedup#2020-12-0405:41misha(let [s (str/join (range 1000))]
(time (nth s 2000))
(time (first (drop 2000 s))))
"Elapsed time: 0.01144 msecs"
"Elapsed time: 0.264392 msecs"
#2020-12-0407:39pezSweet! I got a x10 when replacing (seq) (repeat) (flatten)
with (cycle)
.#2020-12-0407:44pez> 2. replace (cycle) with (mod dx line-len) for next x5-x10 speedup
Not following here.#2020-12-0408:17pezReplacing drop, first with nth gained me x1.2-ish, but I’ll of course keep that and celebrate the speed gain, since it is WAY clearer.#2020-12-0408:29mishanth is linear lookup.
with cycle, each next line does longer and longer linear lookups#2020-12-0408:30mishae.g.:
...
.....
.......
.........
...........
.............
#2020-12-0408:31mishaif you mod
your Xs, your lookups will be:
...
.....
.......
...
.....
.......
#2020-12-0408:34misha(time (nth (cycle "abcd") 100000))
"Elapsed time: 7.717277 msecs"
=> \a
(time (nth "abcd" (mod 100000 (count "abcd"))))
"Elapsed time: 0.093352 msecs"
=> \a
#2020-12-0408:47pezGotcha. Down to 2.5 msec now. That’s x200 in total!#2020-12-0408:52mishatatatananana#2020-12-0408:53pezThis is super helpful to me. I often reach for mod
quickly. This time it was much easier for me to visualize it if I actually repeated the pattern indefinitely. But I should of course have remembered/realized to translate it to mod
once it worked.#2020-12-0402:18pezI updated my input-fetcher to read the cookie from a file instead, like @plexus does in his bash script: https://gist.github.com/PEZ/bcd23b9bc099b8b21a41c8c9de78a0f4#2020-12-0405:15rutledgepaulvthat second part was a lot of minutiae haha#2020-12-0405:50plexusLive stream for day 4 starting soon https://youtu.be/K3f10iwxtOw#2020-12-0407:03plexusAnd the recording: https://youtu.be/XaXB0kbpvjw
Code: https://github.com/lambdaisland/aoc_2020/#2020-12-0407:46Vincent Cantinoh … I feel stupid, I did not think about that (str/split real-input #"\R\R")
#2020-12-0409:03Alekshttps://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle04.clj#L35-L44
the fields are not used anywhere, so they could be removed ^_^#2020-12-0409:03plexusyes, I know#2020-12-0412:08JoeWhat does #"\R\R"
match on? From context it looks like a double carriage return, but is it different from #"\r\r"
? https://regexr.com/ says \R
is just an escaped R, which it clearly isn't in this case.#2020-12-0412:15plexusit matches "\r" "\n" "\r\n" or a number of unicode newline characters. It does not backtrack between "\r\n", so #"\R\R" will match "\r\r" but not "\r\n" (it will match "\r\n\r\n")#2020-12-0412:15plexusbasically it matches everything that conceptually is a newline#2020-12-0412:15JoeAh nice, thanks#2020-12-0405:50Vincent CantinI woke up too late today, bye bye leaderboard 😢#2020-12-0405:52rutledgepaulvyeah i went to bed early and didn't do yesterday's problem until right before tonight's so also dropped 😞#2020-12-0406:27plexusmeh... the leaderboards are really the last of my concerns 🙂#2020-12-0406:30rjrayArgh. Tonight's took much longer than it should. I'm much more rusty than I thought.#2020-12-0406:33djblueParsing and validation feels too much like real work 😆#2020-12-0406:54Aleksso true, and so boring#2020-12-0407:04plexusI was just thinking "if this doesn't work from the first try it's going to suck to debug", but luckily it did#2020-12-0407:09kenj80% of my part 1 solution is parsing 😞#2020-12-0406:35plexusyeah can't say day 4 was particularly interesting... just tediously converting rules into code#2020-12-0406:45plexusso far the puzzles have been surprisingly easy though... was it like this in the past? it's been two years since I participated so maybe I remember it wrong, I guess it'll get harder in a few days.#2020-12-0406:49djblueLast year, for some of the puzzles, we built up a little byte code VM and our inputs were programs, it was pretty cool#2020-12-0406:50djblueWe even got to chain the programs together via input/output ports#2020-12-0406:50AleksYeah, I loved it.#2020-12-0406:51AleksLast year, the first a bit challenging puzzle for me was on day 10, then day 12.#2020-12-0406:54AleksDay 22, part 2 was pretty hard for the most of the participants.#2020-12-0407:40spfeifferYes, it gets harder, and perhaps this year they toned it down a little bit, because i remember last year the were some frustrated participants.#2020-12-0407:50fingertoeIt seems to me the past years I have done it, it gets steeper pretty fast after the first 3 or 4 days. It also tends to go back an re-factor off of your old solutions, so it’s hard to jump right in if you get behind.#2020-12-0407:53nbardiuklast year day 3 was already challenging. If you look at stats https://adventofcode.com/2019/stats you can find where people have dropped off. Like days 3, 7, 18#2020-12-0408:06erwinrooijakkersLast year became really challenging for me, but first four days were similar to this year. It was interesting last year with puzzle inputs being programs in a fictional language called intcode you fed in various ways to your own interpreter(s) that you build up over the days with various stories around it (having a robot that runs on a computer that has to perform certain tasks by feeding it input and the coordinates it spit out in return will display a word which is your answer, stuff like that). Also a puzzle that could best be solved using trigonemetry and one with fast fourier transforms. Was magical and instructive.#2020-12-0407:41Vincent CantinMy solution to day 4: https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_4.clj#2020-12-0408:26Vincent Cantin@plexus I used Regal 🙂#2020-12-0408:26plexusI'm glad someone did :rolling_on_the_floor_laughing:#2020-12-0408:28Vincent CantinI am happy I spent time to get familiar with it, it might be useful one day.#2020-12-0407:49fingertoeThat was way harder than it needed to be.. 😉. I really need to learn my destructuring better..#2020-12-0407:49nbardiukToday is a bit boring, but I've spend some creativity on refactoring parsing rules#2020-12-0407:50nbardiukhttps://github.com/nbardiuk/adventofcode/blob/22219651baab8485652b456770e4134a2dee6ba0/2020/src/day04.clj#L31-L40#2020-12-0407:59Ben ListNot super happy with what I came up with today. But I'm still new to clojure
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/04.clj#2020-12-0408:31plexusinteresting that you reach to core.match
for this!#2020-12-0408:46erwinrooijakkersindeed very nic#2020-12-0408:46erwinrooijakkerse#2020-12-0413:37motformalways fun to see core.match!
Also, if you want to destructure map keys into vars with the same name, you can use the handy :keys
syntax (defn validate-passport-fields [{:keys [ecl pid eyr hcl byr iyr hgt]} ,,,)
#2020-12-0414:48Ben ListI'm a scala dev by trade so pattern matching calls to me, and great tip thanks!#2020-12-0408:10erwinrooijakkersMissed my alarm, tedious puzzle luckily everything worked first try#2020-12-0408:10erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day4.clj#2020-12-0408:17mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day04.cljc#2020-12-0408:52nbardiukAOC made bad job generating invalid passports 😆 you code proves that
• all years fields are actually numbers
• height does not have other text than number and unit of measure
• documents do not have keys other than explicitly specified #2020-12-0408:53mishatrue#2020-12-0408:59misha(remove #(not-empty (dissoc % "hgt" "byr" "eyr" "iyr" "ecl" "hcl" "cid")))
and
(defn parse-int [s else]
(try
(Integer/parseInt s 10)
(catch Exception e else)))
(parse-int "foo" -1)
=> -1
would fix that#2020-12-0408:19mishaover-engineering, over-engineering everywhere facepalm#2020-12-0409:13AleksMy solution to day 4, but I’m going to refactor it
https://github.com/zelark/AoC-2020/blob/72968c3e2baa8fcb2a2a5a0ff84d9a6fb689f644/src/zelark/aoc_2020/day_04.clj#L1#2020-12-0414:03Aleksa refactored version https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_04.clj#2020-12-0411:34genmeblogand mine solution (possibly over-engineered 🙂) https://github.com/genmeblog/advent-of-code-2020/blob/master/src/advent_of_code_2020/day04.clj#2020-12-0422:59pezI think it is super nice. I learn a lot by looking at it. One thing makes me wonder “why?” though, and that is your between?
function. Is (partial between? 1920 2002)
more readable to you than #(<= 1920 % 2020)
?#2020-12-0411:54Joehttps://redpenguin101.github.io/posts/2020_12_04_aoc2020_day4.html - clojure.spec seems tailor-made for this 🙃. No-one else seemed tempted though? Just not worth it for such a simple use case?#2020-12-0412:05nbardiukI've given up on specs, but when I got a wrong answer regretted it. Spec's explain would be very useful to debug which rule invalidated an entry#2020-12-0413:35erwinrooijakkersI was in a hurry. Would have loved to use Malli or spec#2020-12-0413:36Vincent CantinI solve the puzzle using Minimallist, a library inspired by Malli and Spec.
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_4.clj#2020-12-0412:43benoitMy solution to Day 4 with clojure.spec: https://github.com/benfle/advent-of-code-2020/blob/main/day4.clj#2020-12-0413:40motformGreat to see someone use spec! My solution is very boring, I’m sure parse-passport
and valid-hgt?
could be more terse, but it was a bit to boring to refactor. https://github.com/motform/advent-of-clojure/blob/master/src/advent-of-clojure/2020/four.clj#2020-12-0413:41motformAlso, general question! Dones anyone have any examples of fancy ways of doing validation? Rule based systems?#2020-12-0414:28StuartMy day 4. Not a great solution, but it worked in the end.
https://gist.github.com/stuartstein777/7b69f6f39fe44669c77e935ba1249aec#2020-12-0414:36Narve SaetreI am really glad I used spec for part 1 😄 First practical use of spec for me:
(def text (slurp "adv4.input.txt"))
;(def text "ecl:gry pid:860033327 eyr:2020 hcl:#fffffd\nbyr:1937 iyr:2017 cid:147 hgt:183cm\n\niyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884\nhcl:#cfa07d byr:1929\n\nhcl:#ae17e1 iyr:2013\neyr:2024\necl:brn pid:760753108 byr:1931\nhgt:179cm\n\nhcl:#cfa07d eyr:2025 pid:166559648\niyr:2011 ecl:brn hgt:59in")
(defn parse-line [l]
(let [
psa (string/split l #"[\s+]")
pa (map #(string/split %1 #"\:") psa)
ma (map (fn [p] {(first p) (second p)}) pa)
m (apply merge ma)]
m))
(def entries (map parse-line (string/split text #"\n\n")))
(s/def ::byr (s/and string? #(<= 1920 (bigint %1)) #(>= 2002 (bigint %1))))
(s/def ::iyr (s/and string? #(<= 2010 (bigint %1)) #(>= 2020 (bigint %1))))
(s/def ::eyr (s/and string? #(<= 2020 (bigint %1)) #(>= 2030 (bigint %1))))
(s/def ::hgt (s/and string? (s/or ::in #(re-matches #"\d{2}in" %1) ::cm #(re-matches #"\d{3}cm" %1))))
(s/def ::hcl (s/and string? #(re-matches #"\#[0-9a-f]{6}" %1)))
(s/def ::ecl #{"amb" "blu" "brn" "gry" "grn" "hzl" "oth"})
(s/def ::pid (s/and string? #(re-matches #"[0-9]{9}" %1)))
(s/def ::passport
(dict {"ecl" ::ecl
"pid" ::pid
"eyr" ::eyr
"hcl" ::hcl
"byr" ::byr
"iyr" ::iyr
"hgt" ::hgt}))
(def v (count (filter #(s/valid? ::passport %1) entries)))
(println "Valid: " v " total " (count entries))
#2020-12-0415:08Vincent Cantin@USAGL3YUS As the topic says, please put spoilers in thread replies. Thank you.#2020-12-0415:08Vincent Cantinlinks to code are also ok#2020-12-0417:09Ben Listfyi you can do (<= min num max)
instead of (and (<= min num) (>= max num)
#2020-12-0619:39Narve SaetreRight, sorry i'll use thread replies or links next time.#2020-12-0619:40Narve SaetreThanks for the hint, @U01CNM6254M - I saw that in other submissions. Lots of improvements to make!#2020-12-0417:35mishad#2020-12-0417:38tschadyanother spec sol’n. To handle part1 being less specific, I would up with a non s/keys
spec for it. Any ideas there? I didn’t want to start undef’ing specs for half the problem.
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d04.clj#2020-12-0417:40tschadyi have unit tests that verify part-1 and part-2 are still correct as I refactor and optimize, so I need both parts to work at same time.#2020-12-0417:42tschady(like ::hgt
needs refactoring)#2020-12-0417:43Aleksbtw, you could a bit simplify the spec for part 1#2020-12-0417:43Aleks(every? (partial contains? %) required-fields)
would work#2020-12-0417:47tschadymuch better, updated, thanks!#2020-12-0417:54Jeff Evansare you assuming for day4, part1 that the “values” are always non-empty?#2020-12-0418:00nbardiukyes, if there is a key it has a value#2020-12-0419:32pezIf there is a will there is a way. #2020-12-0417:56st3fanOhh I should have used spec for this one#2020-12-0417:57st3fanOne thing I learned today is (<= 150 height 193)
- which is a nice readable short form for (and (…) (…))#2020-12-0417:58st3fanDay 5 Answers Thread .. Post your answers here#2020-12-0505:54mchampine;; part 1
(def input (str/split-lines (slurp "resources/day05.data")))
(def fblrbits {\F 0 \B 1 \L 0 \R 1})
(defn seatcode [v]
(-> (apply str (map fblrbits v)) (Integer/parseInt 2)))
(def codes (map seatcode input))
(apply max codes)
;; part 2
(let [dc (partition 2 1 (sort codes))]
(inc (ffirst (filter (fn [[a b]] (= 2 (- b a))) dc))))
Explanation:
Part 1: FBLR code is just binary. Convert to 1's and 0's and then to base 10.
Part 2, You’re looking for a gap. Sort the codes and make pairs of (code, nextcode). Where that difference is 2, your seat number is in-between them, so add one to the first value.#2020-12-0506:16rjrayDefinitely more verbose than the previous one 🙂. This is my post-submission cleaned-up version: https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day05bis.clj#2020-12-0506:24AdamHi 👋 here's https://github.com/ocisly/advent2020/blob/94b52d8bb63865a8ace75f34226f6acb390c69ef/day-5.clj#L5-L36#2020-12-0507:10Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_5.clj is here.#2020-12-0507:13plexushttps://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle05.clj#2020-12-0507:19fingertoehttps://github.com/jreighley/aoc2020/blob/master/src/day5.clj. Kinda messy — I always feel clever when I can map gibberish data to functions.#2020-12-0510:32tschadywith clojure.set
I go for readability with some lets
. https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d05.clj#2020-12-0510:32Dos(def l->b {\B 1 \F 0 \R 1 \L 0})
(def powers-of-2 (iterate (partial * 2) 1))
(->> s
(map l->b)
reverse
(map * powers-of-2)
(apply +))
#2020-12-0511:09AleksMy final decode is
(defn decode [code]
(-> (str/escape code {\F 0 \L 0 \B 1 \R 1})
(Long/parseLong 2)))
That’s all you need 🙂#2020-12-0512:14Joehttps://redpenguin101.github.io/posts/2020_12_05_aoc2020_day5.html - I didn't pick up on the 'trick', very cool though! Even without it it can be solved very concisely.#2020-12-0513:14JoeI'm also linking to and trying to summarize and comment on other peoples solutions on that page, hope no-one minds#2020-12-0515:15BradMy day 5 solution: https://github.com/bradlucas/advent-of-code-2020/blob/master/src/advent/day05.clj#2020-12-0515:36st3fanhttps://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day5.clj#2020-12-0515:36st3fanNot super proud of part 2 - I think that could have a simpler solution#2020-12-0515:37st3fanHmm subvec
#2020-12-0515:38st3fanOhh reduce
clever I did a recursive loop#2020-12-0515:40st3fanomg a binary decode#2020-12-0515:41st3fansigh 🙂#2020-12-0515:41st3fanShould have recognized that#2020-12-0516:17jculp(ns advent.day5
(:require [advent.core :as core]
[clojure.string :as s]))
(defn seat-id [boarding-pass]
(-> boarding-pass
(s/replace #"[FL]" "0")
(s/replace #"[BR]" "1")
(Integer/parseInt 2)))
(->> (core/input-file "day5.txt")
(map seat-id)
(reduce max))
;; => 998
(defn my-seat? [[a b]]
(= 2 (- b a)))
(->> (core/input-file "day5.txt")
(map seat-id)
sort
(partition 2 1)
(filter my-seat?)
first
first
inc)
;; => 676
I thought the partition
for part 2 was clever, but wondering if theres a better way to do the filter, first, first, inc chain?#2020-12-0516:19Aleks@U0ESCTA1E yes, as Arne showed you could use some
instead.#2020-12-0516:20Aleks(some (fn [[lo hi]] (when (= (+ lo 2) hi) (inc lo))))
#2020-12-0516:31jculpclever!#2020-12-0516:57mchampine;; day 5 super golf
(let [ec #(-> (str/escape % {\F 0 \B 1 \L 0 \R 1})
(Integer/parseInt 2))
sc (sort (map ec (str/split-lines
(slurp "resources/day05.data"))))
p2 (ffirst (drop-while #(apply = %)
(partition 2 (interleave (iterate inc (first sc)) sc))))]
{:part1 (last sc) :part2 p2})
#2020-12-0517:08plexussome+when is a useful pattern. I vastly prefer it nowadays over filter+first#2020-12-0518:52Ben Listmy day 5, didnt pick up on the trick until I was nearly done but still fairly happy with the result (I did a scala solution using the trick afterwards)
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/05.clj#2020-12-0518:55Ben Listscala version if anyone cares to see that: https://github.com/listba/advent-of-code-2020/blob/master/scala/src/main/scala/aoc2020/solutions/day-05.scala#2020-12-0523:52Ola SikströmInteresting to see all different/similar solutions 🙂
Here's my take https://github.com/teppix/advent-of-code-2020/blob/main/src/advent/day05.clj
Used bit-shifting instead of the '2r' trick, but same idea.#2020-12-0601:50devnI am extremely jealous of @U06B54Y95’s solution#2020-12-0601:52devnhttps://gist.github.com/devn/29ee7fc152e359dd6c3a604b372291fb#2020-12-0417:59st3fanDay 6 Answers Thread .. Post your answers here#2020-12-0605:11AdamWell, that was https://github.com/ocisly/advent2020/blob/1a4b5d46c17a67b86b274e12a37a13cd5d035b92/day-6.clj#L5-L11!#2020-12-0605:32rjrayMine was basically the same as Adam’s, just more verbose 🙂. https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day06.clj#2020-12-0605:34Dos(->> (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 +))
#2020-12-0605:42fingertoehttps://github.com/jreighley/aoc2020/blob/master/src/day6.clj. I really seem to like sets this year.#2020-12-0606:03mchampineMine looks similar to others..
;; part 1
(def input
(->> (slurp "resources/day06.data")
str/split-lines
(partition-by empty?)
(take-nth 2)))
(apply + (map #(count (set (apply str %))) input))
;; part 2
(defn groupcnt [l]
(count
(for [x (set (apply str l))
:when (every? #(str/includes? % (str x)) l)] x)))
(apply + (map groupcnt input))
#2020-12-0606:20Vincent CantinI used frequencies
for part 2
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_6.clj#2020-12-0606:31AleksAnd I used union for the part 1, and intersection for the part 2. Just went with the same data structure for the both parts.
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_06.clj#2020-12-0606:36nbardiukTurns out both parts differs only whether it is set intersection or union https://github.com/nbardiuk/adventofcode/blob/c30b10fc2320c8f29fb9e84dd9afeaad3b04363b/2020/src/day06.clj#L17-L18#2020-12-0607:25Vincent CantinI had that intuition as well, but the timer told me to write first and think later 😛#2020-12-0607:41kenjI rewrote my part 1 after noticing the same thing about the set operations https://gist.github.com/KennyMonster/ef878c0a789cebe2df3e572a11803f01#2020-12-0607:56Ben Listdefinitely a pretty easy one with set operations
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/06.clj#2020-12-0609:13pezI want more of these easy ones.
(comment
(def input (util/fetch-input 6))
; step 1
(->> (clojure.string/split input #"\R\R")
(map #(clojure.string/replace % #"\R" ""))
(map #(clojure.string/split % #""))
(map set)
(map count)
(apply +))
; step 2
(->> (clojure.string/split input #"\R\R")
(map clojure.string/split-lines)
(#(for [answers %]
(->> answers
(map set)
(apply clojure.set/intersection))))
(map count)
(apply +)))
#2020-12-0611:33tschadyhttps://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d06.clj#2020-12-0612:53Joehttps://redpenguin101.github.io/posts/2020_12_06_aoc2020_day6.html#2020-12-0614:15Bradhttps://github.com/bradlucas/advent-of-code-2020/blob/master/src/advent/day06.clj#2020-12-0616:43Stuart;; part 1
(defn count-answers [s]
(->> (mapcat #(str/split % #"") s)
(into #{})
(count)))
;; part 2
(defn count-answers-2 [s]
(let [num-people (count s)
combined (apply str s)
answer-frequencies (frequencies combined)]
(->> (filter (fn [[_ v]] (= num-people v)) answer-frequencies)
(count))))
;; shared
(as-> (slurp "puzzle-inputs/2020/day6") o
(str/split o #"\R\R")
(map #(str/split % #"\n") o)
(map count-answers-2 o)
#_(map count-answers o)
(reduce + o))
#2020-12-0622:09neeasadeI did something really silly at first lol -- forgot you could just (set "string")
-- https://github.com/neeasade/AdventOfCode/commit/aa941beeb54407bde2b7a00c6678d34345eff80c#2020-12-0622:50st3fanhttps://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day6.clj#2020-12-0418:00st3fanCheck the pinned threads people - no spoilers in the main channel#2020-12-0418:13kenjMy solution using spec… probably poorly since I just recently learned it 🙂 https://gist.github.com/KennyMonster/a51c03c53403e76413aa2fe4d61d57a4#2020-12-0422:08pezMy day-4 solution. I have a feeling I could have used spec for the parsing, but I’m such a newbie with spec so what do I know. https://gist.github.com/PEZ/42375289c032e43ee6dd8cd40b3c1b42#2020-12-0423:09curlyfryI've been using re-seq
with capturing groups pretty heavily in some of these, just in case someone wasn't aware of it! Can be a really nice way of parsing the input sometimes if it follows a simple pattern. Less string splitting and you get a seq of the values you're interested in right away.#2020-12-0423:14kenjthis would have simplified parsing on day 4 for me!#2020-12-0423:20pezI used it for my day 4 parser, which ended up like so:
(defn parse [card]
(->> (clojure.string/replace card #"\s" " ")
(re-seq #"(\S+):(\S+)")
(map rest)
(reduce
(fn [m [k v]]
(assoc m
(keyword k)
v))
{})))
#2020-12-0423:32kenjI just refactored mine from a giant nasty looking threading macro doing all sorts of terrible hack n slash
(defn parse-passport-chunk [s]
"key/val pairs separated by whitespace into a map"
(into {} (map (fn [[_ key val]] [(keyword key) val])
(re-seq #"(\w+):(\S+)" s))))
(defn input->passports [s]
"Raw input -> map of passwords w/ keyword keys"
(->> (str/split s #"\n\n")
(map parse-passport-chunk)))
#2020-12-0423:38pezYeah, ours are pretty similar now. And I can also get rid of that (map rest)
and do what you do there:
(defn parse [card]
(->> (clojure.string/replace card #"\s" " ")
(re-seq #"(\S+):(\S+)")
(reduce
(fn [m [_ k v]]
(assoc m
(keyword k)
v))
{})))
#2020-12-0423:49kenjgiven how your regex is defined, I don’t think there’s even a need to do the replace
call to normalize the whitespace, since it will be thrown out by re-seq
regardless#2020-12-0423:54pezYeah, I realized that when I saw your code. 😃#2020-12-0504:20neeasadethanks for mentioning re-seq, I remember when I first encountered it and then suddenly I use it literally everywhere. Another tip: with destructuring, you get really smooth group matches to bound names:
EG from my day2 of Advent:
(let [[_ lower upper letter pass] (first (re-seq #"([0-9]+)-([0-9]+) ([a-zA-Z]): (.+)" line))]
;; do stuff with lower, upper, letter, pass
)
#2020-12-0505:06kenj@U4TGNN19D If you use re-matches
you don’t even need the first
:
(let [[_ pmin pmax pc password]
(re-matches #"(\d+)-(\d+) ([a-z]): ([a-z]+)" s)])
#2020-12-0622:08neeasade@UBHTL6AF3 thanks!#2020-12-0507:10Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_5.clj is here.#2020-12-0512:14Joehttps://redpenguin101.github.io/posts/2020_12_05_aoc2020_day5.html - I didn't pick up on the 'trick', very cool though! Even without it it can be solved very concisely.#2020-12-0505:27Vincent CantinGood morning#2020-12-0505:51fingertoeDay 5 probably would have been a lot easier if I had carefully read the problem.. Not too bad though..#2020-12-0505:52rjrayDay 5 done. I found the wording of part 2 to be very confusing. Lost time trying to figure out WTF was being asked for. Once I understood, the solution was pretty simple.#2020-12-0506:16Vincent CantinMy cat started screaming right at that time, making it very difficult to focus on the problem.
📝 memo: take the cat away for tomorrow’s puzzle.#2020-12-0506:02mchampineAgreed, the wording of part 2 took a while to interpret. I thought the description in part one was also a very long winded way to describe binary that could easily lead someone down a very long unproductive path. I suspect that was intentional and that you’re supposed to be rewarded (with time savings) for insights that lead to dramatically simpler solutions.
I’m pretty happy with my 6 line solution to part 1. Part 2 took another 2 lines but is slightly hacky. Looking forward to seeing other approaches.#2020-12-0506:18Vincent CantinI solved part2 before I had a correct expression to solve it, just by doing some data exploration … the solution appeared clearly in the middle of false positives.#2020-12-0506:42erwinrooijakkersGood morning. Probably can be done nicer using an index instead of a vector representation but it’s Saturday. I hope to see an example with index later today 🙂 https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day5.clj#2020-12-0506:53nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day05.clj spoiler 👇#2020-12-0506:53nbardiukseat number is just a binary with 0 and 1 replaced with L|F and R|B#2020-12-0506:58Vincent Cantinanother trick is how to parse it … there is a clojure function for that#2020-12-0507:04dpkpVery nice#2020-12-0507:07nbardiuk@U8MJBRSR5 cannot find anything suitable, I am very intrigued 😮#2020-12-0507:11Vincent Cantin@U076FM90B https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_5.clj#L20-L21#2020-12-0507:12nbardiukoh cool! learn something new with every puzzle 😆#2020-12-0507:17plexusI guess I'm the only one who actually bothered to use bit-shift/bit-or 🙂#2020-12-0507:18Vincent Cantinedn/read-string is a good parser#2020-12-0507:20Vincent Cantin@U07FP7QJ0 I like your approach for part2#2020-12-0507:21plexusthe (partition coll n 1)
trick has saved me more than once#2020-12-0510:21tschadyi prefer (Integer/parseInt s 2)
to read-string
tricks, but that might be personality.#2020-12-0510:32AleksMe too, but the better way to do that is to use Long/parseLong
. Ultimately, all the numbers in Clojure represented as Longs.#2020-12-0510:57Aleks@U076FM90B Just realized from your solution, that splitting at row and col and then some math are not needed at all.#2020-12-0510:58AleksI should carefully look at the input data.#2020-12-0512:20plexusYeah I thought I was pretty smart by spotting it was just binary, but now I feel silly for not realizing that row+col are just a single number, no need to split them up :)#2020-12-0512:25tschady* 8
was the clue. Why 8?#2020-12-0512:30AleksIt’s a power of 2. 2 2 2 = 8. Multiplying by 2 means the same thing you do with shift-left. For example
(= (bit-shift-left 1 3)
(* 1 8))
#2020-12-0512:32Aleksand then just bit-or
it’s binary addition, so you get the same result just by decoding a whole string.#2020-12-0513:07erwinrooijakkersThat’s it yes#2020-12-0513:07erwinrooijakkersMissed it 🙂#2020-12-0513:08erwinrooijakkersJonathan did same: https://www.youtube.com/watch?v=wa0VcQugEsI#2020-12-0513:27woonki.moonhow brilliant!#2020-12-0514:25erwinrooijakkersrow and col are just a single number?#2020-12-0514:26erwinrooijakkersbecause of adding?#2020-12-0514:26erwinrooijakkersah#2020-12-0514:26erwinrooijakkerswow#2020-12-0514:43erwinrooijakkersSo 🙂
For example “BFFFBBFRRR”
is in binary 1000110 111, so:
(+ (* 8 (Integer/parseInt "1000110" 2))
(Integer/parseInt "111" 2))
;; => 567
which is equal to:
(Integer/parseInt "1000110111" 2) ;; => 567
#2020-12-0519:08StuartI feel dumb. I created a range from 0 to 127 and recursively either drop / take half of it.#2020-12-0711:31erwinrooijakkersMe too 45 minutes of fighting with off-by-one errors and nullpointerexceptions 🙂#2020-12-0507:46plexusToday's video: https://youtu.be/eNMJH_GZld0#2020-12-0509:06nbardiukI didn't know about step argument in partition-all
. Literally yesterday had to implement the pairs
function manually#2020-12-0520:59andreaNice! @U07FP7QJ0 any info about your env setup?
Is that vim plus what?#2020-12-0605:31plexushttps://github.com/plexus/corgi#2020-12-0605:33plexusPlanning to get that to a shippable state during the christmas/new years holidays#2020-12-0509:47AleksI solved it literally how it says (spoiler) 😞#2020-12-0509:48Aleks(defn decode [lo hi s]
(if-let [c (first s)]
(case c
(\F \L) (recur lo (+ lo (quot (- hi lo) 2)) (next s))
(\B \R) (recur (+ lo (inc (quot (- hi lo) 2))) hi (next s)))
lo))
#2020-12-0510:43Aleksfull solution
https://github.com/zelark/AoC-2020/blob/3cc64ff25278f82d262c4c32c2eec4268c0997a5/src/zelark/aoc_2020/day_05.clj#2020-12-0510:44Aleksrefactored one
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_05.clj#2020-12-0511:09AleksAnd my final decode
(defn decode [code]
(-> (str/escape code {\F 0 \L 0 \B 1 \R 1})
(Long/parseLong 2)))
#2020-12-0512:04nbardiukCool! escape
another function I've learned today#2020-12-0512:21plexusOoh that's a good one! Sequestering it for my toolbox :) 🧰#2020-12-0514:22pezI did it even more literally. 😃 I figured while doing it that there must be another way, but the thing with gold stars is that they give me fever and make me indifferent to what happens to gnomes and kittens.#2020-12-0605:17Vincent CantinGood morning !#2020-12-0605:38fingertoeHello! Today’s problem was pretty straightforward.. I am tied with the amount of problems I finished last year.. Not close to burning out.. I wonder if it is going easy on us this year?#2020-12-0605:58Vincent CantinI am awaiting the difficult problems like a surfer awaiting its wave.#2020-12-0605:59AleksYou can pick one from the last year ^_^#2020-12-0606:03Vincent CantinI will keep them for January.#2020-12-0605:58mchampineAgree! #6 usually starts ramping way up.#2020-12-0605:59kenjwhy give us a difficult problem on the weekend when you can save it for a weekday…#2020-12-0606:00Vincent CantinDuring the first 1 min 30, I was staring at a blank page, waiting for the page to load.#2020-12-0606:13plexusAoC really starts the first time you add
(set! *unchecked-math* :warn-on-boxed)
(set! *warn-on-reflection* true)
to a namespace#2020-12-0606:23Vincent CantinI like @dos’s solution, which did not separate the input loading from the processing for the solution.
It might be faster to type in that way.#2020-12-0606:31jamesThis is the first year I'm (seriously) trying to do this. Does it usually get harder day by day?#2020-12-0606:34james(Today's puzzle was pretty easy, but if they're going to get difficult I might not have time to see it through.)#2020-12-0606:34markwProblems have been surprisingly simple so far this year#2020-12-0606:35markwLast year for me, was by far the most difficult of them all#2020-12-0606:36AleksThat’s probably because we’re going to vacation 😃#2020-12-0606:37markwthat or he’s lulling us into complacency just before dropping the hammer tomorrow#2020-12-0606:37markwoh you got work Monday morning? Hope you remember A* search#2020-12-0606:40plexusI skipped AoC last year because the year before I ended up spending sometimes multiple hours on a single solution. If it gets like that again I'm out, but a bit more challenging than today's would be nice too 🙂#2020-12-0606:41markwI’ve done them since 2015, finished most but not all of them.. Except last year i bailed very early#2020-12-0606:41plexusToday's video: https://www.youtube.com/watch?v=b0a5siw85N4&feature=youtu.be I also talk a bit about the different ways that people solved yesterday's puzzle#2020-12-0606:42plexusMany thanks to folks who dropped into the live chats or left comments!#2020-12-0607:22Vincent CantinLet me know if I leave too many comments during the streaming 😅
I have a hard time holding them while excited by the contest.#2020-12-0607:56plexusAll good, it's nice to see some activity :)#2020-12-0606:41markwthey definitely get difficult and I was spending hours on problems routinely, but i’m not a fast solver#2020-12-0606:42markwlast year by like day 14 you had implemented a VM for a made up language, and then implemented pong using that language#2020-12-0606:45jamesCool.#2020-12-0606:45jamesI'm not a fast solver either, and also I'm doing them in Clojure, which I don't really know, so I'm extra slow.#2020-12-0606:46markwi know the feeling… i’m trying to go back and do them in Go after I finish in Clojure, and it is … painful (i don’t know Go)#2020-12-0606:46markwlots of typing#2020-12-0610:34devnDay 6 Answers Thread - Post your answers here#2020-12-0610:34devn(ns day6
(:require [clojure.string :as str]
[clojure.set :as set]))
(def input "...")
(def groups (str/split input #"\n\n"))
;; Part I
(apply + (for [group groups] (count (distinct (str/replace group #"\n" "")))))
;; Part II
(apply + (for [group groups
:let [people (str/split-lines group)
answer-sets (map set people)]]
(count (apply set/intersection answer-sets))))
#2020-12-0610:53tschady(ns aoc.2020.d06
(:require [aoc.file-util :as file-util]
[clojure.set :refer [intersection]]
[clojure.string :as str]))
(def input (map str/split-lines (file-util/read-chunks "2020/d06.txt")))
(defn part-1 [input]
(reduce + (map (comp count distinct (partial apply str)) input)))
(defn part-2 [input]
(reduce + (map (comp count (partial apply intersection) (partial map set)) input)))
#2020-12-0610:53tschadyfirst pass, feels inelegant#2020-12-0610:59devni feel the same way, but 🤷#2020-12-0611:00devnim guessing there’s a frequencies
-based solution#2020-12-0611:31nbardiukAlso checkout pinned thread for day 6 https://clojurians.slack.com/archives/C0GLTDB2T/p1607104763255500?thread_ts=1607104763.255500&cid=C0GLTDB2T#2020-12-0612:54benoitI misread part1 and actually solve part2 first 🙂 https://github.com/benfle/advent-of-code-2020/blob/main/day6.clj#2020-12-0615:31djbluehttps://github.com/djblue/advent-of-code/blob/master/src/advent_of_code/core_2020.clj#L196#2020-12-0616:06st3fanhttps://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day6.clj#2020-12-0616:08st3fan@U1G869VNV nice ... (str/split input #"*\n\n*")
that did not occur to me, I do a (partition-by empty?)
🙂#2020-12-0620:16Narve SaetreNoob code coming up - but I am actually quite happy with this code, it reads nicely I think:
(defn count-group [group]
(->> group
(string/split-lines)
(map set)
(apply clojure.set/intersection)
(count)))
(->> (string/split (slurp "adv6.input.txt") #"\n\n")
(map count-group)
(reduce +))
#2020-12-0620:18Narve SaetreI love the -> and ->> macros, but sometimes they can't be used because the place to put the previous form is different ... any tips for that particular problem? Is there a -?> which "does the right thing depending on the form 😄#2020-12-0620:28Narve SaetreAnswering my self: I just searched and found as->, a very nice function. This allows me to write e.g.
(as-> "adv6.input.txt" v
(slurp v)
(string/split v #"\n\n")
(map count-group v)
(reduce + v))
#2020-12-0622:55tschady@USAGL3YUS YMMV, but I try not to use as->
, I find it has maintenance problems for me. I like to just pull out the different one as a let
, so there’s only 1 threading type. In this case, could do:
(let [groups (-> path slurp (str/split #"\n\n")]
(->> groups...))
#2020-12-0706:44Narve Saetreyeah, I c your point. I can also use minor (-> or (->> lines within the larger thread-block as well.
Just gotta pick the right tool for the job 🙂#2020-12-0616:06st3fanDay 7 Answers Thread - Post your answers here#2020-12-0706:25Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_7.clj#2020-12-0706:42Vincent CantinI need to improve my regex capture skills. Let me know if you have a fast way to do the parsing/capturing, I am interested to learn.#2020-12-0706:55Aleksnot ideal, but I came up with this for parsing
(defn parse-entry [entry]
(let [p (re-find #"\w+ \w+" entry)
cs (->> (re-seq #"(\d+) (\w+ \w+)" entry)
(reduce (fn [m [_ v k]] (assoc m k (Long/parseLong v))) {}))]
[p cs]))
(def bags (into {} (map parse-entry (str/split-lines input))))
#2020-12-0707:41Vincent CantinI just realized that the algorithm for part2 could be used for part1#2020-12-0707:56oxalorg (Mitesh)My naive solution: https://github.com/oxalorg/aoc/blob/main/src/puzzle7.clj
Using some kind of memo could speed up first pass, but this works! ^_^#2020-12-0708:03AleksMy solution
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_07.clj#2020-12-0708:18erwinrooijakkersMine: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day7.clj
I don’t know why exactly I had to call set on the tree-seq entries in part 1 nor why I had to do apply + 1 in part 2, but it works 🙂#2020-12-0708:18Vincent CantinI forgot about tree-seq … that’s a good idea.#2020-12-0708:28erwinrooijakkers🙂 i now see set is because you have to find amount of different colors and + 1 is because you also have to count the containing bag#2020-12-0708:30erwinrooijakkers(into (set found-bags) (mapcat #(find-outer-bags bags %) found-bags))
nice @U067R559Q#2020-12-0708:46AdamI used this one as an https://github.com/ocisly/advent2020/blob/a96bd7be5e961d737bf33bc552724542e9e65d02/day-7.clj#L19-L41 to learn core.logic
... 😬#2020-12-0709:05erwinrooijakkersWow nice, I tried to use core.logic last year for a somewhat similar problem (https://adventofcode.com/2019/day/14) but I did not manage#2020-12-0709:30Aleks@U2PGHFU5U thanks to your solution for part 2, I simplified mine. Now it’s pretty straightforward
(defn count-bags [bags [bag n]]
(* n (apply + 1 (map #(count-bags bags %) (get bags bag)))))
#2020-12-0709:32nbardiukdon't have good intuition for graphs, always struggle https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day07.clj#2020-12-0709:34Dos(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))))
#2020-12-0709:36Dos(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]))))
#2020-12-0709:39plexushttps://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle07.clj#2020-12-0712:33genmebloghttps://github.com/genmeblog/advent-of-code-2020/blob/master/src/advent_of_code_2020/day07.clj#2020-12-0713:45benoitNothing very exciting in my solution but I will post anyway 🙂
https://github.com/benfle/advent-of-code-2020/blob/main/day7.clj
It took me way too long to figure out I was off by one for part 2 because I was counting the top shiny gold bag :)#2020-12-0714:15tschadyusing loom:
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d07.clj#2020-12-0715:15jculpWhat am I missing with this regex? Works fine for groups of 1 or two but fails with 3 or more (the second group gets improperly matched)
(\w+ \w+) bags? contain ((\d+) (\w+ \w+).*? bags?)(, (\d+) (\w+ \w+) bags?)*\.
#2020-12-0715:19tschadythe *
doesn’t repeat the capture group like you think it does#2020-12-0715:26tschadyi’d consider re-seq
#2020-12-0715:45Aleksvisualization >_<
https://i.redd.it/gx6l9oavzp361.jpg#2020-12-0715:56Aleks> What am I missing with this regex?
@U0ESCTA1E if you repeat a group, this group will be overwritten by the next match.
For such cases you need to split a line, or just write 2 regex. Check my solution above for example.#2020-12-0716:59Ben Listheres mine, O'm definitely interested to see what others came up with today as I'm fairly new to clojure still
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/07.clj#2020-12-0720:02rjrayHere's mine: https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day07.clj
Writing the parsing took longer than I'd like, but I really got stuck in part 1 due to a small logic-error. Part 2 only took about 10 more minutes.#2020-12-0720:55Joehttps://redpenguin101.github.io/posts/2020_12_07_aoc2020_day7.html. So impressed at how concise some of the answers here are. That was a fun problem though!#2020-12-0723:09mchampineAgain, lots of effort spent on processing the raw input into a nice shape. I notice my part 2 recursive function has the same pattern as several others. Took me some grinding to get it working. Still not pretty, oh well.
;; with input processed as:
;; ["dull aqua" ([4 "dark fuchsia"] [1 "shiny purple"])]
(defn count-nestedbags [inp topbag]
(letfn [(rcount [bag]
(let [[_ bt] bag
contained (second (first (filter #(= bt (first %)) inp)))]
(apply + 1
(for [[bc bn :as thebag] contained]
(if (= bn "no other") bc
(* bc (rcount thebag)))))))]
(dec (rcount [1 topbag]))))
(count-nestedbags input-part2 "shiny gold")
#2020-12-0723:15pezThis was so hard for me. It took me a lot of time to realize my first regex approach would not work. Then I had struggles wrapping my head around the recursion I needed. Then I made all sorts of silly mistakes even though the structure was right… And the result aint pretty!
(comment ; step 1
(def input (util/fetch-input 7))
(->> (clojure.string/split-lines input)
(map #(clojure.string/split % #"[ ,]"))
(map #(->> %
(partition 2 5)
(map vec)
(map (partial apply str))))
((fn dig [look-for found rules]
(let [directs (reduce (fn [acc [bag & bags]]
(if (seq (clojure.set/intersection (set bags) look-for))
(conj acc bag)
acc))
#{}
rules)]
(if (seq directs)
(dig directs (conj found directs) rules)
found)))
#{"shinygold"} #{})
(apply clojure.set/union)
(count)))
(comment ; step 2
(def input (util/fetch-input 7))
(->> (clojure.string/split-lines input)
(map #(clojure.string/split (str "1 " %) #"[ ,]"))
(remove #((set %) "no"))
(map #(->> %
(partition 3 5)
(map (fn [[n c1 c2]]
[(Integer/parseInt n) (str c1 c2)]))))
((fn dig [look-for found rules]
(let [directs (reduce (fn [acc [[_n bag-color] & bags]]
(->> (for [color look-for
:when (= color bag-color)]
(map #(repeat (first %) %) bags))
(apply concat)
(apply concat)
(into acc)))
[]
rules)]
(if (seq directs)
(dig (map second directs) (into found directs) rules)
found)))
["shinygold"] [])
(count)))
#2020-12-0723:16pezwhen I have troubles naming things, I know I don’t know what I am doing, but I pressed on on sheer intuition. ¯\(ツ)/¯#2020-12-0819:40devn@U067R559Q is my hero. his solution in this thread blows me away.#2020-12-0819:49devnI didn’t finish Part II in this style yet, but I decided to try and do day7 in a rules engine (#clara). There’s a better way to write this, but this gets the right answer:
(defrecord ContainerBag [type contained-bags])
(defrecord IntermediateBag [parent-type type])
(defrecord GoldBag [parent-type])
(defrule produce-intermediate-bags
[ContainerBag
(= ?type type)
(= ?contained-bags contained-bags)]
=>
(when (seq ?contained-bags)
(insert-all!
(mapv (fn [[kind num]]
(if (= kind "shiny gold")
(map->GoldBag {:parent-type ?type})
(map->IntermediateBag {:parent-type ?type
:type kind})))
?contained-bags))))
(defrule indirect-gold-bags
[ContainerBag
(= ?type type)]
[IntermediateBag
(= ?type parent-type)
(= ?intermediate-type type)]
[GoldBag
(= ?intermediate-type parent-type)]
=>
(insert! (map->GoldBag {:parent-type ?type})))
(defquery gold-bags []
[?gold-bags <- (acc/distinct :parent-type) :from [GoldBag]])
(defn run-rules []
(-> (mk-session :cache false)
(insert-all (doall (for [[k vs] (parse input)]
(map->ContainerBag {:type k
:contained-bags vs}))))
(fire-rules)))
;; Part I
(-> (run-rules)
(query gold-bags)
first
:?gold-bags
count)
;; => 179
#2020-12-0819:52devnIt would be cool to dynamically generate defrules for each line#2020-12-0616:06st3fanDay 8 Answers Thread - Post your answers here#2020-12-0805:35Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_8.clj#2020-12-0806:06nbardiukhttps://github.com/nbardiuk/adventofcode/blob/7a65f3ea75e9fc33fa31dbcd4e75e2ab837090f1/2020/src/day08.clj#L35-L44#2020-12-0806:06oxalorg (Mitesh)Todays challenge was super fun!
https://github.com/oxalorg/aoc/blob/main/src/day8.clj#2020-12-0806:34Vincent CantinIt reminds me my old emulator https://github.com/green-coder/girlfriend-advance#2020-12-0807:14Aleks(defn run-code [code]
(let [history (atom #{})]
(loop [acc 0
ip 0]
(let [[op arg] (nth code ip [:hlt 0])]
(if (contains? @history ip)
{:inf-loop acc}
(do (swap! history conj ip)
(case op
:hlt {:halt acc}
:nop (recur acc (inc ip))
:acc (recur (+ acc arg) (inc ip))
:jmp (recur acc (+ ip arg)))))))))
#2020-12-0808:06AleksAnd my final solution:
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_08.clj
in the Part 2 firstly I used case
, but re-implement it with a hash-map
as @U07FP7QJ0 showed on the live stream.#2020-12-0808:11plexusMy version: https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle08.clj#2020-12-0808:27fingertoeI always feel filthy when I use atoms…. This one is pretty dirty, but I got it done: https://github.com/jreighley/aoc2020/blob/master/src/day8.clj#2020-12-0811:09erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day8.clj#2020-12-0812:06mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day08.cljc#L45-L54#2020-12-0812:07motformdefinitely a bit engineered, but I’m not getting caught off-guard by a part 2: intcode boogaloo
https://github.com/motform/advent-of-clojure/blob/master/src/advent-of-clojure/2020/eight.clj#2020-12-0812:35genmeblogPart 2 was nice. https://github.com/genmeblog/advent-of-code-2020/blob/master/src/advent_of_code_2020/day08.clj#L29-L36#2020-12-0812:36benoitLooks like most of us have similar approaches.
https://github.com/benfle/advent-of-code-2020/blob/main/day8.clj#2020-12-0815:23Lars NilssonDay 8 makes me appreciate immutable data structures and defmulti. I am fairly happy with my code for a change.
https://github.com/chamaeleon/aoc2020-clj/blob/master/src/aoc2020/day08.clj#2020-12-0815:45tschadyhttps://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d08.clj#2020-12-0816:00Bradhttps://github.com/bradlucas/advent-of-code-2020/blob/master/src/advent/day08.clj#2020-12-0818:49Joehttps://redpenguin101.github.io/posts/2020_12_08_aoc2020_day8.html - this one did give me some flashbacks to intcode 😨#2020-12-0819:30Ben ListI really liked the intcode ones last year so I hope there's some future days that build this one up
Anyways my solution for day 08
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/08.clj#2020-12-0821:28karolhttps://github.com/kfirmanty/advent-of-code-2020/blob/main/src/advent_of_code_2020/day8.clj#2020-12-0822:44pezI tried for so long do step 2 in a tree-ish way. Gave up. The brute force was with me though. Copying the program and modifying each one differently worked. I want my gold stars! Glad I learned about cond->
the other day.
(defn parse [input]
(->> (clojure.string/split-lines input)
(map #(clojure.string/split % #" "))
(mapv (fn [[op arg]] [op (Integer/parseInt arg)]))))
(defn run [program]
(let [length (count program)]
(reduce (fn [cpu _]
(let [{:keys [pc pcs]} cpu]
(if (< pc length)
(let [[op arg] (nth program pc)]
(if (pcs pc)
(reduced cpu)
(cond-> cpu
(= op "acc") (update :acc #(+ % arg))
(#{"acc" "nop"} op) (update :pc inc)
(= op "jmp") (update :pc #(+ % arg))
:always (update :pcs conj pc))))
(reduced cpu))))
{:acc 0
:pc 0
:length (count program)
:pcs #{}}
(range))))
(comment
(def input (util/fetch-input 8))
; step 1
(->> input
(parse)
(run)
:acc)
; step 2
(->> input
(parse)
(#(repeat (count %) %))
(keep-indexed (fn [i program]
(let [[op val] (program i)]
(assoc program i [(cond
(= "nop" op) "jmp"
(= "jmp" op) "nop"
:else op)
val]))))
(map run)
(filter #(= (:pc %) (:length %)))
(first)
:acc))
#2020-12-0906:30kenjI’m officially a day behind now and late to the party https://gist.github.com/KennyMonster/9b9db6daa056e41413112d0fb31a5e47#2020-12-0906:31kenjfeels like part 2 could be way nice even brute forcing it… but I dunno how#2020-12-0921:38pezA reason part 2 took me so long is that I was looking at it as a tree problem. So I was able to build a structure something like so (simplyfied):
[[nop jmp]
[acc]
[acc]
[jmp nop]
[acc]]
But then I failed building the programs from this. Which for the example above would be:
[[nop acc acc jmp acc]
[jmp acc acc jmp acc]
[nop acc acc nop acc]
[jmp acc acc nop acc]]
Does anyone have any pointers on how to go about it?#2020-12-1001:41Vincent Cantin@pez Here is what I would do to optimize this problem:
• Collect all the switch-indexes
, indexes of the nop and jmp where the original program go before an infinite loop is detected, because the solution is to flip one of those indexes.
• Build the reverse-jmp-graph
, where edges are from jmp-targets to jmp-sources.
• In this graph, collect all land-indexes
which are reachable from the end of the program.
• Find which change on instructions at switch-indexes
let the program go into instructions at land-indexes
.#2020-12-0619:08StuartI've learnt a few neat functions from looking at you guys solution so far this year 🙂#2020-12-0622:50tschadyIn case you haven’t seen it, I highly recommend being well versed in all these base functions, really helps to know what’s possible. https://clojure.org/api/cheatsheet#2020-12-0622:46st3fanI am doing 2015 in parallel 😕#2020-12-0706:43Vincent Cantinsplit keyboard? 😉#2020-12-1001:41Vincent Cantin@pez Here is what I would do to optimize this problem:
• Collect all the switch-indexes
, indexes of the nop and jmp where the original program go before an infinite loop is detected, because the solution is to flip one of those indexes.
• Build the reverse-jmp-graph
, where edges are from jmp-targets to jmp-sources.
• In this graph, collect all land-indexes
which are reachable from the end of the program.
• Find which change on instructions at switch-indexes
let the program go into instructions at land-indexes
.#2020-12-0706:18Vincent CantinGood morning 🙂#2020-12-0706:18Vincent Cantin“Oh oh oh” (to read with the voice of Santa Claus) … it seems that the channel is more quiet than usual 😉#2020-12-0706:57Aleksmight because it’s Monday 😁#2020-12-0706:33fingertoeThis one seems quite a bit harder… 😉#2020-12-0708:08plexusToday's was definitely harder than the last few days, but not too hard yet. I quite like them like this. A bit challenging but still solvable in under an hour.#2020-12-0708:18erwinrooijakkersUnder an hour you say? 😛#2020-12-0708:18erwinrooijakkersI’m lucky I still have time for breakfast#2020-12-0708:28Vincent CantinI am going to add Specter and Instaparse to my deps.edn#2020-12-0708:30Vincent CantinInstaparse has a good API for parsing and shaping the result data.#2020-12-0708:32AleksI’m going to stack with vanilla Clojure for this AoC#2020-12-0709:28StuartI just woke up, looked at it, it's not a 9am problem.#2020-12-0709:37plexusyeah I'm also generally sticking to vanilla clojure, unless I really end up re-implementing a common library#2020-12-0709:38plexustoday's video: https://youtu.be/uujzvDnEXp0#2020-12-0709:39plexusand solution: https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle07.clj
I also talk a bit more about yesterday's puzzle, and answer some questions people asked in the comments.#2020-12-0712:52Aleksmaybe I missed it, have you mentioned that using io/reader
without with-open
macro is not a good practice?#2020-12-0713:21plexusOh that's a good point, I'll mention it tomorrow#2020-12-0715:22erwinrooijakkerscurious to what’s wrong? :_#2020-12-0715:22erwinrooijakkershave to stay tuned I guess#2020-12-0715:22erwinrooijakkersfind out tomorrow in a new episode#2020-12-0715:33StuartI think its because if you call io/reader
without with-open
(or explicitly try / catch yourself), then you can be left with an open reader in the case of an exception? But I'm guessing here. If thereis an exception I think with-open
calls close on its binding#2020-12-0716:13tschadyDay 7 using graph library#2020-12-0716:13tschadyhttps://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d07.clj#2020-12-0716:17tschadyand viz for fun:#2020-12-0719:19kenjSomehow I managed a stack overflow using loop
/`recur` :man-shrugging:
(count (bag-children "shiny gold" sample-bags))
=> 32
(count (bag-children "shiny gold" bags))
Execution error (StackOverflowError) at (REPL:1).
#2020-12-0720:30kenjCan anyone help me figure out my stack overflow issue? I realize my code/approach is far from optimal… all the same it bugs me I can’t reason about why this is failing the way it is https://gist.github.com/KennyMonster/4e965505f0a8b592a91dd25b5306023f#2020-12-0721:06tschadyyou have a recursive call inside a recur
form, that’s atypical#2020-12-0721:14markwi don’t think he does.. he shadowed bag children in the loop binding#2020-12-0721:15tschadyoops, missed. I guess that’s a reason to avoid that.#2020-12-0721:18markw(defn bag-children [color bags]
(let [bags-lookup (into {} (map #(vector (:color %) %) bags))]
(loop [colors-to-walk [color]
bag-children []]
(if (seq colors-to-walk)
(let [contained-bags (mapcat contained-bag-colors-as-seq (:contain (bags-lookup (first colors-to-walk))))]
(recur (into (subvec colors-to-walk 1) contained-bags)
(into bag-children contained-bags)))
bag-children))))
#2020-12-0721:18markwyikes formatting#2020-12-0721:24markwNope#2020-12-0721:24markwI edited his gist since I can’t format in slack apparently#2020-12-0721:24markwit’s concat#2020-12-0721:27tschadycool, thanks for link#2020-12-0721:55kenjThanks for taking a look!#2020-12-0721:55kenjI had no idea about concat… I had just assumed it was lazy#2020-12-0721:56kenjor that even if it was eager, it would just utilize too much memory vs a stack overflow#2020-12-0805:12plexusit is lazy, which is why you're getting the stack overflow. consider this
(def x (reduce concat (map #(list %) (range 100000))))
(first x)
the def
will work fine, but as soon as you try to realize the first element it throws. At that point it tries to realize the outer concat
, which first needs to realize the concat
inside of it, and so forth until it bottoms out. Realizing a lazy-seq concumes a stack frame. It's really just a wrapper around an IFn
which implements the Seq interface.#2020-12-0805:12plexusI'll talk about this on the stream today, it's one of those surprising clojure gotchas.#2020-12-0720:31kenjI would think my part 2 solution would just take a ton of time/memory#2020-12-0805:34Vincent Cantingood morning#2020-12-0805:37Vincent CantinToday, I hoped there was a part 3.#2020-12-0819:27Ben ListIf its anything like last year there will be some future problems building off this one#2020-12-0806:08devnim still banging my head on yesterday’s. trying to do a clara.rules version. I figured out Part I, but Part II is getting me#2020-12-0806:09devn(defrecord ContainerBag [type contained-bags])
(defrecord IntermediateBag [parent-type type])
(defrecord GoldBag [parent-type])
(defrule produce-intermediate-bags
[ContainerBag
(= ?type type)
(= ?contained-bags contained-bags)
(seq contained-bags)]
=>
(when (seq ?contained-bags)
(insert-all!
(mapv (fn [[kind num]]
(if (= kind "shiny gold")
(map->GoldBag {:parent-type ?type})
(map->IntermediateBag {:parent-type ?type
:type kind})))
?contained-bags))))
(defrule indirect-gold-bags
[ContainerBag
(= ?type type)]
[IntermediateBag
(= ?type parent-type)
(= ?intermediate-type type)]
[GoldBag
(= ?intermediate-type parent-type)]
=>
(insert! (map->GoldBag {:parent-type ?type})))
(defquery gold-bags []
[?gold-bags <- (acc/distinct :parent-type) :from [GoldBag]])
(defquery intermediate-bags []
[?intermediate-bags <- IntermediateBag])
(defn run-rules []
(-> (mk-session :cache false)
(insert-all (doall (for [[k vs] (parse input)]
(map->ContainerBag {:type k
:contained-bags vs}))))
(fire-rules)))
;; Part I
(-> (run-rules)
(query gold-bags)
first
:?gold-bags
count)
;; => 179
#2020-12-0807:30mishaunfortunately, this is unreadable in slack thread even on 15" screen due to line wrapping :(#2020-12-0821:10devn@U051HUZLD will post as a gist, one sec#2020-12-0821:11devnalso, you can drag the sidebar and expand it#2020-12-0821:11devnhttps://gist.github.com/devn/b7b961b41e6f6f2e864a960a4fece130#2020-12-0806:45plexusToday's was a lot of fun!#2020-12-0807:01AleksHope they will continue this series as it was last year.#2020-12-0817:07StuartA few months ago I wrote an toy asm interpreter as one of my first learn clojure projects. Be nice if I can reuse bits of this for aoc.#2020-12-0808:23fingertoeBombed out on 7…. Caught up on 8.. I am guessing this is one worth building really good tests around since they will probably have us refactor it a bunch??#2020-12-0812:35StuartHavent looked at day 8 yet, is it int code computer all over again ? 😄#2020-12-0814:21fingertoeSmells like it.. ;-)#2020-12-0811:31StuartFor day 7, part 2. What does this mean "becomes topologically impractical"?#2020-12-0811:32StuartI solved part1 as a graph, then reverseed the graph and counted from shiny gold to all the unique nodes i can hit.
But I dont know what it means that i have to take into account topologically impractical#2020-12-0811:41nbardiukthe statement means to go as deep as data, even if in practice nobody would be able nest so many bags in each other
be sure to count all of the bags, even if the nesting becomes topologically impractical!
#2020-12-0812:21Stuartthank you, so it's like a joke rather than soemthing technical I have to consider?#2020-12-0812:22Stuartthat makes sense now.#2020-12-0812:34nbardiukYes, there are usually only several statements relevant and the rest is for Christmas atmosphere and laughs#2020-12-0812:02plexushttps://mobile.twitter.com/pauladozsa/status/1336061757933187072#2020-12-0818:03pezPart 2 of day 8. I hate it a bit. But now dinner and reading Stravaganza with my kids. Hopefully that will cleanse my thought patterns. #2020-12-0818:09AleksMay the Force be with you. Brute force.#2020-12-0823:02pezBruted it. I feel dirty now. #2020-12-0906:30kenjbruted it with code I’m not too proud of 🤕#2020-12-0911:32pezGold fever is bad for your soul. 😃#2020-12-0821:11andrea.crottiI probably wrote too much code#2020-12-0821:12karolHello everybody and welcome to day8 😄 I finished todays task rather fast but I am left wondering if there is more clever solution to second part than just generating all permutations and executing them so this will probably occupy my mind for a little bit. It still completed in less than 70 milliseconds so ¯\(ツ)/¯ but I felt a little like cheating by bruteing it 😄#2020-12-0821:12andrea.crottiI also went for the brute force#2020-12-0821:12andrea.crottican't really think of another way tbf#2020-12-0821:19karolso as I mentioned my gut feeling is that because jumps are not conditional you could write code that would analyze the source and identify the jumps that would 100% end in infinite loop#2020-12-0821:20andrea.crottiyeah maybe it's possible#2020-12-0821:21andrea.crottianother thing is that you probably don't need to re-run the whole simulation every time with the changed instructions set (which is what I did at least)#2020-12-0821:21andrea.crottiyou would only need to branch out every time there is a nop or a jmp#2020-12-0821:25karolgood idea, you could explore the "code space" like tree#2020-12-0821:30andrea.crottimoving my solution here
https://github.com/AndreaCrotti/advent2020/blob/master/src/problems.clj#L257#2020-12-0822:11genmeblogactually you don't need to generate all permutations upfront, you can generate lazy list of permutations and stop when you find first one which terminates properly.#2020-12-0822:19andrea.crottiwell I generated all the possible replacements https://github.com/AndreaCrotti/advent2020/blob/master/src/problems.clj#L294
which I guess would not be that expensive anyway#2020-12-0822:19andrea.crottiit's running the simulation that in theory is the expensive thing#2020-12-0822:20andrea.crottibut actually in my solution I'm calling terminates? on all the permutations tbf 😄 so yeah could definitively improve that#2020-12-0822:23benoitYou could represent the program as a directed graph and run an algorithm to find the minimal cycle-breaking set. But that doesn't seem easy after quick googling :)#2020-12-0822:29andrea.crottiWell with loom it would be doable#2020-12-0822:30andrea.crottiThe graph algorithm is done at least#2020-12-0821:15karol*spoiler alert click on thread only after finishing the task 🙂#2020-12-0821:15karolMy gut feeling is that there might be some possible way to do simple heuristics over the code and analyze the bits that will surely loop as the loops are not conditional so they are bound to be executed ever time.#2020-12-0821:16karolbut to be honest this will probably take much more code and in the end will execute slower than basic permutation generation ;d#2020-12-0821:22andrea.crottiyeah probably#2020-12-0907:35plexusI think you can get some reuse by keeping the program state up until the point where you hit the changed instruction, and reusing that. Still, not sure if it would really be worth it.#2020-12-0912:36karolthat is what Andrea suggested in other thread and I think it would definitely help in "feel good by not brute forcing it 100%" and I like the idea 😄#2020-12-0912:37karolbut I was thinking more in the vein that because the every jump is not conditional you could use that as an advantage#2020-12-0913:26andrea.crottihehe well the problem is that that there is a new problem every day#2020-12-0913:26andrea.crottican't really spend too much time on smart solutions if I want to keep up to date 😄#2020-12-0821:23karolsaw the pinned msg, moved my link there#2020-12-0821:30andrea.crottiah yes my bad I did the same#2020-12-0903:24Vincent CantinPolling for yesterday's solution:
PC people bmo vs. IP people bananadance#2020-12-0905:25djblueI'm going to rename my repo to advent-of-for 😆#2020-12-0905:57AleksDay 9 Answers Thread - Post your answers here#2020-12-0905:58AleksJust solved today’s puzzle, but it’s a bit dirty, so I’m going to refactor it before publishing ^_^#2020-12-0906:14rjrayGrrr. Got my first wrong submission this time, on part 1. Last year I reached day 12 before I made a wrong submission. Ah well. clojure.math.combinatorics
helps again...
https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day09.clj#2020-12-0906:15mchampineMine’s quick-n-dirty also, but whatever.. [edit] Cleaned up a bit.
(def input
(map #(BigInteger. %)
(str/split-lines (slurp "resources/day09.data"))))
;; part 1 (refactored for to set/when/not-any via nbardiuk)
(defn none-valid? [blk]
(let [ps (set (butlast blk))
n (last blk)]
(when (not-any? #(ps (- n %)) ps) n)))
@(def sol-p1 (some none-valid? (partition 26 1 input)))
;; => 400480901
;; part 2
(defn findn [n] (filter #(= sol-p1 (apply + %)) (partition n 1 input)))
(->> (ffirst (remove empty? (map findn (iterate inc 2))))
(#(+ (apply max %) (apply min %))))
;; => 67587168N
#2020-12-0906:33fingertoeUsing reductions + as a set has to be a terrible idea, but it worked.. https://github.com/jreighley/aoc2020/blob/master/src/day9.clj#2020-12-0907:07nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day09.clj today I've used partition
juxt
reductions
it was fun#2020-12-0907:38plexushttps://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle09.clj#2020-12-0907:43Vincent CantinMy solution, after a lot of clean up.
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_9.clj#L19-L48
I made a first-for macro.#2020-12-0908:01erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day9.clj#2020-12-0910:15Joehttps://github.com/RedPenguin101/aoc2020/blob/main/day9.clj#2020-12-0910:21pezNot cleaned up at all.
(defn parse [input]
(->> input
(re-seq #"\d+")
(map #(Integer/parseInt %))))
(comment
(def input (util/fetch-input 9))
; step 1
(->> input
(parse)
(partition 26 1)
(keep #(apply (fn [& nums]
(let [code (butlast nums)
checksum (last nums)
sums (for [a (butlast code)
b (rest code)
:let [sum (+ a b)]]
sum)]
(when-not ((set sums) checksum)
checksum))) %))
(first))
; step 2
(def weakness 127)
(def weakness 36845998)
(->> input
(parse)
((fn dig [weakness data]
(loop [remaining data]
(let [nums (reduce (fn [acc num]
(let [new-acc (conj acc num)
sum (apply + new-acc)]
(cond
(= sum weakness) (reduced new-acc)
(> sum weakness) (reduced nil)
:else new-acc)))
[]
remaining)]
(if nums
nums
(recur (rest remaining)))))) weakness)
((fn [nums] [(apply min nums) (apply max nums)]))
(apply +)))
#2020-12-0911:01genmebloghttps://github.com/genmeblog/advent-of-code-2020/blob/master/src/advent_of_code_2020/day09.clj#2020-12-0911:46benoitNothing very exciting today either ... https://github.com/benfle/advent-of-code-2020/blob/main/day9.clj#2020-12-0912:03motformIt seems like brute-force was the name of the game. Missed an opportunity to juxt though!
https://github.com/motform/advent-of-clojure/blob/master/src/advent-of-clojure/2020/nine.clj#2020-12-0912:08st3fanhttps://github.com/st3fan/aoc/blob/master/2020/advent-of-code/src/advent_of_code/day9.clj#2020-12-0912:08st3fanYup brute force#2020-12-0912:10st3fanOh! recur
without a loop
is allowed?#2020-12-0912:13Aleks@U4T7GE7PE Yes it works with functions as well.#2020-12-0912:14motformIt goes to the latest fn-def, which can be #(), letfn, loop, defn
or fn
(afaik those are the main ones). I always thought of loop
as a nicer proxy for a nested recur-fn a scheme#2020-12-0912:54Björn EbbinghausHow long does your solutions take?
I need 1,3s and it really bugs me, that I don’t know why it takes so long..#2020-12-0912:55Vincent CantinWhat is the algorithmic complexity of your code?
Mine is O(n^2) and it is faster than your. O(n) might be possible also.#2020-12-0912:59JoeMine is 150ms for part 1, 35ms for part 2. Only using time
though, so might be inaccurate. That's also with the input already loaded into memory.#2020-12-0913:35nbardiuk#2020-12-0913:37Vincent CantinFor part2, if all the numbers are positive, it might be possible to solve it by doing one pass over the collection, adding in front when the sum is less, and removing from behind when the sum is greater.#2020-12-0914:37pezI think that means that all numbers in my input are positive. 😃#2020-12-0914:59tschadymeh: https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d09.clj#2020-12-0915:33Vincent CantinYes, that's what I meant.#2020-12-0915:35Vincent CantinThe sum could be a rolling sum ... you add in front and substract in the back.#2020-12-0916:02tschadyyes, i know i’m resumming too much, that’s for a phantom refactor that may never happen 🙂#2020-12-0916:11Bradhttps://github.com/bradlucas/advent-of-code-2020/blob/master/src/advent/day09.clj#2020-12-0916:29AleksHere I am
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_09.clj#2020-12-0916:58djbluehttps://github.com/djblue/advent-of-code/blob/master/src/advent_of_code/core_2020.clj#L318#2020-12-0917:28Ben Listnot my best work but gets the job done
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/09.clj#2020-12-0917:33Aleks@U076FM90B, you solution is awesome! But I noticed that has-sum
should be called has-not-sum
🙂#2020-12-0917:46nbardiukThat is right! I have renamed it couple times and never noticed the missing negation#2020-12-0918:20AleksAlso (apply max-key count)
could be just first
🤐#2020-12-0918:25tschady@vincent.cantin refactored to be a rolling sum:
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d09.clj#2020-12-0918:44R.A. PorterDefinitely needs some cleanup: https://github.com/coyotesqrl/advent2020/blob/master/src/coyotesqrl/advent2020.clj#L464
but I was not completely disgusted by what I wrote.#2020-12-0919:38markwNot the most efficient, but I think it’s reasonably clean:
https://github.com/Solaxun/aoc2020_clj/blob/main/src/aoc2020_clj/day9.clj#2020-12-1002:35Vincent Cantin@U1Z392WMQ This is my new optimized version, super fast.
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_9.clj#L52-L65#2020-12-1007:25pwojnowskiFor the record: https://github.com/pwojnowski/advent-of-code/blob/master/src/aoc/aoc2020.clj#L258#2020-12-0907:36plexusRecording for day 9 https://youtu.be/7gp4MZdCDQc used a nested loop/recur for part 2, I may try to clean that up a bit later today 🙂#2020-12-0907:44Vincent CantinAfter some heavy cleanup, I made a version which is using only the for loop.
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_9.clj#L19-L48
Edit: not totally, there is still a reduce inside.#2020-12-0908:41Vincent CantinI decided to write some functions with the purpose of saving time of some commonly used operations.
Here is my new group-by
. Feedback welcome:
(defn group-by
"Same as clojure.core/group-by, but with some handy new arities which apply
custom map & reduce operations to the elements grouped together under the same key."
([kf coll]
(group-by kf identity conj [] coll))
([kf vf coll]
(group-by kf vf conj [] coll))
([kf vf rf coll]
(group-by kf vf rf (rf) coll))
([kf vf rf init coll]
(persistent!
(reduce
(fn [ret x]
(let [k (kf x)
v (vf x)]
(assoc! ret k (rf (get ret k init) v))))
(transient {}) coll))))
#2020-12-0908:42Vincent CantinTesting expressions:
(group-by first [[:a 1] [:a 2] [:b 3] [:a 4] [:b 5]])
(group-by first second [[:a 1] [:a 2] [:b 3] [:a 4] [:b 5]])
(group-by first second + [[:a 1] [:a 2] [:b 3] [:a 4] [:b 5]])
(group-by first second + 10 [[:a 1] [:a 2] [:b 3] [:a 4] [:b 5]])
=> {:a [[:a 1] [:a 2] [:a 4]], :b [[:b 3] [:b 5]]}
=> {:a [1 2 4], :b [3 5]}
=> {:a 7, :b 8}
=> {:a 17, :b 18}
#2020-12-0910:17erwinrooijakkersah nice#2020-12-0910:22erwinrooijakkersperhaps nice addition to medley: https://github.com/weavejester/medley/blob/master/src/medley/core.cljc#2020-12-0909:09Vincent CantinI made this group-by
because usually the part which is in the val after the group-by is often the target of further computation.#2020-12-0909:11Vincent CantinAnother problem I want to address is comp
on functions. The way I think about the operations to apply is the reverse of what I need to write.
(defn comp-> [& args]
(apply comp (reverse args)))
#_ ((comp str inc) 17) ; => "18"
#_ ((comp-> inc str) 17) ; => "18"
Feedback welcome.#2020-12-0909:29imre@vincent.cantin I recommend taking a look at https://github.com/cgrand/xforms - there are lots of goodies in there that help build stuff like this but it's all transducer-based#2020-12-0909:31imreI used it in a lot of places in my solutions so far https://github.com/imrekoszo/advent-2020/#2020-12-0909:32Vincent CantinIt is a good library.
With this tree-seq transducer, you may have used it at one more place too.
https://github.com/cgrand/xforms/issues/20#2020-12-0909:34imreNice one, that 🙂#2020-12-0909:34Vincent Cantinon the shiny bag day#2020-12-0909:35imreI don't think I got that far just yet#2020-12-0909:35imreI'm 3 days behind rn#2020-12-0909:36Vincent CantinSide note: The functions I past in the channel are targeted at saving typing time. They are not necessarily the right choice for quality code.#2020-12-0909:38Vincent CantinUntil now, performance was not the issue in all the puzzles, so lazy collections are still in the game.#2020-12-0909:38imreI prefer using transducers even then. Easy to go back to lazyland from there#2020-12-0909:54Vincent CantinOne last function: the equivalent of partition, but with vector input and a sequence of subvec as output.
(defn partitionv
([n vec-coll]
(partitionv n n vec-coll))
([n step vec-coll]
(for [i (range n (inc (count vec-coll)) step)]
(subvec vec-coll (- i n) i))))
#_ (partitionv 3 (vec (range 10)))
#_ (partitionv 3 1 (vec (range 10)))
The idea is to keep collections which are indexable (i.e. vectors) while having the benefits of partition
#2020-12-0910:00Vincent Cantin@plexus you may like that one#2020-12-0910:01plexusoh yeah that's nice#2020-12-0910:29erwinrooijakkersmaybe more logical to return a vec of subvecs?#2020-12-0911:19Vincent Cantinthe lazyness on the outter sequence could be useful, I want to keep it.#2020-12-0911:26Vincent CantinI will also make a variation partition-indexes
which returns the indexes of the possible sub-vectors.#2020-12-0912:29nbardiukI've build similar function, which returns sequence of vectors, but does not require input to be a vector https://gist.github.com/nbardiuk/ec16046263734c795a82d33dcf83fb81#file-moving-avarage-clj-L4-L8 but in my case it would be probably simpler to just use partition
(I didn't know it has step argument)#2020-12-0918:28AleksDay 10 Answers Thread - Post your answers here#2020-12-1006:24Vincent CantinMy solutions for today
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_10.clj#2020-12-1006:27AleksAnd mine, definitely wanna clean up it
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_10.clj#2020-12-1006:38mchampineUpdated w/ part 2.
Note: I found an interesting pattern. Looking a the diffs pattern (first and last value with moving window of 3) you can simply count the number of runs of 2's. Runs of 3 = 7, runs of 2 = 4, runs of 1 = 2, then take the product.
;; part 1
(let [jolts (sort (concat input [0 (+ 3 (apply max input))]))
diffs (map (fn [[a b]] (- b a)) (partition 2 1 jolts))]
(apply * (vals (select-keys (frequencies diffs) [1 3]))))
;; => 1690
;; part 2
(defn adapter-combos [inp]
(->> (sort (concat inp [0 (+ 3 (apply max inp))]))
(partition 3 1)
(map (fn [[a _ c]] (- c a)))
(partition-by identity)
(keep {'(2 2 2) 7 '(2 2) 4 '(2) 2})
(reduce *)))
(adapter-combos input)
;; => 5289227976704
#2020-12-1007:18AleksRefactored version
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_10.clj#2020-12-1007:53pezNo real idea about how to think about step 2. Step1 seemed like this to me:
(->> input
(parse)
(sort)
(cons 0)
(#(concat % [(+ 3 (last %))]))
(partition 2 1)
(map #(- (second %) (first %)))
(frequencies)
(vals)
(apply *))
#2020-12-1008:02Dos{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 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))]))
(defn next-ways [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 (next-ways ways))))
#2020-12-1009:03nbardiukhttps://github.com/nbardiuk/adventofcode/blob/923232e713a34bdcbbbab7d35ee2f933209bf284/2020/src/day10.clj#2020-12-1009:08pezTrying to not look at your solutions just yet, but seems best to ask this here. Part 2 seems like a math problem to me. When there is a string of distances 1, I can remove some subsets of them and still have a “bridge”. Does that make sense to you people?#2020-12-1009:31oxalorg (Mitesh)My day 10 solution, but I ported my python solution as-is. I am not satisfied with this though and maybe there's a more "clojurey" / "functional" way to do this. I'll go through some of the above solution to check alterntative methods: https://github.com/oxalorg/aoc/blob/main/src/day10.clj#2020-12-1009:33oxalorg (Mitesh)@pez I can probably give you a small hint: It's not a math problem, it's a memory problem. Can you find out a way to mix and match such that you reduce unnecessary computations.#2020-12-1009:39erwinrooijakkersI calculated in three parts using brute force https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day10.clj
Cut the coll in three parts (finding snips where I could cut the adapters, if there’s a gap of 2 in between you don’t miss any) then multiplying the separate answers
Not proud of this using an atom
to count. But it works. Will try to improve if I have more time. Also wanting to fully automate.#2020-12-1009:45erwinrooijakkersI read btw that the creator of AoC is not a fan of checking in your inputs, he prefers not making them public#2020-12-1009:49erwinrooijakkers@U013MQC5YKD a you can also brute force using memoize?#2020-12-1009:49erwinrooijakkersCutting of parts you already did?#2020-12-1009:52pezPart of it can be seen as a math problem, it seems, @U013MQC5YKD. Here’s a “solution”:
(->> input
(parse)
(sort)
(cons 0)
(#(concat % [(+ 3 (last %))]))
(partition 2 1)
(map #(- (second %) (first %)))
(partition-by identity)
(keep #(seq (filter #{1} %)))
(map count)
(map {1 1
2 2
3 4
4 7})
(apply *))
#2020-12-1009:57pezUsing the longer example in the calendar, after the keep
there I have this: ((1 1 1 1) (1 1 1 1) (1 1 1) (1 1) (1 1 1 1) (1) (1 1 1 1))
which is the strings of 1 distances I was thinking about. So after mapping count over them I have (4 4 3 2 4 1 4)
. I then map those over the “magic” function that tells me how many combinations each string contributes with. Then multiplying all those.#2020-12-1009:58pezI have yet to figure out the “magic” function, but don’t expect a blocker there.#2020-12-1009:59oxalorg (Mitesh)@U2PGHFU5U That is a very nice solution! If you can try and generalize your part cutting solution in a way where you don't have to cut, rather just progressively find solutions to larger subsets then you will have discovered Dynamic programming!#2020-12-1010:00oxalorg (Mitesh)@pez That is an interesting take on this, I'll have to dig deeper to understand it haha#2020-12-1010:01erwinrooijakkershaha funny you say that talked about dynamic programming last night with a friend and realized i did not know what it was and that i would find out more today#2020-12-1010:02pezI will have to check that out too! 😃#2020-12-1010:02erwinrooijakkersso you start in the small, then go up to a larger problem, adding the sub amounts?#2020-12-1010:02erwinrooijakkerslike the opposite of memoization#2020-12-1010:03erwinrooijakkerswith memoization you start in the large and memoize subparts, with dynamic programming you start in the small and go to the large, i have to find out more after work 🙂#2020-12-1010:23erwinrooijakkers@U013MQC5YKD the problem with the cutting is that for just bare multiplication the subparts needs to be separated on the three jumps.
e.g.,
From the example:
(count-paths [1 4 5 6 7 10 11 12 15 16 19])
;; => 8
and when cutting on a three jump (from 7 to 10) you can just multiply solutions to both parts:
(* (count-paths [1 4 5 6 7])
(count-paths [10 11 12 15 16 19]))
;; => 8
But when cutting between 10 and 11, you miss a few solutions:
(* (count-paths [1 4 5 6 7 10])
(count-paths [11 12 15 16 19]))
;; => 4
So not sure how I can prevent this cutting part or maybe if there’s some logic to the type of cutting and the factor of paths you miss#2020-12-1010:27oxalorg (Mitesh)Don't think about cutting the input randomly. Put a bit more stress on the problem and figure out a pattern in which dividing the problem into smaller parts gives you something concrete (the ability to avoid future computations)#2020-12-1010:29nbardiukI've cut input by difference of 3, then counted connections inside each group. Since 3 is the longest possible link, only one item from group can reach next group#2020-12-1012:11pezSo the “magic” function/map in my step 2 “solution” above was really just the needed 2-combinations + 1. So then this is my real solution:
(defn ! [n]
(reduce *' (range 1 (inc n))))
(defn combinations [n r]
(if (= 1 n)
0
(let [n! (! n)
r! (! r)
r-n! (! (- n r))]
(/ n! (* r! r-n!)))))
(->> parsed-input
(sort)
(cons 0)
(#(concat % [(+ 3 (last %))]))
(partition 2 1)
(map #(- (second %) (first %)))
(partition-by identity)
(keep #(seq (filter #{1} %)))
(map count)
(map #(inc (combinations % 2)))
(apply *))
#2020-12-1012:14pezGiven parsed input it runs in just above 1ms on my machine fed my input data. I guess that decent. Anyone see any speed gains I could collect? @U051HUZLD, maybe?#2020-12-1012:55oxalorg (Mitesh)This is beautiful @pez ! So basically you're finding out how many ways can we arrange consecutive adapters until we have a jump which is a 3 volt difference. Since a 3 volt difference can't be reached by any adapter in the previous consecutive list (except for the last one) so that won't affect the number of arrangements.#2020-12-1012:56oxalorg (Mitesh)You definitely did it the math way 😄#2020-12-1013:00pezThanks! Yes, like that. When solving step 1, I had stuff like this before I applied frequencies
:
(1 1 1 1 3 1 1 1 1 3 3 1 1 1 3 1 1 3 3 1 1 1 1 3 1 3 3 1 1 1 1 3)
And those strings of 1s looked like bridges to me.#2020-12-1013:01pezBut then I needed to ask my daughter for help with figuring out the pattern. Then wikipedia helped me with the math. 😃#2020-12-1013:02oxalorg (Mitesh)That was great thinking, not going to lie I don't think I would've noticed this! 🙈#2020-12-1013:04pezI think it was because I think so literally about the problem as it is stated. It made me miss those binary numbers when finding a seat on that plane, but spot this bridging thing instead. Haha.#2020-12-1013:05oxalorg (Mitesh)One catch in this solution would be if the requirement of using all adapters were loosened and the AOC input had something like this: [2 4 7]
So there would be two ways to arrange this: [2 4 7]
and [2 7]
Maybe something can be done with the bridges to divide them even further? Or just count the number of 2
and multiply the result by n^2
as every 2 would lead to two possible solutions#2020-12-1013:05nbardiukoh, I didn't notice that there are only differences in 1 and 3, I assumed that there should be 2s somewhere 😮#2020-12-1013:06oxalorg (Mitesh)@U076FM90B Yes I didn't realise that either, just went back and checked they've said "need to use all adapters" and they've conveniently left input which can lead to a difference of 2#2020-12-1013:08oxalorg (Mitesh)Awesome solution by @pez in case people missed this thread!#2020-12-1013:32benoitA solution to Day 10. https://github.com/benfle/advent-of-code-2020/blob/main/day10.clj#2020-12-1013:36benoitpath-count(n) = path-count(n+1) + path-count(n+2) + path-count(n+3)
#2020-12-1014:04AleksBrilliantly!#2020-12-1014:42misha@pez I don't think 1ms needs any speeding up. I have a similar solution wrt splitting by "magic" [3 3] pattern, but my "combinations" function is a dirty loop, I have left over from the morning#2020-12-1014:47misha(def minus (fnil - ##Inf ##Inf))
(defn split [xs]
(let [threes (fn [[a b c]] (= 3 (minus a b) (minus b c)))]
(->> xs
(partition-all 3 1)
(partition-by threes)
(map (partial map first))
(partition-all 2)
(map (partial apply concat)))))
(->> xs split (map p1) (reduce *))
#2020-12-1014:52mishaso test input gets split like this: https://gist.github.com/akovantsev/782045b0f49a5d3875c0c42c11776ed4#2020-12-1015:00pezIt’s wonderful!#2020-12-1015:33Ben Liststruggled with part 2 for a little bit, but memoization saved the day. Pretty happy with my end result
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/10.clj#2020-12-1016:30genmeblogFinally! 2-3ms for part 2 with input sorted in descending order. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day10.clj#L17-L31#2020-12-1017:55rjrayThis took me over 2 1/2 hours. I basically had part 2 correct, but I had the memoize
at the wrong lexical level and I wasn’t getting any benefit from it. Looking at @vincent.cantin’s solution showed me what I had wrong. At least I can take some solace in knowing I was about 96% there…
https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day10bis.clj#2020-12-1018:01tschadyNot as clean as the awesome O(n) above, but this was my first idea - to isolate the areas of multiple paths (runs of 1), compute the ways through them (kind of like a change making algo), then multiply those together.
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d10.clj#2020-12-1018:14mchampineI found an interesting pattern for part 2. I haven’t waded through all the other solutions to see if someone discovered this, but:
Looking at the diffs pattern (first and last value with moving window of 3) you can simply count the number of runs of 2's. Runs of 3 = 7, runs of 2 = 4, runs of 1 = 2, then take the product.
[edit]. Just discovered @UGFL22X0Q posted a question on the main thread earlier that references the prime factorization. So, yeah, some others were onto this idea also.. Maybe there are more.
Note: runs in “Elapsed time: 0.5174 msecs”
;; part 2
(defn adapter-combos [inp]
(->> (sort (concat inp [0 (+ 3 (apply max inp))]))
(partition 3 1)
(map (fn [[a _ c]] (- c a)))
(partition-by identity)
(keep {'(2 2 2) 7 '(2 2) 4 '(2) 2})
(reduce *)))
(adapter-combos input)
;; => 5289227976704
#2020-12-1018:28tschady@U06B54Y95 i wrote a fn to calculate those magic 7, 4, 2
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d10.clj#L23-L29#2020-12-1018:32JoeDang, tough part 2, spent a good half-hour with pen and paper before I touched the keyboard. https://github.com/RedPenguin101/aoc2020/blob/main/day10.clj- but it is fast, < 2ms.#2020-12-1019:01R.A. PorterI’m not going to say how long part 2 took me. And it’s not like it’s the prettiest of solutions…would be really short if I’d found a graphing library to count all paths in a DAG for me.
https://github.com/coyotesqrl/advent2020/blob/master/src/coyotesqrl/advent2020.clj#L550#2020-12-1019:37Joehttps://redpenguin101.github.io/posts/2020_12_10_aoc2020_day10.html. Looking forward to going through other peoples solutions for this one!#2020-12-1020:39pezI got very different results from time
so tried criterium quick-bench
which reports:
Evaluation count : 4350 in 6 samples of 725 calls.
Execution time mean : 137,221776 µs
Execution time std-deviation : 3,615336 µs
Execution time lower quantile : 134,692566 µs ( 2,5%)
Execution time upper quantile : 143,297341 µs (97,5%)
Overhead used : 6,391737 ns
Found 1 outliers in 6 samples (16,6667 %)
low-severe 1 (16,6667 %)
Variance from outliers : 13,8889 % Variance is moderately inflated by outliers
#2020-12-1020:46pezI get 18 µs for the smallest sample input and 43 µs for the larger.#2020-12-1023:10curlyfry(ns day10.core
(:require [clojure.string :as str]))
(def input (slurp "src/day10/input.txt"))
(defn add-device [coll]
(cons (+ 3 (apply max coll)) coll))
(def adapters (->> input
(str/split-lines)
(map #(Long. %))
(add-device)
(cons 0)
(sort)))
;; Part 1
(defn part1 []
(let [freqs (->> adapters
(partition 2 1)
(map (fn [[x y]] (- y x)))
(frequencies))]
(* (get freqs 1) (get freqs 3))))
;; Part 2
(defn part2 []
(let [graph (->> adapters
(partition-all 4 1)
(map (fn [[x & xs]] [x (vec (remove #(< 3 (- % x)) xs))]))
(into {}))
vs (reverse adapters)
goal (first vs)]
(loop [[v & vs] (rest vs)
v->count {goal 1}]
(let [n (apply + (map v->count (get graph v)))]
(if (seq vs)
(recur vs (assoc v->count v n))
n)))))
(time (part2))
"Elapsed time: 0.496946 msecs"
For part 2, I made the numbers into a DAG (where the neighbours of a number are the numbers with a diff of 3 or smaller). Did a little bit of googling for efficient graph algorithms and found out that a property of a topologically sorted graph (which is what you get when you sort the input numbers) is that you can find the number of paths really efficiently using dynamic programming.
Basically I keep a map (`v->count`) of the number of paths from which you can reach the goal from the given vertex. The number of paths to reach the goal from the goal is 1. Then I go to the next vertex in the topological sorting and look at its neighbours (only the goal in this case), and store the number of paths in the map. I then keep doing this until I reach the start. Since we're going backwards, the map will already contain the number of paths for all the neighbours we're checking, and the last neighbour sum (the neighbours of the start vertex) is the answer!#2020-12-1102:22Stuartday 10 part 2, dirty solution
(as-> (slurp "puzzle-inputs/2020/day10") o
(str/split-lines o)
(map #(Integer/parseInt %) o)
(sort o)
(concat [0] o)
(map - (rest o) o)
(partition-by identity o)
(filter #(some #{1} %) o)
(map #(case (count %) 1 1 2 2 3 4 4 7) o)
(reduce * 1 o))
#2020-12-1104:52markwLate to the party - didn’t find the math trick, went with memoization:
(defn adapter-fits? [current-adapter other-adapter]
(< current-adapter other-adapter (+ 4 current-adapter)))
(defn possible-arrangements [root adapters]
(if-let [choices (seq (filter #(adapter-fits? root %) adapters))]
(reduce + (map #(possible-arrangements % adapters) choices))
1))
(def possible-arrangements (memoize possible-arrangements))
#2020-12-0920:12andrea.crottiwhat's the best way to do a cartesian product but without the order?#2020-12-0920:28markwwhat do you mean by without the order?#2020-12-0920:44misha(for [x (range 3) y (range 3)] [x y])
=> ([0 0] [0 1] [0 2] [1 0] [1 1] [1 2] [2 0] [2 1] [2 2])
#2020-12-0920:44mishaor https://github.com/clojure/math.combinatorics/blob/master/src/main/clojure/clojure/math/combinatorics.cljc#L232-L249#2020-12-0921:05andrea.crottiyeah I mean having [0 1] but not [1 0] for example#2020-12-0921:06andrea.crottiso imagining a square, taking the diagonal and the lower or upper half#2020-12-0921:07tschadycombination instead of permutation?#2020-12-0921:08imreha. Is this for day 1?#2020-12-0921:11imreCause that did bug me with day 1 where you kinda need elements taken for the combinations of indices. Not being able to find an existing implementation, I wrote a transducer for it but its performance is shite when compared to the for-based approach: https://github.com/imrekoszo/advent-2020/blob/master/src/imrekoszo/advent2020/day1_alternatives.clj#L102#2020-12-0921:15Lars NilssonI used (for [i (range size) j (range i size)] ...)
to get a triangle of indices (where size if the count of the collection)#2020-12-0921:15markw@andrea.crotti There is more than one way to do it, but as mentioned above that’s combinations vs permutations. Another way is in the for macro to make sure that one index is > than another, e.g. 1(for [i xs j xs :when (> j i))1#2020-12-0921:16markwbasically you want your inner loop to always start at 1 + the outer loop var#2020-12-0921:16raicotopas @markw mentions:
(for [x (range 5)
y (range 5)
:when (< x y)]
[x y])
;; => ([0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4] [3 4])
#2020-12-0921:16markwYep - I think @plexus mentioned this in the most recent video#2020-12-0921:18raicotopThat's where I saw it too I guess. Came in handy for day 9.#2020-12-0921:20mishalacks diagonal: [0 0] – [4 4]#2020-12-0921:21markwif you need diagonals you can just add a condition to the :when
#2020-12-0921:22markw:when (or ( = x y) (< x y))
#2020-12-0921:22Lars NilssonOr change <
to <=
, I would imagine...#2020-12-0921:22markwoh yeah#2020-12-0921:22misha<=
? kappa#2020-12-0921:25Lars NilssonUsing the when clause will make the for comprehension iterate over all 5*5 indices though (perhaps a small cost compared to the work overall...)#2020-12-0921:26markwif you want efficient generation i would use combinatorics and tack on the diagonals explicitly#2020-12-0921:26Lars NilssonIt just won't generate an entry for the failing conditions.#2020-12-0921:27andrea.crotticool nice#2020-12-0921:27Lars NilssonAs I mentioned above, I did it using the two argument version of range to get the triangular shape of indices.#2020-12-0921:29markwMissed the fact that you started the second loop at i
rather than i+1
which would have made it effectively the same as combinations#2020-12-0921:32Lars NilssonIn my actual for sequence I do have :let
and :when
for other purposes, just not the range/index checking.#2020-12-0921:33Lars NilssonI feel somewhat stupid about my day 1, part 2 implementation where I just added another index instead of doing something else.#2020-12-0921:34misha(time (do (doall (for [x (range 1000) y (range 1000) :when (<= x y)] [x y])) nil))
"Elapsed time: 40.609524 msecs"
=> nil
(time (do (doall (for [x (range 1000) y (range x 1000)] [x y])) nil))
"Elapsed time: 27.957203 msecs"
#2020-12-0921:34markwoh yeah i brute forced that one O^N(3)#2020-12-0921:34markwi’m not going to be clever on day 1 😛#2020-12-0921:35mishaDepends on what your goals are for this puzzle thing. And there are a bunch of conflicting ones there.#2020-12-0921:36Lars Nilsson(time (do (doall (for [x (range 1000) y (range 1000) :when (<= x y)] [x y])) nil))
"Elapsed time: 65.1356 msecs"
(time (do (doall (for [x (range 1000) y (range x 1000)] [x y])) nil))
"Elapsed time: 53.8159 msecs"
#2020-12-0921:37Lars NilssonNever mind my duplicate experiment. I misread yours completely and thought it did not include the x offset for y... Time to fetch my glasses.#2020-12-0921:38andrea.crottiI'm using loom for problem 7 https://github.com/aysylu/loom
and it worked out nicely for the first part of the problem#2020-12-0921:38andrea.crottiI also added the number of bags contained as the weight of each edge, so I thought it would be easy to do part b of the exercise#2020-12-0921:39andrea.crottibut I can't find anything useful to do that#2020-12-0921:39misha> it worked out nicely for the first part of the problem
famous last words™#2020-12-0921:40Lars NilssonThanks for the heads-up on loom.. I might need to look at that for some non-aoc stuff.#2020-12-0921:40andrea.crottiin theory I just want to be able to sum all the paths that I generate with a DFS search for example (multiplying the weights)#2020-12-0921:40mishasomeone shared loom solution here#2020-12-0921:41andrea.crottiit's pretty much just
(->> "shiny gold"
(la/bf-traverse (get-graph))
count
;; removing the node itself
dec)
once you have the graph#2020-12-0921:41andrea.crottibut yeah getting the actual weights to do something seems to be another matter#2020-12-0921:42mishathere is a loom conj presentation https://www.youtube.com/watch?v=wEEutxTYQQU#2020-12-0921:44misha> Aysylu Greenberg - Loom and Graphs in Clojure#2020-12-0921:44andrea.crottiyeah I think I saw that some time ago, but well I kind of know how I could do it I guess.
I need to find in the whole dfs which are the terminal nodes, for them generate all the paths, then get the weights, multiply them and sum it all together#2020-12-0921:44andrea.crottiwould be nice if there was an easier way though#2020-12-0921:45mishasounds like one ugly loop
would do just fine here kappa#2020-12-0921:45andrea.crottihehe yeah that would work I guess#2020-12-0921:45andrea.crottiwas trying to avoid that since that's all I'm doing apparently#2020-12-0921:46mishayeah, story of my aoc life for 5 years#2020-12-0921:48Lars NilssonDay 7 was some ugly for comprehension over recursive calls for me.#2020-12-0921:49mishabut yeah, downloading a bunch of ugly loop
s from clojars might seem more idiomatic :)#2020-12-0922:17andrea.crottimm dammit I think I'm close
(defn n-bags-inside [gr starting]
(let [edges (lg/out-edges gr starting)]
(if (empty? edges)
1
(apply +
(for [e edges]
(* (lg/weight gr e)
(n-bags-inside gr (second e))))))))
at least it works for this simple graph
;; desired = 16
(def sample-g
(lg/weighted-digraph
[:a :b 2]
[:a :d 10]
[:b :c 3]))
#2020-12-0922:18andrea.crottibut aoc doesn't agree with me#2020-12-0922:29andrea.crottimm weird my result is exactly (actual-result / 2 + 1) using the example from the instructions#2020-12-0922:30andrea.crottibut of course if I (dec (* 2 current)) it still doesn't work 😄#2020-12-0922:30andrea.crottiso probably just a coincidence#2020-12-0922:31andrea.crottiI think the problem is maybe the graph generated because the algorithm I think it's correct, bah I'll see tomorrow#2020-12-0922:39Joe@andrea.crotti tws used https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d07.clj if you want to peek. Mine is in the related https://github.com/RedPenguin101/aoc2020/blob/main/day7.clj#2020-12-0922:40andrea.crottithat's quite neat thanks#2020-12-0922:40markwI have been revisiting some prior years problems I gave up on… https://adventofcode.com/2018/day/20 is really stumping me. Is it possible to parse something like ENWWW(NEEE|SSE(EE|N))
using recursive descent into the following paths? Basically each |
is an optional fork in the path, which starts from the point in each prior group formed by (
. The instructions give some more detail, but the above should yield these three paths:
• ENWWWNEEE
• ENWWWSSEEE
• ENWWWSSEN
I feel like this should be simple yet I’ve been stuck on it for an embarrassingly long amount of time. I recently abandoned the recursive approach dealing with each symbol in-turn for a token-by-token approach, which is getting be closer but bleh.#2020-12-0922:54Lars NilssonCheating to use instaparse?#2020-12-0923:00markwthat’s next, first i want to understand how to do it though#2020-12-0923:07st3fanDid a bunch of reading on graphs and depth first search and I think I finally have all the pieces I need to solve day 7#2020-12-0923:07st3fanTotally out of my comfort zone, but it is a good learning exercise#2020-12-0923:07st3fanGot some code snippets in a file that need to work together and then … ⭐#2020-12-1013:08oxalorg (Mitesh)Awesome solution by @pez in case people missed this thread!#2020-12-1001:20st3fanTotally over-thinking this one#2020-12-1006:19fingertoeKinda quiet in here tonight? 😉#2020-12-1006:22Vincent CantinI am sure people will start to be VERY DYNAMIC very soon.
… or never (<- hidden joke there)#2020-12-1009:04plexusI had to google "dynamic programming", seems this is basically just divide and conquer algorithms? it's not confusing at all that this has nothing to do with dynamic programming languages or dynamic bindings#2020-12-1018:17Vincent CantinIt is a "divide and reuse" way of doing. I guess the "dynamic" part is the non-constant cost of calculating things when memoized.#2020-12-1007:25rjrayCrap... almost 2 1/2 hours and I can't get a solution for part 2 that takes less than forever...#2020-12-1008:26plexusSpent about an hour on this one, and same deal. The second demo input takes ~25ms for part2, but no end in sight with the real input. Might have to crack out visualvm and do some profiling.#2020-12-1010:25Björn EbbinghausDon’t forget your old friend memoize
. That takes the naive approach straight to O(n).#2020-12-1010:46plexusI don't see how my solution benefits from memoize, it's not doing anything multiple times#2020-12-1010:47plexuswell, not 100% true, but still 🙂#2020-12-1013:09plexusalright, got a solution now#2020-12-1008:30plexusIt's that time of the year where I'm starting to wonder why I'm wasting my time on this...#2020-12-1008:56Stuartman, top solver had solution for part 2 solved in 2:19#2020-12-1009:29oxalorg (Mitesh)Oh wow didn't know you could check the stats! Thanks, it took me 26 minutes 🙈#2020-12-1009:23andrea.crottibtw during reclojure I saw someone fire up a nice graph genreated from the profiler output#2020-12-1009:24andrea.crottianyone knows how it can be done? I used to love to generate these graphs with Python and https://github.com/gak/pycallgraph#2020-12-1009:25andrea.crottisomething like https://github.com/jstepien/flames maybe but I think it was a different one#2020-12-1009:59solf@andrea.crotti probably this one: https://github.com/clojure-goes-fast/clj-async-profiler#2020-12-1014:31AleksThe best solution I’ve seen today. Only one thing I could add to it is simplifying of the part 1 by reverting map’s arguments. [Spoiler inside]#2020-12-1014:31Aleks(->> (frequencies (map - (rest adapters) adapters))
vals
(apply *))
#2020-12-1014:51Alekshttps://twitter.com/alekszelark/status/1337047003541463040#2020-12-1109:14Greg SugiyamaI'm having trouble wrapping my head around this solution for part 2. Anyone care to explain the logic behind it?#2020-12-1211:05Aleks@UE8PRHLTY The key here is a reverse order of adapters.
We start with a map with just the end adapter, which means there is only one way to reach the end. Then, on each iteration we count ways for the next adapter based on cnts map and previous calculations. And so on, until we reach opposite end of reverse sequence of adapters. At the end, we get a result hold under 0
key.
Actually, the idea is pretty simple and elegant.#2020-12-1014:34mishap2:
"Elapsed time: 0.39624 msecs"
=> 19208 (test input)
"Elapsed time: 9.720333 msecs"
=> 96717311574016
#2020-12-1015:08Lars NilssonWas trying to come up with some clever solution, but in the end gave up and memoized results.#2020-12-1015:08Lars NilssonSide-effect of my accomplishment is code that hurts my eyes.#2020-12-1015:33pezShiny gold stars does that to ya! 😃#2020-12-1015:37Lars NilssonIs that why I'm looking at completing a backlog of AoC years?#2020-12-1015:18Average-userForgot about aoc this year. Just remembered yesterday. Finally caught up !#2020-12-1016:27MnoI found an odd… pattern? in the results of day 10 part 2 .
The results will only have prime factors of 2 and 7… I’ve been trying to figure out why..
and if I could leverage that into a different solution.#2020-12-1016:45Average-userCheck out https://www.reddit.com/r/adventofcode/comments/ka9pc3/2020_day_10_part_2_suspicious_factorisation/ post in reddit, unless you don't want any spilers#2020-12-1016:46tschady@UGFL22X0Q it’s because a run of 4 ones has 7 combos, a run of 3 ones has 4 combos, and a run of 2 ones has 2 combos.#2020-12-1016:46tschadymy input didn’t have more than run of 4#2020-12-1016:47Average-userYep, it depends upon the length of runs, but I think is not that simple to get the exponents anyway#2020-12-1016:47tschadymy solution (almost there) may show that. it’s a variant of a change-making problem#2020-12-1016:50Average-userKind of, I guess. But in this case there is an O(n) solution, so clearly not the general one#2020-12-1016:50MnoI can’t say I understand it yet, but thanks a lot for the info guys#2020-12-1017:29StuartMy thinking is, but I'm having trouble implementing it.. Spoiliers ahead if this works*
Find partitions where smallest number in partition is within 3 of biggest. either the partition will have 4 numbers in it, or the partition will have 3 numbers in it (or less)
Partitions with 4 will have 4 combos.
Partitions with 3 will have 2 combos.
Multiply all theses partitions combo counts together.
It works for the smaller test but not the bigger one. Or my code is guff. 😕
Am I on the right track or should I give up with this line of thinking?#2020-12-1017:35Mnomake sure you have the beginning and ending pieces there#2020-12-1017:36Stuartyou mean the starting (0) and ending + 3, does this makes a difference?#2020-12-1017:36Stuartdamn, thought i could ignore that#2020-12-1017:36Mnoit does for this because you’re adding a 1 and 3 to the total#2020-12-1017:39MnoI dunno how to explain it, because I don’t really understand it, but I did make it work by checking the number of consecutive 1 jumps and mapping:
{:dual-consecutive-1s 2
:trip-consecutive-1s 4
:quad-consecutive-1s 7}
#2020-12-1017:40Mnoand so in the beginning if you omit the 0 to 1 jump you’re missing a consecutive 1 from the beginning.
I suppose the 3 jump at the end can be ignored#2020-12-1017:41Stuartyes, you are correct. The 0 at the start definitely makes a difference!#2020-12-1018:03tschadyspoiler, but my solution goes along these lines:
https://github.com/tschady/advent-of-code/blob/master/src/aoc/2020/d10.clj#2020-12-1018:03tschadyrelevant bit:
(defn permuted-partition-count
"Returns the number of different ways a sequence can be carved up
into segments of length 1,2, or 3"
[xs]
(->> (combo/partitions xs :min 1 :max 3)
(map (comp count combo/permutations))
(reduce +)))
#2020-12-1018:17mchampineAh, I discovered the powers of 7, 4 and 2 pattern independently and used it for my part 2:
Runs in “Elapsed time: 0.5174 msecs”
;; part 2
(defn adapter-combos [inp]
(->> (sort (concat inp [0 (+ 3 (apply max inp))]))
(partition 3 1)
(map (fn [[a _ c]] (- c a)))
(partition-by identity)
(keep {'(2 2 2) 7 '(2 2) 4 '(2) 2})
(reduce *)))
(adapter-combos input)
;; => 5289227976704
#2020-12-1221:39Jeff Evanshere is my (probably not too Clojurey) version, but hopefully with clear enough comments to explain the logic. https://github.com/jeff303/advent-of-code-2020/blob/master/src/advent_of_code/day10.clj#L41-L73#2020-12-1016:45andrea.crottijeez it's getting hard even to understand the assignment#2020-12-1016:45andrea.crottiI have to fire up all the neurons even to understand the instructions#2020-12-1020:43Stuartglad its not just me!#2020-12-1017:20roelofJust learning clojure and I wonder if the first 3 days can easiliy be done in clojure#2020-12-1017:26andrea.crottidepends what you mean by easily#2020-12-1017:26andrea.crottiif you have never done clojure it might take a while but the algoriths to use are quite simple#2020-12-1017:26AleksThere is a couple guys who recorded videos. You can learn from them a lot.#2020-12-1017:27Alekshttps://youtu.be/9ITiZ88sljA#2020-12-1017:27andrea.crottiyeah but you should try by yourself first maybe#2020-12-1017:28Aleksand https://youtu.be/Vp8RbO7l6eg#2020-12-1017:35roelofI like his man : https://www.reddit.com/r/Clojure/comments/k9cg8l/a_teacher_looks_at_advent_of_code_2020_days_07/#2020-12-1017:37Lars NilssonA lot of the very early problems rely on using things like regular expressions, generating sequences using for and range, map and filter or sequences. Having a handle on things like that will take you past several problems.#2020-12-1017:56roelofoops I hate regexes#2020-12-1017:57roelofrange, map and filyer I already learned#2020-12-1017:57roelofbut now how to read from a file#2020-12-1017:59Lars Nilsson(slurp filename), or (line-seq (reader filename)) is fairly suitable. The first gets the whole content into a string, the second generates a sequence of lines (using reader from the http://clojure.java.io namespace).#2020-12-1017:59roelofI see , I think first learn more and get more familiar with clojure#2020-12-1018:01Lars Nilsson(map #(Long/parseLong %) (line-seq (reader filename)))
would be a common way of getting a sequence of integers out of lines of integers in a file.#2020-12-1018:06Average-user> I see , I think first learn more and get more familiar with clojure
Doing AoC was for me, a good way to learn a language (in my case was Prolog)#2020-12-1018:49roelofthanks both#2020-12-1017:24Aleksan interesting stats today#2020-12-1017:28Mnopart 2… it’s definitely not easy, I’d guess because the puzzle doesn’t hint at the solution so directly?#2020-12-1017:40markwI saw part 2 and was like.. oh that’s easy, i’ll just generate permutations for everything +3 from current, drop the count of that from the remaining sequence, and concat all the results to what i’ve found so far and recurse#2020-12-1017:41markwYeah that didn’t work#2020-12-1017:41markwthen I thought.. oh that’s easy, I’ll just do a depth first search and track the paths.#2020-12-1017:41markwThat also didn’t work… I think you can see where this is going#2020-12-1017:45Average-userI also tried working out all the paths, and went to buy bread (I do these in the morning). When I got back, it (obviously) had not finished, and just then I came up with the good one 🙂#2020-12-1017:46markwI guess my first indication should have been when using the second test input took like 5 seconds to count the valid paths#2020-12-1017:47Lars NilssonMy clue was the word "trillions".#2020-12-1017:47markwwell it’s only trillions if you generate all permutations up front I think#2020-12-1017:48markwor that’s how i interpreted it late last night#2020-12-1017:54markwhmm actually, if you assume an upper bound for the branching factor of 3 (can be 1, 2, or 3 higher), then wouldn’t the possible paths be count of input ^ 3?#2020-12-1018:03Lars NilssonWouldn't it be 3^input?#2020-12-1018:03markwoops sorry yes that’s what i meant#2020-12-1018:03Lars Nilsson3^100 is a big number..#2020-12-1018:03markwso basically a very big number#2020-12-1018:03markwyeah you know it’s a problem when there is an ‘e’ in the google rsults#2020-12-1018:04markweven being generous and assuming a branching factor of 2, that’s 2.1 billion paths for the second test input#2020-12-1018:05markwso much for search#2020-12-1018:08Average-userIs there any goo way to work a clojure file without creating a whole project? This year I'm doing days in different languages. And I don't want to create a whole project for single days#2020-12-1018:09kpavYou could use a deps.edn
file#2020-12-1018:09kpavalso, as far as I know, you can just create a .clj
file, im not aware of any need to create a whole project for it#2020-12-1018:12Average-userYup you can. But working with it gets kind of awkward. For example, I work with emacs-cider, and refuses to cider-jack-in
(run the repl) correctly#2020-12-1018:13kpavah yeah, in that case try with a deps.edn
file, i have a project with that and cider-jack-in
seems to work fine#2020-12-1018:14Average-userAnything special in deps.edn
? Mine still fails#2020-12-1018:14Alekstouch hw.clj
echo "(println \"Hello world\")" > hw.clj
clj hw.clj
WARNING: When invoking clojure.main, use -M
Hello world
#2020-12-1018:17kpavI think you might just need {:deps}
? heres the documentation https://clojure.org/guides/deps_and_cli#2020-12-1018:18Aleksat least you have to have {:paths [“src”]}, that’s enough to start#2020-12-1018:19Aleksan example: https://github.com/zelark/AoC-2020/blob/master/deps.edn#2020-12-1018:21Average-userThanks, Is now working#2020-12-1018:10kpavI am still learning though so take that with a grain of salt!#2020-12-1018:17Lars NilssonI (like a lot of people, I imagine) have a project for all the days, and one file per day with a different namespace ( (ns aoc2020.day01)
for example)#2020-12-1020:47StuartI must be missing something obvious but why are the intervals between any 2 adapters today either 1 or 3. Why not 2?#2020-12-1020:49R.A. PorterThat’s just the way the Institute of Elvish Electrical Engineers spec’d them, I guess.#2020-12-1020:50pezNot sure, but I “misunderstood” the description such that this was the case and based my solution on it. 😃#2020-12-1020:51Stuartyeah, i just realised i think my solution totally breaks if any 2 adapters were seperated by 2 (and not 1 or 3)#2020-12-1020:53pezMine certainly will produce the wrong answer then. But I think it is quite small adaption needed,#2020-12-1021:02Average-userHow do they fail? Are working with prime factorization? Or am I missing something?#2020-12-1021:04StuartI look for partitions that are like [4 5 6 7], and then find the ways through those partitions find the product of those, plus the count of the partitions that dont result in a branching.#2020-12-1021:06Stuartso if in the 1st test input if the adapters were 1 4 5 6 8 10, my code would split it into [4 5 6] and I'd lose a branching multiplier#2020-12-1021:06Average-userwhat woul return to [1 3 5]?#2020-12-1021:07Stuart1#2020-12-1021:08Stuart[0 1 4 5 6 8 10] ;=> 2, where it should be 3#2020-12-1021:09StuartI got lucky my assumption held in the actual real data to pass 😄#2020-12-1021:09Average-userThe input being [1 4 5 6 8 10]? Because we were supposed to add 0 ourselves right?#2020-12-1021:09Stuartyes#2020-12-1021:09Average-userMhh, yes I think I understand what the problem is#2020-12-1021:09StuartI ignored adding the final value, it changes nothing#2020-12-1021:10Stuartsince its + 3, it can't affect branching#2020-12-1021:10Average-useryeah right#2020-12-1021:10Average-userMine I think it works with differences of two#2020-12-1021:11Average-userBut I'm not so sure anymore haha#2020-12-1021:11pezMy solution does not split or anything like that. Instead it finds sprees of distances 1, calculates (inc (combinations n 2))
on the length of these sprees and then multiplies them. This only works if there are no distances 2. But I think that I could adapt it for those as well.#2020-12-1021:11pezSo, basically some math on part 1.#2020-12-1021:13Average-userCould you elaborate? I thought there was no close formula (even under the assumption that the there are no differences of 2)#2020-12-1021:15pezI used this: https://www.calculatorsoup.com/calculators/discretemathematics/combinations.php#2020-12-1021:16pezTranslated that into:
(def !
(memoize (fn [n]
(reduce *' (range 1 (inc n))))))
(def combinations
(memoize (fn [n r]
(if (= 1 n)
0
(let [n! (! n)
r! (! r)
r-n! (! (- n r))]
(/ n! (* r! r-n!)))))))
#2020-12-1021:19Average-userThanks, I'll have a look at it. Though combinations of two can be calculated with n(n-1)/2, since r is constant in your application you don't need that complicated algorithm#2020-12-1021:24pezOh, I struggled hard to see that connection. Very nice! I’ll throw criterium on this simpler one and see it gains me execution time as well.#2020-12-1021:29Average-userI really don't understand why your solution works 😂 But nicely done. Can you prove that it does what it should?#2020-12-1021:29Average-userOre give me an insight?#2020-12-1021:31pezSo, about the same performance, but I take the simplification! 😃
Evaluation count : 4242 in 6 samples of 707 calls.
Execution time mean : 145,779817 µs
Execution time std-deviation : 4,846516 µs
Execution time lower quantile : 141,316390 µs ( 2,5%)
Execution time upper quantile : 152,683197 µs (97,5%)
Overhead used : 6,391737 ns
#2020-12-1021:32pezI can’t really prove it, but I can tell you how I arrived at it…#2020-12-1021:37Average-userIf you check, the lengths of runs of 1
s are alel numbers between 1 and 20 (at least in my input) so yeah, not gonna change performance.#2020-12-1021:38Average-userAnd I think I'm understanding why it works now Thanks!#2020-12-1021:40pezLet’s look at my part 1 solution:
(->> input
(parse)
(sort)
(cons 0)
(#(concat % [(+ 3 (last %))]))
(partition 2 1)
(map (fn [[a b]] (- b a)))
(frequencies)
(vals)
(apply *))
For the larger input example, after the (map (fn [[a b]] (- b a)))
step I have:
(1 1 1 1 3 1 1 1 1 3 3 1 1 1 3 1 1 3 3 1 1 1 1 3 1 3 3 1 1 1 1 3)
So, to me those strings of 1
s looked like “bidges”. For the shorter sprees it was easy to reason “I can remove none of them, this one, this one, those two…” and so on. There was a pattern to it and my daughter helped me see what the pattern was about. Then I googled it a bit and it seemed like the 2-combinations + 1 was the answer. I tried it and, boom.#2020-12-1021:40pezPasting my part 2 here as well, for comleteness:
(->> input
parse
(sort)
(cons 0)
(#(concat % [(+ 3 (last %))]))
(partition 2 1)
(map (fn [[a b]] (- b a)))
(partition-by identity)
(keep #(seq (filter #{1} %)))
(map count)
(map #(inc (combinations % 2)))
(apply *)))
#2020-12-1021:53Average-userI think your solution does not always work. Even if there are no differences of two: Try it on [1,2,3,4,5,8,9] for example. I think you are going to get 11
. Where the real aswwer should be 13
#2020-12-1021:57pezHaha, yes. it produces 11. Can you elaborate?#2020-12-1021:57Average-userNot that if you get to 4 or 5, you only have one way to proceed. Since 4 must go to 5. And 5 must go to 8 which must go to 9. So we can count 4 and 5 as leaves. And you get a tree with 13 leaves:#2020-12-1021:58pezSo, my solution breaks at runs > 4
?#2020-12-1021:59Average-userI thought so. But, my input has runs of 7 and it works on my input. So I'm not completely aware of whats going on#2020-12-1022:02pezThis that the last 1 near a 3 couldn’t be removed was a thing that I and my daughter saw when we were looking at it. We didn’t draw a tree of it (thankfully, maybe) but we reasoned our way towards that, like you did there before you drew the tree.#2020-12-1022:04pezDoes your input have runs of 5?#2020-12-1022:04Average-userjust {1,2,4,7}#2020-12-1022:07pezMine has 1,2,3,4… quite strange.#2020-12-1022:09Average-userNo no, I lied sorry#2020-12-1022:09Average-userIt does have runs of at most 4, there it is. I was looking at the wrong output#2020-12-1022:10Average-userhaha. yes with runs of <= 4 it works as you found the formula so it fitted that pattern#2020-12-1022:20pezSo then there might be a formula that works past 4, I guess. I just fitted 2-combinations + 1
onto the table we plotted, my daughter and I.#2020-12-1022:22pezDon’t know if you saw this https://clojurians.slack.com/archives/C0GLTDB2T/p1607593968030300?thread_ts=1607538538.458400&cid=C0GLTDB2T 😃#2020-12-1022:22Average-userYup. That would be my guess too. About another formula I'm not too sure. That's why was suspicious in the first place. A lot of this combinatorial problems have no, or very hard to find closed formula#2020-12-1022:24pezSometimes it helps not knowing much math.#2020-12-1022:24Average-userhahaha, yup.#2020-12-1022:25pezIt bothers me to know end that there wouldn’t be a formula solution to it, though.#2020-12-1022:28Average-userYou can still try to find one! I don't know if definitively does not exist. But yeah, probably not gonna be easy.parrot#2020-12-1022:29pezI’m no Ramanujan for sure.#2020-12-1022:33Average-userOn reddit I saw solutions using "Tribonacci" numbers. Which are a generalization of fibonacci numbers. And fibonacci numbers have closed formulas (although using irrationals). So there might be one, but again, probably involving irrationals#2020-12-1022:36pezInteresting. My daughter and I was “seeing” fibbonacci sequences a while, but then when we blinked they were gone. 😃#2020-12-1022:38pezI have this feeling that some day soon the AoC challenge will involve runs > 4 and that I was supposed to walk into that trap.#2020-12-1022:43pezI se 1, 2, 4, 7, 13
in that tribonacci sequence, hmmm.#2020-12-1022:45Average-userYup, that must be it#2020-12-1022:47pez(defn tribonacci [a b c]
(lazy-seq (cons a (tribonacci b c (+' a b c)))))
According to stackoverflow.#2020-12-1023:04pezThat would make a solution I am still unable to prove to be:
(defn tribonacci [a b c]
(lazy-seq (cons a (tribonacci b c (+' a b c)))))
(def run-lenght->paths
(memoize (fn [n]
(nth (tribonacci 1 2 4) (dec n)))))
(quick-bench
(->> parsed-input
(sort)
(cons 0)
(#(concat % [(+ 3 (last %))]))
(partition 2 1)
(map (fn [[a b]] (- b a)))
(partition-by identity)
(keep #(seq (filter #{1} %)))
(map count)
(map run-lenght->paths)
(apply *)) ; => 24179327893504
)
; Evaluation count : 3990 in 6 samples of 665 calls.
; Execution time mean : 150,040247 µs
; Execution time std-deviation : 5,732067 µs
; Execution time lower quantile : 143,768069 µs ( 2,5%)
; Execution time upper quantile : 157,965810 µs (97,5%)
; Overhead used : 6,391737 ns
#2020-12-1100:51Average-userGonna take a closer look to it, but probably tomorrow#2020-12-1107:42erwinrooijakkersNice pictures#2020-12-1107:43erwinrooijakkersI read on the subreddit that it’s indeed a tribonacci sequence, but not sure what that means for the solution#2020-12-1113:32Average-userIt is not hard actually. So suppose values for t(1),t(2), and t(3) are correct. And you wanna know how many ways are there to get to the fourth place in a run of ones, then since the fourth must be preceded by one of the previous three, there must be t(1) + t(2) + t(3) options. And so on an so on#2020-12-1116:34pezI think that what it means for the solution is about what I have there. Of course, it's solving the special case where there are no gaps off 2 in the input. #2020-12-1022:30rfisherPart 2 feels like it requires some knowledge of mathematics which I do not have. Presumably some aspect of combinatorics.#2020-12-1022:32pez@rob156 It might seem like that. And it helped me gather my shiny gold stars thinking it did. But I’ve just learnt (the thread above your post) that I had the math wrong. Haha.#2020-12-1022:34rfisherHmm.... I'll keep thinking then!#2020-12-1022:46Jeff Evansis there a typo on day 10, part 2, the longer sample input? here: https://adventofcode.com/2020/day/10
“In this larger example, in a chain that uses all of the adapters, there are `22` differences of 1 jolt and `10` differences of 3 jolts.”
I think there are actually 9
differences of 3 jolts. I counted by hand (and also my code came up with that, which of course may not be bug free)#2020-12-1022:48Average-userMaybe you are not counting the max element + 3 you must add#2020-12-1022:48Jeff Evansah, good catch. I somehow missed that. thanks, @lucaspolymeris!#2020-12-1102:18st3fanCan someone help me with the following (may contain a spoiler)#2020-12-1102:18st3fan(frequencies (map #(* -1 (apply - %)) (partition 2 1 [0 1 4 5 6 7 10 11 12 15 16 19 22])))
;; => {1 7, 3 5}
(defn jolt-distribution [jolts]
(frequencies (map #(* -1 (apply - %)) (partition 2 1 jolts))))
(jolt-distribution [0 1 4 5 6 7 10 11 12 15 15 19 22])
;; => {1 6, 3 4, 0 1, 4 1} ???
#2020-12-1102:18st3fanI am pretty tired, so maybe I just don’t see it - but why do I get a different result .. the function is exactly what the expression above it does#2020-12-1102:19st3fanMaybe I should restart the REPL#2020-12-1102:20st3fanI don’t get it 😕#2020-12-1102:20Stuarttwo 15s#2020-12-1102:20st3fanwhaaat#2020-12-1102:20Stuartlook at line 4#2020-12-1102:20st3fanSigh 🙂#2020-12-1102:20Stuart12 15 15 19#2020-12-1102:21Stuart(Y)#2020-12-1102:21st3fanHope I can solve part 1 before I pass out 🙂#2020-12-1102:21st3fanTY#2020-12-1102:26Stuarttoday was tough#2020-12-1102:38st3fanUhoh now I am afdraid of what to get for part 2 🙂#2020-12-1102:50st3fanI need to get better at thinking in recursion#2020-12-1102:52Stuartare you onto part 2?#2020-12-1106:26Average-userHow long take your programs for day 11?#2020-12-1107:21plexusPart 2 of day 11 on the real input runs in just under a second for me. Probably could be a lot faster but good enough for me 🙂#2020-12-1106:50Vincent CantinGood morning !#2020-12-1106:51Vincent CantinIf you find it difficult today, just remember: “C’est la vie !” (that’s life)#2020-12-1107:22plexusPleasantly surprised that my initial attempt at part 2 actually finished in under a second, I was expecting a similar scenario as yesterday... "back to the drawing board"#2020-12-1107:35Vincent CantinImpressive#2020-12-1107:39Vincent CantinI did not believe that the simple approach would be fast enough, so I spent a lot of time optimizing the algorithm and writing it down.#2020-12-1107:43plexusOne more optimized approach I can think of is doing a single pass over the layout for each of the 8 directions, so you end up with 8 data structures with precomputed values for what the next chair in that direction is. I hope that makes sense 🙂#2020-12-1107:44Vincent Cantinthat's what I did.#2020-12-1107:44plexusAnd, how fast is it?#2020-12-1107:44Vincent Cantina couple of seconds ... but my computer is a mac book air from 2011#2020-12-1107:45plexushmmm that still feels like it should be faster#2020-12-1107:45Vincent CantinNote to self: learn the mutating operators ... assoc! and friends.#2020-12-1107:46Vincent CantinI used an atom as acc inside a double for loop#2020-12-1107:46plexusyeah transients can help... not sure how much#2020-12-1107:47Vincent CantinDoing the optimised algorithm only with immutable datastructure in limited time is very hard.#2020-12-1107:47Vincent CantinI only thought about atom because I usually don't do mutable things. It's time to change that.#2020-12-1107:48Vincent CantinOther note for myself: add a reverse-range
function to my tool ns#2020-12-1107:49plexusor just use a step of -1
?#2020-12-1107:50Vincent Cantin(range (dec n) -1 -1) .. with the adrenaline of the rush, a reverse-range function is wiser.#2020-12-1107:50plexusI might have a stab at doing the precomputing later, I feel like it should be possible to make it very fast without funky stuff like transitiens#2020-12-1107:50Vincent CantinThe key is not to have to write 8 functions.#2020-12-1107:51plexusyeah, makes sense. I might write two, one for diagonal one for straight#2020-12-1107:52Vincent Cantinthe transient stuff is a good idea for opening your next stream#2020-12-1107:52plexusmeh...#2020-12-1107:53plexusI've never come across a real life need for transients#2020-12-1107:53Vincent Cantinbut people in AoC may need it soon.#2020-12-1107:54Vincent Cantin.. and that would be a good demonstration of the versatility of Clojure.#2020-12-1113:35Average-userYup, I decided to do it in haskell yesterday and I really don't want to add mutation to it.#2020-12-1116:12plexusTried the "precompute 8 layers" approach, haven't finished it yet, but calculating the layers takes about 1ms per layer or 8-10ms for all ten. Still feels like it should be possible to do that faster.#2020-12-1116:13Vincent CantinCan we see how you did?#2020-12-1116:19plexusI'll push it, trying to wrap it up. Also surprising find, looking up in 2-dimensional array is twice as slow as lookup in a two-dimensional vector#2020-12-1116:22plexus(defn getxy ^long [grid x y]
(.nth ^clojure.lang.PersistentVector (.nth ^clojure.lang.PersistentVector grid x) y))
(defn agetxy [^"[[J" arr ^long x ^long y]
(java.lang.reflect.Array/get (java.lang.reflect.Array/get arr x) y))
(let [dim 1000
arr (array-grid dim dim)]
(time
(doseq [x (range dim)
y (range dim)]
(agetxy arr x y))))
;; This takes ~150ms
(let [dim 1000
arr (mapv vec (array-grid dim dim))]
(time
(doseq [x (range dim)
y (range dim)]
(getxy arr x y))))
;; This only take ~75ms
#2020-12-1116:22plexusseems there not really any way to generate direct array lookup bytecode#2020-12-1117:09plexus@vincent.cantin https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle11_alt.clj
Here it is, a lot of effort, and in the end still slower than my first solution. Then I went back and just ported the optimized nested vector lookup, and it cut the time for my original solution in half. So now I'm at 500ms for part 2, or about 1.5s with the "8 layers" approach#2020-12-1117:17Vincent CantinI think that the lack of eccentricity of the input data implies that the simple implementation is working fast enough.#2020-12-1117:18Vincent CantinThe optimization is only saving some time when the lookup of the neighbors is costly, and it does not seem to be the case here.#2020-12-1117:21Vincent CantinI give up on trying to improve my solution any further, it makes the code look like ugly C, it’s unreadable and not interesting.#2020-12-1117:21Vincent CantinThank you for spending the time to look into it.#2020-12-1117:25Vincent CantinA last cheap optimization to be considered: having the grid on a 1 dimensional vector.
PRO: faster look up
CONS: need to manually write code to make sure that the col index is correct + it looks ugly as hell.
… tried and rolled back :face_vomiting:#2020-12-1204:13Vincent Cantin@U07FP7QJ0 I fixed your array access function, it should look like that instead:
(defn agetxy ^long [^"[[J" arr x y]
(aget ^"[J" (aget arr x) y))
#2020-12-1204:14Vincent CantinThe benchmarking has a problem too, the result of the operation needs to be used, otherwise the JVM will just drop the body using dead code elimination.#2020-12-1204:15Vincent CantinProbably, the DCE is triggered when the read expression is fully understood statically and that’s why the reflective calls where not removed - but they were slow anyway.#2020-12-1204:30Vincent Cantin@U07FP7QJ0 This is the correct way to bench, and even with the addition and transducing process overhead, it is still faster than your previous fastest.
(set! *unchecked-math* :warn-on-boxed)
(defn agetxy ^long [^"[[J" arr x y]
(aget ^"[J" (aget arr x) y))
(let [dim 1000
arr (make-array Long/TYPE dim dim)
_ (doseq [x (range dim)
y (range dim)]
#_ (aset ^"[[J" arr x y 1) ;; super slow - don't use this!
(aset ^"[J" (aget ^"[[J" arr x) y 1))
result (time
(transduce (map (fn [x]
(transduce (map (fn [y]
(agetxy arr x y)))
+
(range dim))))
+
(range dim)))]
(prn result))
#2020-12-1107:23plexusDay 11 answers thread - Post your answers here#2020-12-1107:24plexusNot gonna win at code golf but at least it works 🙂 https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle11.clj#2020-12-1107:45erwinrooijakkersSecond part (just executing how it is stated) takes 2 minutes but well, https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day11.clj. Not sure how to improve the speed.#2020-12-1107:59mchampinePart 1, kinda crufty.
;; get neighbor coords
(defn addpairs [[x1 y1] [x2 y2]] [(+ x1 x2) (+ y1 y2)])
(def surround [[1 0] [1 1] [0 1] [-1 1] [-1 0] [-1 -1] [0 -1] [1 -1]])
(defn neighbors [posn] (map addpairs (repeat posn) surround))
;; get / set seat value
(defn getxy [brd [x y]] (get (get brd y) x))
(defn setxy [brd [x y] v]
(let [row (get brd y)
newrow (apply str (assoc (vec row) x v))]
(assoc brd y newrow)))
(defn countneighbors? [brd seat]
(count (filter #{\#} (map (partial getxy brd) (neighbors seat)))))
(defn update1seat [brd seat]
(let [seatstatus (getxy brd seat)
adjseats (countneighbors? brd seat)]
(case seatstatus
\L (if (= 0 adjseats) \# \L)
\# (if (>= adjseats 4) \L \#)
\. \.)))
(defn step1 [brd]
(let [dimx (count (first brd))
dimy (count brd)
allseats (for [y (range dimy) x (range dimx)] [x y])
updatedseats (map (partial update1seat brd) allseats)]
(vec (map (partial apply str) (partition dimx updatedseats)))))
(->> input
(iterate step1)
(partition 2 1)
(drop-while #(apply not= %))
ffirst
(apply str)
(filter #{\#})
count)
;; => 2412
#2020-12-1109:08nbardiukmy solution runs in 3s and 6s, I am very curious to learn from the thread to find better data structures or approach https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day11.clj#2020-12-1110:09mishacache first-seen xys, and remove dots (floor) from the map. @U076FM90B#2020-12-1113:36genmeblogMy runs in 0.6s and 1.2s with index of seen chairs. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day11.clj#2020-12-1113:44Vincent CantinMy messy original solution (a cleaned up and faster version is coming later)
For the part 2, it scans the whole data in 8 directions in O(n) before updating the data in O(n)
https://github.com/green-coder/advent-of-code-2020/blob/1df1043c19017850257d403000d9b6f5568fddee/src/aoc/day_11.clj#2020-12-1113:57AleksHere is my solution. The key is “all decisions are based on the number of occupied seats…”
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_11.clj#2020-12-1114:23benoitMy solution to Day 11. https://github.com/benfle/advent-of-code-2020/blob/main/day11.clj#2020-12-1114:28erwinrooijakkers#2020-12-1115:27plexusTFW you think you'll speed it up by changing arrays in-place, and it's 100 times slower than updating vectors#2020-12-1115:29Vincent CantinDid you transient
/ persistent!
a lot?#2020-12-1116:00Aleks@vincent.cantin I tried, but it didn’t help much#2020-12-1116:03AleksI benched my solution with Criterium: part 1 — 882ms, and part 2 — 772ms.#2020-12-1116:07Vincent CantinCan you bench my part 1 and tell me how fast it takes on your computer? (I think my computer is way slower than everybody else) https://github.com/green-coder/advent-of-code-2020/blob/01fc1785a26872c165302c463e26caceb93e82ff/src/aoc/day_11.clj#2020-12-1116:08AleksSure!#2020-12-1116:08Vincent CantinIn this version, I tried to leverage the transducers.#2020-12-1116:17AleksPart 1 — 512.213845 ms
Part 2 — 2.664164 sec#2020-12-1116:18Vincent CantinThank you ! It seems that your computer is exactly twice faster than mine.#2020-12-1117:36markwAs concise as I could get it, but it does take ~20s to run both parts
https://github.com/Solaxun/aoc2020_clj/blob/main/src/aoc2020_clj/day11.clj#2020-12-1118:47curlyfry(time (solve adjacent-count 4)) "Elapsed time: 1488.883654 msecs"
(time (solve seen-count 5)) "Elapsed time: 2997.948211 msecs"
I was pretty happy with the functional composition in this one! (And the completely unnecessary selections
from math.combinatorics)
https://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day11/core.clj#2020-12-1121:33pez#2020-12-1121:33pez#2020-12-1121:43misha@U0ETXRFEW https://clojurians.slack.com/archives/C0GLTDB2T/p1607681391129000?thread_ts=1607671401.120300&cid=C0GLTDB2T#2020-12-1121:43nbardiukafter incorporating examples and suggestions I've managed to reduce runtime from 2s,6s to 0.6s,0.9s. What helped is to precompute near seats for each seat and split map of seat states into 3 sets (occupied, floor, seats)#2020-12-1121:46pez@U051HUZLD:I remove floor cells from the map.#2020-12-1122:56pezSo if I memoize my neighbour-of function, I get 3 secs for step 2. But can only do it once then, because on the second round it never finishes.
(def neighbours-of-
(fn
[{:keys [floor size]} seat]
(let [[rows cols] size]
(->> [[-1 -1] [0 -1] [1 -1] [-1 0] [1 0] [-1 1] [0 1] [1 1]]
(keep (fn look [direction]
(loop [delta direction]
(let [[new-r new-y] (map + seat delta)]
(when-not (or (neg? new-r)
(neg? new-y)
(> new-r rows)
(> new-y cols))
(if (floor [new-r new-y])
(recur (map + delta direction))
[new-r new-y]))))))
(into #{})))))
(def neighbours-of
(memoize neighbours-of-))
(defn occupied-neighbours-of
[ferry seat]
(->> (neighbours-of (select-keys ferry [:floor :size]) seat)
(filter #((:occupied-seats ferry) %))
(into #{})))
#2020-12-1200:05pezI’m down to 2 secs now, with cached neighbours/first-seens. Can’t see where I have gains to make. I might have choosen the wrong data structure for the grid.
#2020-12-1200:05pez(defn parse-seats [rows chs]
(->> rows
(map-indexed (fn [y row]
(map-indexed (fn [x this-ch]
(when (chs this-ch)
[x y]))
row)))
(apply concat)
(remove nil?)
(into #{})))
(defn parse [input]
(->> input
(re-seq #"[.L#]+")
((fn parse-ferry
[rows]
(let [floor (parse-seats rows #{\.})]
{:floor floor
:occupied-seats (parse-seats rows #{\#})
:all-seats (clojure.set/difference (parse-seats rows #{\# \. \L}) floor)
:neighbours-of {}
:size [(count (first rows)) (count rows)]
:generations 0})))))
(defn neighbours-of-1
[seat]
(->> [[-1 -1] [0 -1] [1 -1] [-1 0] [1 0] [-1 1] [0 1] [1 1]]
(map (fn [direction]
(map + seat direction)))
(into #{})))
(defn occupied-neighbours-of-1
[ferry seat]
(->> (neighbours-of-1 seat)
(filter (fn [c]
((:occupied-seats ferry) c)))
(into #{})))
(defn neighbours-of
[{:keys [floor size]} seat]
(let [[rows cols] size]
(->> [[-1 -1] [0 -1] [1 -1] [-1 0] [1 0] [-1 1] [0 1] [1 1]]
(keep (fn look [direction]
(loop [delta direction]
(let [[new-r new-y] (map + seat delta)]
(when-not (or (neg? new-r)
(neg? new-y)
(> new-r rows)
(> new-y cols))
(if (floor [new-r new-y])
(recur (map + delta direction))
[new-r new-y]))))))
(into #{}))))
(defn occupied-neighbours-of
[ferry seat]
(->> (get-in ferry [:neighbours-of seat])
(clojure.set/intersection (:occupied-seats ferry))))
(defn render [ferry] ; TODO: This is broken
(let [[rows cols] (:size ferry)
pixels (for [row (range rows)
col (range cols)]
(cond
((:floor ferry) [row col]) "."
((:occupied-seats ferry) [row col]) "#"
:else "L"))]
(->> pixels
(partition 10)
(map #(apply str %)))))
(defn next-ferry
[ferry]
(-> ferry
(update :occupied-seats
(fn [_]
(->> (:all-seats ferry)
(filter (fn [seat]
(let [num-occupied-neighbours (count (occupied-neighbours-of ferry seat))]
(cond
(and (not ((:occupied-seats ferry) seat))
(zero? num-occupied-neighbours))
true
(and ((:occupied-seats ferry) seat)
(>= num-occupied-neighbours 5))
false
:else
((:occupied-seats ferry) seat)))))
(into #{}))))
(update :generations inc)))
(defn cache-neighbours [ferry]
(update ferry
:neighbours-of
#(into
%
(->> (:all-seats ferry)
(map (fn [seat]
{seat (neighbours-of ferry seat)}))
(into #{})))))
(comment
(def input (util/fetch-input 11))
(time (->> input
(parse)
(cache-neighbours)
((fn stabilize [ferry]
(loop [old-ferry ferry]
(let [new-ferry (next-ferry old-ferry)]
(if (= (:occupied-seats new-ferry)
(:occupied-seats old-ferry))
old-ferry
(recur new-ferry))))))
(:occupied-seats)
(count))))
#2020-12-1217:46JoeWould anyone be able to give me some clues as to why my Day 11 Part 1 solution is so slow? I'm caching neighbours, but I'm still getting >2 seconds. I'm doing a fair amount of set operations, maybe that's it?
https://github.com/RedPenguin101/aoc2020/blob/main/day11-2.clj#2020-12-1218:00genmeblogPart 2 final stage (probably filpped): https://raw.githubusercontent.com/genmeblog/advent-of-code/master/images/advent_of_code_2020/day11_far_222.jpg#2020-12-1219:23Ben Listdefinitely not my best work, but i never cared for game of life when I had to do it in college either
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/11.clj#2020-12-1112:09Vincent Cantin😱 I replaced get-in
by 2 consecutive get
and I cut my runtime by half !!!#2020-12-1113:46Vincent CantinMy bed book this weekend will be http://clojure-goes-fast.com/blog/#2020-12-1113:49Vincent Cantinas well as https://github.com/bsless/clj-fast#2020-12-1116:23Vincent CantinFrom slower to faster:
(swap! acc update row assoc col c)
(swap! acc assoc-in [row col] c)
(swap! acc (fn [grid]
(update grid row (fn [row]
(assoc row col c))))))))
#2020-12-1121:17pezMy solution for Day 11, step 2 takes 6 seconds to run… But at least I have the stars.#2020-12-1200:13Stuartjust finished part 1 and it took 24 seconds. This does not bode well.#2020-12-1121:36curlyfryI've been getting some good mileage out of iterate
in some of the problems. Haven't gotten the opportunity to use it that much before, it's so nice when the problen fits! I started writing the body for a loop/recur and then realised that I could just feed it to iterate and it turned out much nicer#2020-12-1121:50andrea.crottiAh nice yeah I forgot about iterate#2020-12-1121:51andrea.crottiI feel like I should use a proper matrix library instead of the usual vector of vectors#2020-12-1121:51andrea.crottiWhat's the best library for this kind of stuff atm?#2020-12-1122:00curlyfry@andrea.crotti The ones I've seen (like core.matrix
) are a bit more math focused I'd say. One of the main matrix processing tools in core is https://clojuredocs.org/clojure.walk/prewalk#2020-12-1122:00curlyfryI don't really think either is very useful for today's problem though since you need to keep track of indices and stuff#2020-12-1122:02curlyfryIf you find a way to use one of the walk functions in a nice way in the problem I'd love to hear it! That was the ugliest part of my solution#2020-12-1122:46markw@vincent.cantin may the lisp gods forgive this abomination inspired by your comment:
(defmacro update-in-faster [m [k & ks] f & args]
(if ks
`((fn [m#]
(assoc m# ~k (update-in-faster (m# ~k) ~ks ~f
#2020-12-1203:38fingertoeDid anyone have flashbacks of the “Ants demo”?#2020-12-1203:39markwmore like game of life, these automata problems show up every year#2020-12-1203:40Stuartoh balls, i misread part 2, and have spent faaaar too long calculating how many empty seats i can see in any of the 8 directions until I hit an occupied seat.#2020-12-1208:14pezSounds like it could pretty easily be transformed into the right solution, though. #2020-12-1203:40StuartI have no idea why#2020-12-1203:40markwI did the same thing the first time.. actually I counted all empty seats in any direction#2020-12-1203:41markwwell any of the 8#2020-12-1203:41Stuartyeah, i've done the same. Go off on all the 8 directions and count empty seats until i hit an occupied one#2020-12-1203:41StuartWell, its 3:40 am. Fix it tomorow I guess. Dammit#2020-12-1203:42markwMy reading comprehension falls off a cliff at 11 P.M. CST apparently#2020-12-1203:42markw3:40? there goes my excuse#2020-12-1204:59AleksDay 12 answers thread - Post your answers here#2020-12-1205:52Vincent CantinThis time it was relatively relax … having a clean code helped not getting confused, I think.
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_12.clj#2020-12-1206:18rjrayHere's my (rough) code. I think it can be shorter and cleaner after I've slept a bit and can revisit it.
https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day12.clj#2020-12-1206:25mchampinePart 1, quick-n-dirty
(def raw-input (str/split-lines (slurp "resources/day12.data")))
(defn proc1 [i]
(let [[c nstr] (split-at 1 i)]
[(first c) (read-string (apply str nstr))]))
(def input (map proc1 raw-input))
(def move {\E [1 0] \W [-1 0] \N [0 1] \S [0 -1] })
(def dir->ang {\E 0 \N 90 \W 180 \S 270})
(def ang->dir {0 \E 90 \N 180 \W 270 \S})
(defn turn [currdir turndeg op]
(let [currang (dir->ang currdir)
newang (mod (op currang turndeg) 360)]
(ang->dir newang)))
(defn go [currpos direc howfar]
(let [[currx curry] currpos
[direcx direcy] (move direc)
newx (+ currx (* direcx howfar))
newy (+ curry (* direcy howfar))]
[newx newy]))
(defn step [state inst]
(let [[i v] inst]
(case i
(\N \S \E \W) (update-in state [:pos] go i v) ;; go direction i v steps
\F (update-in state [:pos] go (:direction state) v) ;; go forward v steps
\R (update-in state [:direction] turn v -) ;; turn right v degrees
\L (update-in state [:direction] turn v +)))) ;; turn left v degrees
(defn solve [i]
(let [abs (fn [v] (if (neg? v) (- v) v))
init-state {:pos [0 0] :direction \E}
finstate (reduce step init-state i)
[px py] (:pos finstate)]
(+ (abs px) (abs py))))
;; example
(def ex1 [[\F 10] [\N 3] [\F 7] [\R 90] [\F 11]])
(solve ex1)
;; => 25
(solve input)
;; => 441
#2020-12-1207:12AleksThe final question (not the puzzle itself) is a bit confusing to me. That’s why I spent almost half an hour to figure out what is wrong with my second answer.#2020-12-1207:16AleksEven worse, I solved my first part getting the final calculation wrong. And it gave me the first star.#2020-12-1207:57Dos;; 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"))))
#2020-12-1208:02Vincent CantinI forgot about Math/abs
. Thx Dosbol#2020-12-1208:11Alekshttps://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_12.clj#2020-12-1208:16joppeLooking at all of your solutions I think I have some work to do regarding not leaning too heavily on loop/recur 😅
https://github.com/Yopi/advent-of-code/blob/master/src/adventofcode/2020/day12.clj#2020-12-1208:16nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day12.clj#2020-12-1208:25Vincent CantinNice golf skills#2020-12-1208:28Vincent Cantin@UAWTW2REE You may save yourself some time by using case
#2020-12-1208:29joppeThat also makes a lot of sense, thank you! I saw cond
used somewhere and forgot all about case
😄#2020-12-1210:36pezMy program (step 1) crashes with an arity excretion at what appears to be just when the final position is reduced. I love everything about Clojure except its error messages and stack traces...#2020-12-1210:37Vincent CantinArity excretion ? XD#2020-12-1210:38pezDunno what autocorrect is thinking about today. 😎#2020-12-1210:39Vincent CantinTry completing
#2020-12-1210:52erwinrooijakkersInspiring @U076FM90B#2020-12-1210:52erwinrooijakkersYou combined part 1 and 2 by having a “shift” as a concept, how big the steps are when moving forward#2020-12-1210:53erwinrooijakkersHow you exactly do rotation so concisely is unclear to me I hope to figure it out#2020-12-1210:54erwinrooijakkersI have this monstrosity:
\L (update acc :waypoint-location
(case n
90 (comp rotate-right rotate-right rotate-right)
180 (comp rotate-right rotate-right)
270 rotate-right))
\R (update acc :waypoint-location
(case n
270 (comp rotate-right rotate-right rotate-right)
180 (comp rotate-right rotate-right)
90 rotate-right))
#2020-12-1210:58nbardiukI have 2 vectors: position [x y] and direction [dx dy]. Rotation changes direction vector using rotation matrix that I've grabbed from wikipedia https://en.wikipedia.org/wiki/Rotation_matrix#Common_rotations#2020-12-1211:06pezHaha, I have this:
(defn rotate [dir degrees]
(case degrees
90 [({[0 1] [1 0]
[1 0] [0 -1]
[0 -1] [-1 0]
[-1 0] [0 1]} dir)]
180 [({[0 1] [0 -1]
[1 0] [-1 0]
[0 -1] [0 1]
[-1 0] [1 0]} dir)]
270 [({[0 1] [-1 0]
[1 0] [0 1]
[0 -1] [1 0]
[-1 0] [ -1]} dir)]
dir))
#2020-12-1211:07AleksNot only you, check out the other solutions 🙂#2020-12-1211:08pezI can’t yet. Have this crash in step 1 to sort out. Then of course step 2 will probably take me a while too. 😃#2020-12-1211:09pezNot sure how to use completing
for the problem, @U8MJBRSR5. My function for reducing the instructions looks like so:
(defn run [program]
(reduce (fn [ferry [op arg]]
(let [{:keys [dir]} ferry]
(cond
(dirs op) (update ferry :pos #(move % (dirs op) arg))
(= "F" op) (update ferry :pos #(move % dir arg))
(= "R" op) (update ferry :dir #(rotate % arg))
(= "L" op) (update ferry :dir #(rotate % (get {90 270 270 90} arg arg))))))
{:pos [0 0]
:dir [1 0]}
program))
(Edited to fix a confusing update of :dir
.)#2020-12-1211:26pezThe function works for the example input of ""F10 N3 F7 R90"
then croaks if the next instruction is an F
instruction. (All other instruction types work…) Also the updated function doesn’t crash with arity problems, but with
class clojure.lang.PersistentVector cannot be cast to class java.lang.Number
#2020-12-1211:29pezI think I have a hint at the problem now. I’ll go back and beg for help here if it doesn’t lead anywhere. 😃#2020-12-1211:54pezIt was the gnomes and kittens murder with my rotate
that hit me. All good now.#2020-12-1213:17benoitSolution to Day 12: https://github.com/benfle/advent-of-code-2020/blob/main/day12.clj#2020-12-1213:18benoitI used a shortcut for Part 1 so I redid it so it can be used as well for Part 2.#2020-12-1214:24pezOMG. My head spins now. This was a tough one for me.
(defn parse [input]
(->> (re-seq #"\w\d+" input)
(map #(re-seq #"(\w)(\d+)" %))
(mapv (fn [[[_ op arg]]] [op (Long/parseLong arg)]))))
(def dirs {"N" [0 1]
"E" [1 0]
"S" [0 -1]
"W" [-1 0]})
(defn move [pos dir dist]
(let [movement (map * dir [dist dist])]
(->> pos
(mapv + movement))))
(defn towards [{:keys [me wp]} n]
(let [[dx' dy'] (map - wp me)
[dx dy] (map * [dx' dy'] [n n])]
{:me (map + me [dx dy])
:wp (map + wp [dx dy])}))
(defn rotate [[x y] degrees]
(case degrees
90 [(- (* x 0) (* y -1)) (+ (* x -1) (* y 0))]
180 [(- (* x -1) (* y 0)) (+ (* x 0) (* y -1))]
270 [(- (* x 0) (* y 1)) (+ (* x 1) (* y 0))] ))
(defn rotate-around [origin degrees pos]
(let [[dx' dy'] (map - pos origin)
[dx dy] (rotate [dx' dy'] degrees)]
(map + origin [dx dy])))
(defn run [program]
(reduce (fn [system [op arg]]
(let [{:keys [me]} system]
(cond
(dirs op) (update system :wp #(move % (dirs op) arg))
(= "F" op) (towards system arg)
(= "R" op) (update system :wp #(rotate-around me arg %))
(= "L" op) (update system :wp #(rotate-around me (get {90 270 270 90} arg arg) %)))))
{:me [0 0]
:wp [10 1]}
program))
(defn abs [n]
(if (neg? n)
(- n)
n))
(comment
(def input (util/fetch-input 12))
(->> #_ "F10 N3 F7 R90 F11" input
(parse)
(run)
:me
(map abs)
(apply +)))
#2020-12-1214:25pezWell, the rotation around the ship was. The rest was pretty straight forward and I was mainly fighting my own sloppyness.#2020-12-1215:30chrisblomHere's my solution: https://github.com/chrisblom/advent-of-code/blob/master/src/adventofcode/2020/day12.clj#2020-12-1215:30mchampineLots of interesting rotation functions here. I came up with this:
(defn rotate [currdir turndeg op]
(let [currang ({\E 0 \N 90 \W 180 \S 270} currdir)
newang (mod (op currang turndeg) 360)]
({0 \E 90 \N 180 \W 270 \S} newang)))
;; example: rotate 90 degrees to the left (+) from East
(rotate \E 90 +) ;; \N
#2020-12-1215:41plexusI feel like my solution is very basic compared to all the clever stuff people are doing. Just a couple nested case statements and vector literals 🙂 https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle12.clj#2020-12-1215:42plexusPretty fast too, 0.3ms for part 2#2020-12-1215:43pez0.3! Mine runs in 1.7ms. I thought that was fast.#2020-12-1215:43pezNow I must run yours on my machine. Haha.#2020-12-1216:08pezSo, on my machine with your solution and your input, @plexus:
Evaluation count : 5046 in 6 samples of 841 calls.
Execution time mean : 120,907492 µs
Execution time std-deviation : 2,337936 µs
Execution time lower quantile : 118,892646 µs ( 2,5%)
Execution time upper quantile : 124,815435 µs (97,5%)
Overhead used : 6,737515 ns
My machine, my solution, your input: 1,189428 ms#2020-12-1216:11pezAlso funny, while sanity checking my rotate
for step 2 I had something extremely like your version in my head. No idea why I didn’t just translate that. Haha.#2020-12-1216:28Average-userhttps://github.com/Average-user/aoc2020/blob/main/src/day12.clj#2020-12-1218:16curlyfryUsing core.matrix
for the rotations in part 2:
https://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day12/core.clj#2020-12-1219:05genmeblogNice mess, part 1: https://raw.githubusercontent.com/genmeblog/advent-of-code/master/images/advent_of_code_2020/day12_rules_1.jpg#2020-12-1219:06genmeblogpart 2: https://raw.githubusercontent.com/genmeblog/advent-of-code/master/images/advent_of_code_2020/day12_rules_2.jpg#2020-12-1219:07genmeblogmy solution with rendering code: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day12.clj#2020-12-1221:34Lars NilssonWent with multimethods for day 12
https://github.com/chamaeleon/aoc2020-clj/blob/master/src/aoc2020/day12.clj#2020-12-1223:13StuartDay 12 part 2:
(defn parse-line [line]
(let [[inst v] (rest (re-find #"(\w)(\d+)" line))]
[(keyword inst) (Integer/parseInt v)]))
(defn parse-input [input]
(->> input
(str/split-lines)
(map parse-line)))
(defn rotate-waypoint [[wx wy] inst ang]
(cond (or (and (= inst :R) (= ang 90))
(and (= inst :L) (= ang 270))) [wy (- wx)]
(or (and (= inst :R) (= ang 270))
(and (= inst :L) (= ang 90))) [(- wy) wx]
(= ang 180) [(- wx) (- wy)]
(= ang 360) [wx wy]))
(defn forward [[sx sy] [wx wy] distance]
[(+ sx (* wx distance)) (+ sy (* wy distance))])
(defn move2 [{:keys [ship waypoint] :as acc} [inst d]]
(let [[wx wy] waypoint]
(case inst
:N (assoc acc :waypoint [wx (+ wy d)])
:S (assoc acc :waypoint [wx (- wy d)])
:E (assoc acc :waypoint [(+ wx d) wy])
:W (assoc acc :waypoint [(- wx d) wy])
:L (assoc acc :waypoint (rotate-waypoint waypoint inst d))
:R (assoc acc :waypoint (rotate-waypoint waypoint inst d))
:F (assoc acc :ship (forward ship waypoint d)))))
(->> (reduce move2 {:ship [0 0] :waypoint [10 1]} (parse-input (slurp "resources/2020/day12")))
(:ship)
(map #(Math/abs ^int %))
(reduce +))
Part 2, I just hard coded the rotations.#2020-12-1205:00AleksMorning folks ^_^#2020-12-1205:52Vincent CantinGood morning#2020-12-1206:07Vincent Cantintroll mode: my code runs under 1 second ! 😉#2020-12-1206:10Vincent CantinI solved the puzzle using clojure.core.protocols/nav
(kidding)#2020-12-1211:08mishaboring https://github.com/akovantsev/adventofcode/commit/1302d9721e3f385569684cd5ea4b15f48efd57ef#2020-12-1211:13mishaI wish all the discussion did not happen inside a single overpopulated thread#2020-12-1212:40pezStep 2 movements done. Now to rotate. Big hmmm! Feels like it is my brain rotating and not the waypoint…#2020-12-1215:38plexusFeels like they are saving the easier ones for the weekends#2020-12-1215:44pezThis Manhattan Distance things brings back Robocode memories for me.#2020-12-1215:47plexusI recently worked on a turtle-like API for minecraft, so it definitely reminded me of that 🙂 https://github.com/plexus/witchcraft/blob/main/src/lambdaisland/witchcraft/cursor.clj#2020-12-1215:48pezI don’t know about your weekends theory, @plexus. Today’s was tough for me. Made me realize I am maybe about to drop out soon. Could not afford to spend this amount of time during work days.#2020-12-1217:57StuartAnnoying, my day 11 part 2 works with the test data, finishes with the real data but gives wrong answer. Completely lost to what hte problem is. Printing the grid and inspecting it is out the question.#2020-12-1217:58pezThe example data lacks left turns, so maybe start looking there?#2020-12-1218:08pezIf someone can add some left turns to the example data and provide it with the correct answer, then you could validate with that. I can't provide this right now. Busy with bbq. 😎#2020-12-1218:21plexus@qmstuart here's some test-input that should hit all discrete cases, plus an overview of what the ship's position and waypoint should be after each step: https://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle12.clj#L111-L144#2020-12-1218:22plexusI had the same thing happen to me first as well, I had an error in my implementation for "W", and the demo input does not contain any west instructions, so the demo input ran fine, but the result on real input was wrong#2020-12-1218:23plexusprinting out the position and waypoint after each step allowed me to manually go through the steps and mentally compute what the expected output should be, then I noticed that my west was actually going east#2020-12-1218:24plexusVideo for today: https://youtu.be/WqmswkJX7rM#2020-12-1306:05plexusStreaming day 13 in a few moments: https://youtu.be/ONclnLu3UqA#2020-12-1308:15plexusRecording: https://youtu.be/q-T87Ja2DF8#2020-12-1306:24oxalorg (Mitesh)Looks like today's 2nd part might need some Modular arithmetic to solve 🙈#2020-12-1306:30Vincent Cantin“In life, there are 92319243542196534129765432175643216314925319 kinds of people … those who can solve the math problems, and the others.”#2020-12-1306:33oxalorg (Mitesh)I thought maybe today they want us to brute force it and I waited for 20 minutes for the brute force to complete before giving up 🙈#2020-12-1306:37Vincent CantinI tried brute forcing, but then I read the text again and I stopped torturing my 2011 mac book air.#2020-12-1308:24nbardiukI've given up on brute forcing when it got too warm with laptop on my laps 🙂#2020-12-1308:51fingertoeBrute force? or remember basic HS math from thirty years ago? Maybe my high schooler is up.. If only I was a CS major instead of MIS.. Maybe it will be debits and credits next?#2020-12-1306:30Vincent CantinGood morning !#2020-12-1306:30Vincent CantinDay 13 answers thread - Post your answers here#2020-12-1307:10Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_13.clj#2020-12-1307:36plexushttps://github.com/lambdaisland/aoc_2020/blob/main/src/lambdaisland/aoc_2020/puzzle13.clj#2020-12-1308:18nbardiukthis was the hardest for me this year so far https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day13.clj#2020-12-1309:18Vincent CantinI find it fantastic that we found similar, yet different ways to calculate the result. Interesting.#2020-12-1309:32nbardiuk@U8MJBRSR5 oh, I didn't notice that bus cycles are primes, so I don't need LCM, multiplication is enough, nice catch!#2020-12-1309:49Vincent CantinI guess it depends which data you got, mine were all primes#2020-12-1310:37Vincent CantinThere must be a way to speed up our solutions using https://en.wikipedia.org/wiki/Modular_multiplicative_inverse
… the section “Application” is giving the exact math formula to our puzzle.#2020-12-1311:02joppeI used the chinese remainders theorem in my solution https://github.com/Yopi/advent-of-code/blob/master/src/adventofcode/2020/day13.clj#2020-12-1311:03joppeBut maybe it would have been easier to use modular multiplicative inverse straight away 😄#2020-12-1313:29Vincent CantinI implemented the solution from the Wikipedia article on invert-modulo, here is the source with benchmark:
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_13.clj#L71-L88#2020-12-1313:57Vincent Cantin@UAWTW2REE Clojure has (clojure.core/long n)
#2020-12-1314:24benoitThis one required some research in number theory. https://github.com/benfle/advent-of-code-2020/blob/main/day13.clj#2020-12-1314:26benoit@U076FM90B or not 🙂 Trying to understand your solution...#2020-12-1314:31Vincent Cantin@U963A21SL there is a gcd function in https://github.com/clojure/math.numeric-tower#2020-12-1314:33Vincent Cantinand there is a .modInverse
in the JDK https://clojuredocs.org/clojure.core/bigint#example-59fa5422e4b0a08026c48c8f#2020-12-1314:33benoitThanks, looking.#2020-12-1314:39benoitOk simplified a bit. Number theory is not my friend.#2020-12-1314:56JoeDoes anyone have a more thorough example of using inverses to solve systems of linear congruences? I can't figure out how you'd generalize the formula on the applications section of https://en.wikipedia.org/wiki/Modular_multiplicative_inverse to anything other than 3 equations...#2020-12-1314:59benoit@U0105JJK1L3 I used this https://www.geeksforgeeks.org/chinese-remainder-theorem-set-2-implementation/?ref=lbp#2020-12-1315:00benoit@U076FM90B Nice solution, I didn't realize that each partial solution was also cyclic and you could progress towards the solution for all buses like this.#2020-12-1315:09nbardiukYes, the partial solution repeats with least common multiple of bus cycles. As Vincent noticed all busses have prime cycle so lcm becomes just multiplication#2020-12-1315:51Joe@U963A21SL thanks, that was so much easier to understand#2020-12-1316:37JoePretty easy after you've spent 6 hours reading about modular arithmetic 😵
(defn- linear-congruence-solve [pairs]
(let [remainders (map first pairs)
modulos (map second pairs)
prod (apply * modulos)
pp (map #(/ prod %) modulos)
inv (map #(.modInverse (biginteger %1) (biginteger %2)) pp modulos)]
(mod (apply + (map * remainders pp inv)) prod)))
#2020-12-1317:22JoeA https://redpenguin101.github.io/posts/2020_12_13_mod_mult.html I took on the math in case they will be helpful for anyone else.#2020-12-1400:36genmeblogSo much energy went to figure out such short solution (0.5ms execution time) for part 2: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day13.clj#L34-L44#2020-12-1309:21Vincent CantinI think that those numbers large enough to fear a math overflow are a good hint that we need to be prepared to use https://clojuredocs.org/clojure.core/bigint and its friends.#2020-12-1313:27pezHow long will a really naïve solution take for step 2? Asking for a friend.#2020-12-1313:45Vincent CantinTell your friend that his chances will be better if he tries the “leap of faith” approach:
(-> (for [x (repeatedly (long (* (rand) Long/MAX_VALUE)))
:when (valid? x)]
x)
first)
#2020-12-1313:53pezMy friends computer is getting really hot.#2020-12-1313:53plexusSo my input had 9 bus ids, and up to 6 or 7 my initial approach would still run within a few seconds, but after that it really blew up#2020-12-1314:02Vincent Cantin@U0ETXRFEW It was not meant to be solved this way.
https://moddr.net/uploads/2008/10/computer-bbq.jpg#2020-12-1314:05pezYeah, I must find a better approach. That’s what friends are for, right?#2020-12-1314:06Vincent Cantin[spoilers alert] I can give your friend a hint: find a way to reduce
the constraints by combining them.#2020-12-1314:06pez❤️#2020-12-1314:07Vincent Cantin[spoilers alert] work on a pair of them, see what you can do to make them one#2020-12-1314:08pezWill do. Thanks!#2020-12-1314:50erwinrooijakkersIf your computation for every step takes a millisecond and you have a trillion operations it will take more than 31 years to return#2020-12-1320:52pezI managed to trial and error my way to a solution with @U8MJBRSR5’s hints. It runs in slightly less than 31 years. Now I am quite wasted. Not looking forward to tomorrow, even.#2020-12-1321:33ryan echternachtoh, @U8MJBRSR5 are you saying. find the "step size" that the first 2 numbers must be apart to line up. then combine that with the 3rd number to find a bigger step count, then ...#2020-12-1322:03pezI think that’s what he said. 😃 My reductions look like so:
({:bus 29, :offset 0}
{:bus 1073, :offset 754}
{:bus 438857, :offset 379523}
{:bus 7460569, :offset 5645807}
{:bus 96987397, :offset 50409221}
{:bus 1842760543, :offset 923295794}
{:bus 42383492489, :offset 32250225025}
{:bus 14961372848617, :offset 4312982966414}
{:bus 613416286793297, :offset 408270049879073})
#2020-12-1323:16ryan echternachtYeah, I finally got there too#2020-12-1401:22Vincent Cantin> work on a pair of them, see what you can do to make them one
I was just making a Buddhist joke, but I am glad it helped 😉#2020-12-1412:58pezHaha, I took it quit literally and it guided me to my gold star, which isn’t always easy to find on overcast days.#2020-12-1318:49thomOnly just found this channel and running a bit behind, but I've been putting up marginalia versions of my solutions at: https://lemonwatcher.com/advent.html#2020-12-1318:49thomapologies for any and all crimes against Clojure#2020-12-1318:58StuartBit stuck on part 2 today, not sure what I'm missing:
Given the busses in positions
19 is pos 0
41 is pos 9
37 is pos 13
367 is pos 19
13 is pos 32
17 is pos 36
29 is pos 48
373 is pos 50
23 is pos 73
I have calculated the answer to the problem I think I've to solve as :
561773853149685
Because
(mod 561773853149685 19)
=> 0
(mod 561773853149685 41)
=> 32 (41 - 9 = 32)
(mod 561773853149685 37)
=> 24 (37 - 13 = 24)
(mod 561773853149685 367)
=> 348 (367 - 19 = 348) as 367 is in the 19th pos.
(mod 561773853149685 13)
=> 7 (13-32 mod 13 = 7) as 13 is in the 32nd pos
(mod 561773853149685 17)
=> 15 (17 - 36 mod 17) as 17 is in the 36th pos.
(mod 561773853149685 29)
=> 10 (29 - 48 mod 29)
(mod 561773853149685 373)
=> 273 (373 - 50)
(mod 561773853149685 23)
=> 19 (23 - 73 mod 23)
What am I misunderstanding?#2020-12-1319:17StuartI think my entire idea on how I can solve this doesnt work at all. damn#2020-12-1321:25ryan echternachtit recommends starting at 15 places (100000000000000). Is this a good starting place?#2020-12-1321:26ryan echternachtand is there some smart math form of this (using LCM?). I couldn't figure one out given the offsets#2020-12-1321:30erwinrooijakkersIt’s literally the Chinese remainder theorem#2020-12-1321:31erwinrooijakkersUsing LCM I don’t know#2020-12-1321:50StuartWell, all my buses are primes. So the least common multiplier between any 2 buses is just bus 1 * bus 2#2020-12-1323:26rfisherI enjoy these when they're programming puzzles. It's not so much fun when I have to try (and fail) to independently work out some mathematical theorem I've never heard of.#2020-12-1323:26rfisherThat's not a moan, other than at myself for never learning mathematics 🙂#2020-12-1402:55ryan echternachtI agree @U0132B7P7C6. While it might literally be the Chinese remainder theorem, that's not the part of programming I enjoy/use often#2021-12-3118:18Jeff EvansAgreed with the above. There are times when the “math puzzle” piece is interesting, but at least for me, personally, I’m trying to build up my Clojure skills through this exercise. I managed to Google my way to the Chinese remainder theorem (and this thread), and happy to see others are in the same boat. This is one case where I was happy to copy/paste some code. 😆
https://github.com/jeff303/advent-of-code-2020/blob/master/src/advent_of_code/day13.clj#L80#2020-12-1321:40Joe@ryan072 check out the day 13 answers thread - plenty of advice in there.#2020-12-1322:16Stuartfinally! Got a solution that works for part 2. I had 12 failed attempts at this one!#2020-12-1323:12ryan echternachtThanks. I got it figured out#2020-12-1404:23Vincent CantinDay 14 answers thread - Post your answers here#2020-12-1406:13Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_14.clj#2020-12-1406:59Daw-Ran Liou🙌 https://github.com/dawranliou/advent-of-code/blob/master/2020/src/dawranliou/advent_of_code_2020/day_14.clj 🙌#2020-12-1407:01Daw-Ran LiouTIL bit-set
and bit-clear
😄#2020-12-1407:02AleksDirty, but works
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_14.clj#2020-12-1407:31Aleks@U7PQH43PS a bit refactored your floating function 😊
(defn floating-addresses [mask address]
(let [parsed-mask (map vector (iterate dec 35) mask)
inner (fn inner [mask address]
(if-let [[n m] (first mask)]
(case m
\0 (inner (next mask) address)
\1 (inner (next mask) (bit-set address n))
\X (concat (inner (next mask) (bit-clear address n))
(inner (next mask) (bit-set address n))))
[address]))]
(inner parsed-mask address)))
#2020-12-1407:49nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day14.clj#2020-12-1407:49erwinrooijakkersNice @U067R559Q and @U076FM90B. I didn’t know about bit-set and bit-test 🙂. Maybe I will clean mine up this evening. Dirty solution using bit-and and bit-or: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day14.clj#2020-12-1407:55erwinrooijakkersAlso my use of tree recursion and then calling flatten to get the leave values I don’t like, but not sure how to improve#2020-12-1407:57erwinrooijakkersMaybe by using similar pattern as for floating-addresses above with concat#2020-12-1408:03AleksI like floating-addresses
approach#2020-12-1408:05Aleksgonna refact my solution after work#2020-12-1410:23genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day14.clj#2020-12-1412:18pezMy step 1:
(defn parse [input]
(->> (clojure.string/split-lines input)
(map #(->> (clojure.string/split % #" ")
((fn [[op _ arg]] [op arg]))))
(map (fn [[op arg]]
(if (= op "mask")
{:mask arg}
{:addr op :value (Long/parseLong arg)})))))
(comment
(def input (util/fetch-input 14))
; step 1
(def input "mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0")
(->> input
(parse)
(reduce (fn [acc instruction]
(if-let [mask (:mask instruction)]
(merge acc
{:mask mask
:mask-or (->> (clojure.string/replace mask #"X" "0")
(str "2r")
(read-string))
:mask-and (->> (clojure.string/replace mask #"X" "1")
(str "2r")
(read-string))})
(let [{:keys [addr value]} instruction
{:keys [mask-and mask-or]} acc
masked-value (-> value
(bit-or mask-or)
(bit-and mask-and))]
(-> acc
(update-in [:memory addr] #(bit-or mask-or masked-value (or % 0)))
(update-in [:memory addr] #(bit-and mask-and masked-value (or % 0)))))))
{})
:memory
(vals)
(apply +)))
#2020-12-1413:17mishaI ChiefStringOfficer'ed this one d
https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day14.cljc#2020-12-1413:27bnstvna long one https://github.com/bnii/advent-of-code-2020/blob/main/src/day14.clj#2020-12-1413:51benoitMy solution to Day 14. I couldn't find a nice way to represent the second part. https://github.com/benfle/advent-of-code-2020/blob/main/day14.clj#2020-12-1413:52benoitMy worst performance of the season (according to my criterias) 🙂#2020-12-1413:57Vincent CantinI cleaned up my code a bit: https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_14.clj#2020-12-1414:11AleksI’m glad someone uses str/escape
now 🙂#2020-12-1414:12Vincent CantinThat’s thanks to @U07FP7QJ0 and his videos#2020-12-1414:12Vincent CantinHe saw it somewhere and it spreads#2020-12-1414:12Vincent Cantinwas it from you?#2020-12-1414:13AleksYes 🙂#2020-12-1414:13Alekspeople still like it
https://twitter.com/alekszelark/status/1335185041962504192?s=20#2020-12-1414:17AleksAlso cleaned up my code. Thanks @genmeblog for inspiration
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_14.clj#2020-12-1414:29Joehttps://github.com/RedPenguin101/aoc2020/blob/main/day14.clj - part 2 is possibly the ugliest code ever written, aside from taking over a second to run. Tidy up time!#2020-12-1416:05Aleks@genmeblog, btw in the part 2 just bit-or
is enough#2020-12-1416:09genmeblogOh, I will revisit it later, thanks! Very clean solution btw (yours)!#2020-12-1419:03AleksI ran my code with a difficult input from this thread, waited ~4 minutes and then interrupted it.
Anyone else wants to test it?
https://www.reddit.com/r/adventofcode/comments/kcybyr/2002_day_14_part_2_but_what_if_the_input_is_harder/#2020-12-1419:03Vincent CantinI thought about it, but ran for the simplest solution.#2020-12-1421:49pezI eventually did this differently, but a while I was trying this way:
masked-addr (-> addr
(#(Integer/toBinaryString %))
(->> (format "%36s"))
(clojure.string/escape {\space \0})
(->> (map (fn masker [m a]
(case m
\0 [a]
\1 [\1]
\X [\1 \0]))
mask)))
The relevant part there is how I encoded the masked address. It produces the following for the address 26 assignment in the example input:
"000000000000000000000000000000X1001X"
([\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\0]
[\1 \0]
[\1]
[\1]
[\0]
[\1]
[\1 \0])
I was pleased getting that far and thought the next step would be easy. I think about it as finding all different paths from start to end. But when I try to produce the addresses from them in a horribly nested manner. Like so:
[[[[59 100] [58 100]] [[27 100] [26 100]]] [[[[27 1] [26 1]] [[25 1] [24 1]]] [[[19 1] [18 1]] [[17 1] [16 1]]]]]
And I can’t figure out how to not produce it that way. This is my floater
reducer:
(reduce (fn [acc [masked-addr value]]
(let [floater (fn floater [addr floating]
(if-not (seq? addr)
[(->> floating
(apply (partial str "2r"))
(read-string))
value]
(let [d (first addr)]
(if (= 1 (count d))
(floater (next addr) (conj floating (first d)))
[(floater (next addr) (conj floating (first d)))
(floater (next addr) (conj floating (second d)))]))))]
(conj acc (floater masked-addr []))))
[])
… help?#2020-12-1421:51pez(I also tried using for
but that got even uglier. 😃#2020-12-1422:27pezI figured it out now. At least I figured out a way to get this neat structure:
[[(59 58 27 26) 100] [(27 26 25 24 19 18 17 16) 1]]
concat
is my buddy#2020-12-1422:32pezNext question then. This is my working floater:
(fn floater [addr floating]
(if-not (seq? addr)
[(->> floating
(apply (partial str "2r"))
(read-string))]
(let [ds (first addr)]
(if (= 1 (count ds))
(floater (next addr) (conj floating (first ds)))
(mapcat #(floater (next addr) (conj floating %)) ds)))))
It seems to me that this should be a general problem, finding all paths through a structure like this. I think I can generalize my solution, but wonder if there might already be one out there? In core even? My google fu fails me.#2020-12-1423:19pezSo, then I am ready to share my solution. It takes half a sec to step 2 compute my input, so clearly there are cpu cycles wasted, but I learnt a lot fiddling with this to and from today. Please feel invited to provide feedback to this Clojure learner:
#2020-12-1423:19pez(defn parse [input]
(->> (clojure.string/split-lines input)
(map #(->> (clojure.string/split % #" ")
((fn [[op _ arg]] [op arg]))))
(map (fn [[op arg]]
(if (= op "mask")
{:mask arg}
{:addr (->> (clojure.string/replace op #"^\D+|\D+$" "")
(Long/parseLong))
:value (Long/parseLong arg)})))))
(comment
(def input (util/fetch-input 14))
(def input "mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0")
; step 1
(->> input
(parse)
(reduce (fn [acc instruction]
(if-let [mask (:mask instruction)]
(merge acc
{:mask mask
:mask-or (->> (clojure.string/replace mask #"X" "0")
(str "2r")
(read-string))
:mask-and (->> (clojure.string/replace mask #"X" "1")
(str "2r")
(read-string))})
(let [{:keys [addr value]} instruction
{:keys [mask-and mask-or]} acc
masked-value (-> value
(bit-or mask-or)
(bit-and mask-and))]
(-> acc
(update-in [:memory addr] #(bit-or mask-or masked-value (or % 0)))
(update-in [:memory addr] #(bit-and mask-and masked-value (or % 0)))))))
{})
:memory
(vals)
(apply +))
; step 2
(def input "mask = 000000000000000000000000000000X1001X
mem[42] = 100
mask = 00000000000000000000000000000000X0XX
mem[26] = 1")
(->> input
(parse)
(reduce (fn [acc instruction]
(def acc acc)
(if-let [mask (:mask instruction)]
(merge acc
{:mask mask})
(let [{:keys [addr value]} instruction
{:keys [mask]} acc
masked-addr (-> addr
(#(Integer/toBinaryString %))
(->> (format "%36s"))
(clojure.string/escape {\space \0})
(->> (map (fn masker [m a]
(case m
\0 [a]
\1 [\1]
\X [\1 \0]))
mask)))]
(update acc :assignments conj [masked-addr value]))))
{:assignments []})
:assignments
(reduce (fn [acc [masked-addr value]]
(let [floater (fn floater [addr floating]
(if-not (seq? addr)
[(->> floating
(apply (partial str "2r"))
(read-string))]
(mapcat #(floater (next addr) (conj floating %)) (first addr))))]
(conj acc [(floater masked-addr []) value])))
[])
(reduce (fn [assignments assignment]
(merge assignments
(let [[addresses value] assignment]
(reduce (fn [acc address]
(assoc acc address value))
{}
addresses))))
{})
(vals)
(apply +)))
#2020-12-1500:28curlyfryMost of the solution is generating a list of operations per bit index, so "1XX0"
would be [0 bit-clear 3 bit-set]
that are then applied to the value with reduce
.
For part 2 I use clojure.math.combinatorics/subsets
to get all the ways of picking the floating indices and assign bit-set and bit-clear based on which indices are in each subset. A little weird but it works 🙂
https://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day14/core.clj#2020-12-1516:12Ben Listfairly happy with how mine came out, just a bunch of reductions
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/14.clj#2020-12-1406:10Vincent CantinGood morning !#2020-12-1413:14Average-userJust when I decided to use Lua
the problem requires 64-bit intgeres :c#2020-12-1419:33Alekshttps://www.reddit.com/r/adventofcode/comments/kcpdbi/2020_day_11_part_2luaroblox_waiting_room/#2020-12-1503:45Vincent CantinI may drop from the contest today - life became busy and the AoC is very time consuming when you do it seriously.#2020-12-1510:16nbardiukDon't take it seriously 🙂 Maybe some puzzle will grab your attention#2020-12-1510:18Vincent CantinI will take a look at the problem and try to solve it right before sleeping, maybe.#2020-12-1512:23pezI regret taking a look at the problem before work today. My mind is not at work, like it should be. 😃 Tomorrow I will wait with that.#2020-12-1518:00fingertoeI’ve been down to one star a day, most days Maybe I will catch up later. I find that if I take a stab at it, I ‘build the buckets’ in my brain to absorb “Oh, that’s how that should have beens solved!” at a later date.. If I don’t store the question, I have no context to understand the answer when I see it. Made it a lot further than the last few years. Thanks to everybody for the code samples. I learn a lot from all of you..#2020-12-1505:03Vincent CantinDay 15 answers thread - Post your answers here#2020-12-1505:45solfToday's part1 worked without changes for part2, in stark contrast with day 13. Which makes my first solution just brute force.
I'll spend some time thinking about the smart way, but there's less incentive when you've got the solution already.
(loop [vals (into {} (map-indexed (fn [i n] [n (list i i)]) data))
last (last data)
n (count data)]
(let [prev (take 2 (get vals last))
i-diff (apply - prev)]
#_(println n last prev)
(if (< n 30000000)
(recur
(update vals i-diff
(fn [idxs]
(if (seq idxs)
(conj idxs n)
(list n n))))
i-diff (inc n))
last)))
#2020-12-1505:48AleksYes, 13 sec for Part 2
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_15.clj#2020-12-1505:51erwinrooijakkersMine takes 70 seconds instead:
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day15.clj#2020-12-1505:51erwinrooijakkersKeeping all the indexes is probably bit slower#2020-12-1505:52erwinrooijakkersMaybe cleanup after work 🙂#2020-12-1506:04rjrayMy part 2 took about 37-40s to run, using the same brute-force approach as I used for part 1. Can't wait to see what clever math-trick I completely overlooked...
https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day15.clj#2020-12-1508:03nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day15.clj#2020-12-1510:08erwinrooijakkers@UEF091BP0 appararently there’s no clever math trick known. The sequence is called the https://oeis.org/A181391. See this thread: https://old.reddit.com/r/adventofcode/comments/kdfvec/2020_day_15_theory_behind_the_problem/#2020-12-1511:35genmeblogWith an int-array
and aget
/`aset` it's about 2.5s for part2. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day15.clj#2020-12-1511:36genmeblog(t/deftest part-3e7
(t/is (= 175594 (time (sut/game [0 3 6] 30000000))))
(t/is (= 2578 (time (sut/game [1 3 2] 30000000))))
(t/is (= 3544142 (time (sut/game [2 1 3] 30000000))))
(t/is (= 261214 (time (sut/game [1 2 3] 30000000))))
(t/is (= 6895259 (time (sut/game [2 3 1] 30000000))))
(t/is (= 18 (time (sut/game [3 2 1] 30000000))))
(t/is (= 362 (time (sut/game [3 1 2] 30000000)))))
#2020-12-1511:36genmeblog"Elapsed time: 2433.3227 msecs"
"Elapsed time: 2473.1943 msecs"
"Elapsed time: 2424.8357 msecs"
"Elapsed time: 2471.1161 msecs"
"Elapsed time: 2410.6786 msecs"
"Elapsed time: 2440.9612 msecs"
"Elapsed time: 2407.1532 msecs"
#2020-12-1513:32AleksA bit refactored, also added a fast version which uses int-array
and unchecked-
operations. About 800 ms on my machine. The slow version runs 13 secs.
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_15.clj#2020-12-1513:46nbardiukI've reached the same time of 700ms with int-array and loop/recur on my machine. The same code with java HashMap was 6 times slower 4.5s and clojure maps where another 7 time slower 30s#2020-12-1513:49genmeblogReimplemented using this data structure: http://java-performance.info/implementing-world-fastest-java-int-to-int-hash-map/ It's 2x slower than int-array
approach uses half of the memory.#2020-12-1513:50genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day15.clj#L42#2020-12-1513:51genmeblogCapacity= 16777216
"Elapsed time: 3863.6976 msecs"
#2020-12-1513:58erwinrooijakkers😆#2020-12-1514:00mishawhat's next? implementing in rust?#2020-12-1514:02genmeblogOh come on! It's done in Clojure.#2020-12-1514:04mishasame "transient" 13sec with unchecked inc and typehints.#2020-12-1514:06mishait is still in clojure, but is it 1) readable? 2) worth it?
it is a good illustration where the time is spent though#2020-12-1514:10genmeblogad1 - no, ad2 - yes! I learned something about data structures.#2020-12-1516:12benoitThankfully not too long today (for the human, not the machine): https://github.com/benfle/advent-of-code-2020/blob/main/day15.clj#2020-12-1516:13Ben Listyea my part 1 solution worked for part 2. takes about 50 seconds but not feeling super motivated to optimize it this time around
https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/15.clj#2020-12-1516:14benoitYes, arrays are good for mapping on integers 🙂 I don't have the time to improve the performances unfortunately.#2020-12-1521:58pez15s:
(->> input
(parse)
((fn [starts]
(loop [i (dec (count starts))
spoken (into {} (map-indexed (fn [i n] [n i]) (butlast starts)))
last (last starts)]
(if (< i end-t)
(let [t (spoken last)
say (if t
(- i t)
0)]
(recur (inc i) (assoc spoken last i) say))
last)))))
#2020-12-1522:35pezI get 12 seconds with a transient map and 5 seconds using a java HashMap.#2020-12-1522:37pezSo 5s:
(->> input
(parse)
((fn [starts]
(loop [i (dec (count starts))
spoken (java.util.HashMap. (into {} (map-indexed (fn [i n] [n i]) (butlast starts))))
last (last starts)]
(if (< i end-t)
(let [t (. spoken get last)
say (if t
(- i t)
0)]
(recur (inc i) (do (. spoken put last i) spoken) say))
last)))))
#2020-12-1523:11Joe42 seconds with my vanilla hashmap. Optimized with an int-array
...278 seconds. Think I might be using that wrong. 😄
https://github.com/RedPenguin101/aoc2020/blob/main/day15.clj#2020-12-1604:37curlyfryAbout 14s for my part 2:
https://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day15/core.clj#2020-12-1618:37Vincent CantinMy solution (nothing special, really)
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_15.clj#2020-12-1505:49misha.
"Elapsed time: 19815.950142 msecs" d
"Elapsed time: 13638.142432 msecs" with transient map#2020-12-1505:54misha(defn f [input n]
(loop [turn (count input)
hist (zipmap input (range 1 ##Inf))
prev (peek input)]
(if (= n turn)
prev
(recur
(inc turn)
(assoc hist prev turn)
(if-let [last (get hist prev)]
(- turn last)
0)))))
#2020-12-1506:02misha(defn f [input n]
(loop [turn (count input)
!hist (transient (zipmap input (range 1 ##Inf)))
prev (peek input)]
(if (= n turn)
prev
(let [prev* (if-let [last (get !hist prev)]
(- turn last)
0)
!hist (assoc! !hist prev turn)]
(recur (inc turn) !hist prev*)))))
#2020-12-1506:15mishaif anyone wants to have a stab at numerology and series:#2020-12-1506:15mishap2 answer here is 6428
idx num
65373 0
65374 5
65375 26
65376 275
65377 300
65378 4185
65379 2757
65380 1109
65381 6428
65382 42157
65383 0
71782 0
71783 7
71784 12
71785 45
71786 1111
71787 1927
71788 6428
71789 6407
71790 35727
71791 0
81793 0
81794 4
81795 4
81796 1
81797 19
81798 561
81799 6428
81800 10011
81801 0
137474 0
137475 6
137476 34
137477 6
137478 2
137479 215
137480 331
137481 6428
137482 55682
137483 0
205147 0
205148 7
205149 7
205150 1
205151 31
205152 707
205153 6428
205154 67672
205155 0
236727 0
236728 6
236729 32
236730 200
236731 3313
236732 6428
236733 31579
236734 0
#2020-12-1514:45Vincent CantinI just had an idea of a new format for typing less during the AoC, in case you need:
;; Fast to type
(red [acc acc-init
elm coll]
(conj acc elm))
;; The `red` macro expands to the regular reduce below.
(reduce (fn [acc elm]
(conj acc elm))
acc-init
coll)
#2020-12-1514:51timcreasySounds like into
🙂
https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L6902#2020-12-1514:52Vincent CantinIt's a reduce, don't get misdirected by my simple example.#2020-12-1514:53timcreasyAh, I dig it!#2020-12-1515:04nbardiukWhat would be syntax for reduce without acc-init ?#2020-12-1515:04Vincent Cantin(red [acc elm coll] expr)
#2020-12-1515:05Vincent CantinThat was an easy question. What is the part2? 😉#2020-12-1515:06Vincent CantinThe idea of red
is to follow the chronology of thoughts.#2020-12-1515:06Vincent CantinIt's like my comp->
macro#2020-12-1515:07MnoI’m hoping your next macro is called blue
for the simplest of reasons.#2020-12-1515:07Vincent CantinHow about green?#2020-12-1515:08MnoI’d totally be on board with that as well 😂#2020-12-1516:10benoitThere is a trade off here between readability and how fast it can be typed 🙂 I usually tend to be careful with syntactic sugar. It has to be worth the cost of learning it.#2020-12-1517:32kenjkeystroke count aside, I think this format is way easier to read and understand after the fact#2020-12-1517:55kenjI guess the only downside is you would have to wrap it in another function to use in a ->>
macro#2020-12-1602:28Vincent CantinIn this aspect, it's like for vs map#2020-12-1518:23markwCongrats @pez on the sponsorship#2020-12-1520:35pezHey, thanks! I’m still pinching my arm here.#2020-12-1610:22Vincent Cantincongratz#2020-12-1518:34R.A. PorterMy “efficient” solution to 15-2 is dog slow. Good enough to pass my tests and get mah ⭐ but terrible. About 25 seconds.#2020-12-1603:27fingertoeI got you beat at 33 seconds. 😉. My original solution was going to take a couple days, I think.. repeatedly (count seq) and (drop last) are horrible. I improved it to terrible, but functional..#2020-12-1518:55Average-userI just started reading day 15, I wonder if it has to do with https://oeis.org/A181391#2020-12-1519:14AleksYes, it is, someone said about it today.#2020-12-1602:36st3fanI got Day 15 Part 2 down to 450ms#2020-12-1602:36st3fanRewrote it in C 😉#2020-12-1602:37st3fanWill do a similar solution in Clojure though#2020-12-1606:29AleksDay 16 answers thread - Post your answers here#2020-12-1606:57rjrayLong solution. I also plan to try to improve it. Tomorrow.
https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day16.clj#2020-12-1608:08AleksNot long, but a bit dirty solution. Will try to refact it after work.
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_16.clj#2020-12-1609:29nbardiukI am glad that today's problem does not require some fancy dynamic programming algorithm https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day16.clj#2020-12-1611:33genmeblogTrue, but was much complicated than I thought at the beginning... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day16.clj#2020-12-1614:01Daw-Ran Liou😄 https://github.com/dawranliou/advent-of-code/blob/master/2020/src/dawranliou/advent_of_code_2020/day_16.clj#2020-12-1614:04benoitNothing very exciting to see here 🙂 https://github.com/benfle/advent-of-code-2020/blob/main/day16.clj#2020-12-1614:05benoitMaybe the only interesting bit is to sort the candidates for part2 so you can solve the problem in one pass in a reduce.#2020-12-1614:46Joehttps://github.com/RedPenguin101/aoc2020/blob/main/day16.clj- I'm pretty happy with my implementation for once. Short, fast(ish) and a comprehensible api. I especially like the narrow-down
function here, I thought that was going to much more difficult than it turned out to be.#2020-12-1614:47JoeReally fun puzzle too, I like this sort of thing much more than implementing efficient algorithms or fiddling with bits 😑#2020-12-1615:02misha@U963A21SL how is sorting = one pass? kappa#2020-12-1616:21erwinrooijakkersI overlooked Now that you've identified which tickets contain invalid values, _discard those tickets entirely_
#2020-12-1616:22erwinrooijakkersAnd it was bit more difficult than I thought (could not discard the non “departure” entries)#2020-12-1616:22erwinrooijakkersAnyway, https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day16.clj#2020-12-1617:04benoit@U051HUZLD sort by the number of candidates for each position. The first position will only have one candidate. The second will have two candidates, the one already picked in (1) + a new one which is the solution...#2020-12-1617:46Vincent CantinHi, here is my solution, it runs in 30 msecs on my old computer.
https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_16.clj#2020-12-1618:06euccastro@benoit is that guaranteed, or did it just happen to be true for the challenge input?#2020-12-1618:07euccastroI imagine you could have several positions with the same number of candidates, and not the first one would resolve first?#2020-12-1618:08euccastromy solution just does brute force since it works ~instantly anyway. I didn't clean it up, sorry:
(ns advent.day16
(:require [clojure.string :as str]
[ :as io]))
(def demo-input "class: 1-3 or 5-7
row: 6-11 or 33-44
seat: 13-40 or 45-50
your ticket:
7,1,14
nearby tickets:
7,3,47
40,4,50
55,2,20
38,6,12")
(defn parse-long [x]
(Long/parseLong x))
(defn extents [input]
(for [[_ & extents]
(re-seq #"(\d+)-(\d+)" input)]
(mapv parse-long extents)))
(defn nearby-tickets [input]
(-> input
(str/split #"nearby tickets:\n")
second
(str/split #"\R")
(->> (map #(str/split % #","))
(map #(mapv parse-long %)))))
(defn nearby-ticket-numbers [input]
(flatten (nearby-tickets input)))
(defn valid-number? [n extents]
(first (for [[begin end] extents
:when (<= begin n end)]
n)))
(defn invalid-numbers [input]
(let [extents (extents input)]
(remove #(valid-number? % extents) (nearby-ticket-numbers input))))
(defn solution [input]
(apply + (invalid-numbers input)))
(solution demo-input)
;; => 71
(def real-input (slurp (io/resource "input16")))
(solution real-input)
;; => 21978
;; part 2
(defn attr-extents [input]
(for [[_ attr & extents]
(re-seq #"(\w+\s*\w*):\s+(\d+)-(\d+)\s+or\s+(\d+)-(\d+)" input)]
(apply vector attr (map parse-long extents))))
(comment
(attr-extents demo-input)
)
(defn valid-ticket? [numbers extents]
(every? #(valid-number? % extents) numbers))
(defn valid-nearby-tickets [input]
(let [extents (extents input)]
(filter #(valid-ticket? % extents) (nearby-tickets input))))
(comment
(def valid-tickets* (valid-nearby-tickets demo-input (extents demo-input)))
(def attr-extents* (attr-extents demo-input))
(def num-positions (count (first valid-tickets*)))
)
(defn attr-matches-position? [[_ begin1 end1 begin2 end2] position tickets]
(every?
#(or (<= begin1 % end1) (<= begin2 % end2))
(map #(nth % position) tickets)))
(defn initial-state [aexts tickets]
(vec
(for [pos (range (count aexts))]
(set (keep
(fn [[attr :as attr-ext]]
(when (attr-matches-position?
attr-ext
pos
tickets)
attr))
aexts)))))
(defn resolve-positions [initial-state]
(let [num-positions (count initial-state)]
(loop [state initial-state]
(let [resolved (map
first
(filter #(= (count %) 1)
state))
resolved-set (set resolved)]
(if (= (count resolved) num-positions)
resolved
(recur
(map
(fn [x]
(if (= (count x) 1)
x
(remove resolved-set x)))
state)))))))
(def resolved
(resolve-positions
(initial-state
(attr-extents real-input)
(valid-nearby-tickets real-input))))
(defn my-ticket [input]
(-> input
(str/split #"ticket")
second
(->> (re-seq #"\d+")
(map parse-long))))
(def m (zipmap resolved (my-ticket real-input)))
(apply * (vals (select-keys m (filter #(str/starts-with? % "departure") (keys m)))))
;; => 105368685
#2020-12-1618:08euccastronames and factoring are very questionable, sorry#2020-12-1618:11euccastrobtw this is the first day I actually worked through the problem myself. so far I've just binge-watching @U07FP7QJ0's recorded videos (haven't caught up yet)#2020-12-1618:15pezStep 1 done. Turns out my solution is not as applicable to step 2 as things were yesterday 😃
(->> input
(parse)
((fn [notes]
(let [valid? (reduce (fn [acc rule]
(->> (:ranges rule)
(map (fn [[start end]]
(into #{} (range start (inc end)))))
(apply (partial clojure.set/union acc))))
#{}
(:rules notes))]
(filter (complement valid?) (apply concat (:nearby notes))))))
(apply +))
#2020-12-1618:45Vincent CantinI am up to date with the puzzles ^_^#2020-12-1619:57markwWill probably try to do some cleanup, time permitting:
https://github.com/Solaxun/aoc2020_clj/blob/main/src/aoc2020_clj/day16.clj#2020-12-1620:29erwinrooijakkersHow do I turn this into valid core.logic?
(run* [q]
(fresh [i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20]
(logic/== q [i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20])
(fd/in i0 i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 i16 i17 i18 i19 i20 (fd/interval 0 21))
(logic/membero i0 #{1 2 3 5 6 8 10 11 14})
(logic/membero i1 #{0 1 2 3 4 5 6 8 10 11 14 15})
(logic/membero i2 #{0 1 2 3 4 5 6 7 8 10 11 14 15 18 19})
(logic/membero i3 #{1 2 3 4 5 6 8 10 11 14})
(logic/membero i4 #{0 1 2 3 4 5 6 8 10 11 14})
(logic/membero i5 #{6 8 10 11})
(logic/membero i6 #{6 8 11})
(logic/membero i7 #{1 5 6 8 10 11 14})
(logic/membero i8 #{6 8 10 11 14})
(logic/membero i10 #{1 2 5 6 8 10 11 14})
(logic/membero i11 #{6 8})
(logic/membero i12 #{1 6 8 10 11 14})
(logic/membero i13 #{8})
(logic/membero i14 #{0 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19})
(logic/membero i15 #{0 1 2 3 4 5 6 7 8 10 11 14 15 17 18 19})
(logic/membero i16 #{0 1 2 3 4 5 6 7 8 10 11 14 15 16 17 18 19})
(logic/membero i17 #{0 1 2 3 4 5 6 7 8 10 11 12 14 15 16 17 18 19})
(logic/membero i18 #{0 1 2 3 4 5 6 8 10 11 14 15 19})
(logic/membero i19 #{0 1 2 3 4 5 6 8 10 11 14 15 18 19})
(logic/membero i20 #{0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19})))
;=> ()...
#2020-12-1620:29erwinrooijakkersThis does not make sense#2020-12-1620:31erwinrooijakkersI’ll ask in core.logic#2020-12-1621:44peterc@U65FN6WL9 @U963A21SL I also did the sort approach as I did it for speed. 1. Inspect the results after you removed the invalid fields for each position. There are some clues that a relatively "simple" solution can be used. 2. Next, sort the valid fields by count and do a set difference between each element to see that there is indeed a unique solution. Obviously a solution is not guaranteed, but step two is quick to test.#2020-12-1621:45peterchttps://github.com/peterhhchan/aoc2020/blob/main/src/aoc2020/day16.clj#2020-12-1623:46curlyfryThis one was pretty fun!
https://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day16/core.clj#2020-12-1609:21mishachief loop officer#2020-12-1609:26misha(let [[rules mine other] (parse i)
valid? (->> rules vals (reduce into #{}))
valid (->> other
(remove #(seq (remove valid? %)))
(map vec))
transposed (apply map vector valid)
candidates (fn [pred]
(->> transposed
(map-indexed
(fn [idx col]
(when (every? pred col)
idx)))
(remove nil?)))
labels (loop [done {}
todo (->> rules
(map-vals candidates)
(sort-by #(-> % val count) <)
(into PersistentQueue/EMPTY))]
(if (empty? todo)
done
(let [[label cols] (peek todo)
todo (pop todo)
cols (remove done cols)]
(if (-> cols count (= 1))
(recur (assoc done (first cols) label) todo)
(recur done (conj todo [label cols]))))))]
(->> labels
(filter #(-> % val (str/starts-with? "departure")))
(map key)
(map mine)
(reduce *)))
#2020-12-1609:38mishaofc it would loop forever, if at some point every unmapped label had more than 1 candidate idx. that'd be job for core.logic#2020-12-1618:14erwinrooijakkersah indeed#2020-12-1618:14erwinrooijakkerssmart#2020-12-1618:14erwinrooijakkersdid not think about core.logic but this is core.logic#2020-12-1614:25mdallastellaNamaste. I have a "philosophical" question about the first problem of day 1. I saw solutions like this around the internet:
(for [x input y input :when (= 2020 (+ x y))]
(* x y))
#2020-12-1614:27mdallastellabut what if my input
list is (1010
? Isn't going to stop on the first element?#2020-12-1614:27andrea.crottiThat's probably true#2020-12-1614:28andrea.crottiAnother check to make sure the numbers are not the same is enough#2020-12-1614:29andrea.crottiBut apparently it wasn't necessary given the input data#2020-12-1614:30mdallastellaI agree, but given the statement:
> Specifically, they need you to find the two entries that sum to `2020` and then multiply those two numbers together.#2020-12-1614:30mdallastellaThey won't be two entries, but one#2020-12-1614:31mdallastellaAnyway checking that are different can be enough#2020-12-1614:32mdallastellabut if I have, let's say (1010
the elements are two#2020-12-1614:33mdallastellaMaybe I'm a little pedantic...#2020-12-1614:46andrea.crottihehe well I think noone cares about the perfect solution as long as it works and it's fast enough 😄#2020-12-1614:52mishayou can compare indexes instead of actual numbers in case you want to be pedantic
(let [input [1010 1721 299 1465]]
(for [[a x] (map-indexed vector input)
[b y] (map-indexed vector input)
:when (= 2020 (+ x y))
:when (not= a b)]
(* x y)))
=> (514579 514579)
#2020-12-1615:00mishabut then :when (< a b)
is even better#2020-12-1618:39Vincent CantinDay 17 answers thread - Post your answers here#2020-12-1705:40AleksMy solution ^_^
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_17.clj#2020-12-1705:56Vincent Cantinso fast !
I can’t past part 1, I have a bug or a misunderstanding.#2020-12-1706:02Vincent CantinI don’t understand how the neighbors are counted, it seems inconsistent with the example .. maybe my english has a problem.#2020-12-1706:09AleksI believe your english much better than mine. I often have difficulties to understand what they want in the end.#2020-12-1706:10Vincent CantinI don’t understand why at z=-1 in their example, the first cube becomes active. I don’t see 3 active neighbors.#2020-12-1706:12Vincent CantinTime to work, will continue tonight.#2020-12-1706:13euccastroToday I got it cleaner than yesterday, but the solution to the second one takes ~780ms
https://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day17.clj#2020-12-1706:20euccastro@U067R559Q really neat!#2020-12-1706:22euccastroI left the first solution untouched (just redefined what had to be generalized for the second one) and much of my time went to generalize the neighbors function, just because it seemed fun#2020-12-1706:25euccastroand yeah, my cycle function would be neater had I realized that cells with 3 neighbors are always activated, whether they were already or not#2020-12-1706:30erwinrooijakkersNaive brute force (checking every neighbour for every point in every iteration) finished in 15 minutes or so for second part while I tried to optimize in the mean time https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day17.clj
Not sure how to optimize though, maybe stop counting when it’s more than 3? Any other suggestions? I’ll take a look later.#2020-12-1706:31erwinrooijakkersAH maybe use keep-indexed and not store \. as false to start with 🙂#2020-12-1706:31rjrayPure brute force for today: https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day17.clj#2020-12-1706:31rjrayI've thought of a way to avoid looping over the entire coordinate system, but it'll have to wait until tomorrow after I've slept.#2020-12-1706:39Vincent CantinI solved it. My problem was just that the text did not mention that the slides of the examples were shifted down by 1.#2020-12-1706:43Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_17.clj#2020-12-1706:49Aleks@vincent.cantin Yes, it isn’t illustrated. Sometimes it can give you wrong assumptions. Actually I didn’t look at the examples, because the description was enough to me today.#2020-12-1706:53AleksWho wants more, here you go :))
https://adventofcode.com/2019/day/24#2020-12-1707:37Vincent CantinI will keep it for january#2020-12-1707:46peterc@vincent.cantin love your solution, learned a lot from it, ty!#2020-12-1707:47Vincent CantinSeriously ?? Which part?#2020-12-1707:48Vincent CantinTIL from @U067R559Q#2020-12-1708:08petercOoops my mistake, I meant @@U067R559Q :X#2020-12-1708:46nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day17.clj#2020-12-1708:58nbardiuk@U067R559Q I love the frequences approach, it improved my slow implementation from 5s to 450ms#2020-12-1709:10mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day17.cljc#2020-12-1709:31misha9 seconds, and I don't care d#2020-12-1710:01nbardiuk@U051HUZLD sometimes it is harder to "let it go"#2020-12-1710:08mishanot after ~day15 usually#2020-12-1710:27genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day17.clj#2020-12-1713:35benoitRepresenting the pocket dimensions as a set of active cubes. Looks similar to others here. https://github.com/benfle/advent-of-code-2020/blob/main/day17.clj#2020-12-1713:36benoitOf course I had to rewrite the function that compute the neighbor coordinates for part2 to support an arbitrary number of dimensions 🙂#2020-12-1713:40Vincent Cantinhttps://github.com/benfle/advent-of-code-2020/blob/main/day17.clj#L55-L60 could also be written like (->> (all-neighbor-coordinates state) (filter (partial next-cube-active? state)) set)
#2020-12-1713:47Vincent CantinThere is also the transducer way which should run faster: (into #{} (filter (partial next-cube-active? state)) (all-neighbor-coordinates state))
#2020-12-1713:47benoitThanks, done.#2020-12-1713:49benoitThat would be cool if my IDE could detect this kind of semantic-preserving transformations and automatically propose them :)#2020-12-1713:50Vincent CantinWhich IDE are you using? Is it open source?#2020-12-1714:07benoitemacs, I believe it is open source lol#2020-12-1714:09Vincent CantinIt could eventually be in https://github.com/borkdude/clj-kondo/blob/master/doc/editor-integration.md#emacs#2020-12-1714:13Vincent Cantinnear the goal ... https://github.com/borkdude/clj-kondo/issues/323#2020-12-1714:19benoitYeah I would certainly leverage things in clj-kondo
🙂 But I'm not a fan of the overall approach of linters. This should be a la carte and an assistant to help you navigate the design space. Not a collection of rules that you must respect or be warned about.#2020-12-1716:03Joehttps://github.com/RedPenguin101/aoc2020/blob/main/day17.clj - Fun! About 500ms for Part 2#2020-12-1803:13euccastronice! nit: (apply concat (map neighbors coords))
could be just (mapcat neighbors coords)
#2020-12-1804:04curlyfryhttps://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day17/core.clj#2020-12-1804:26markwbetter late than never:
https://github.com/Solaxun/aoc2020_clj/blob/main/src/aoc2020_clj/day17.clj#2020-12-1618:49Aleks@vincent.cantin I see you’re back in the game, that’s great!#2020-12-1707:46Vincent Cantin> "Why to type [-1 0 1]
when we can just simply (range -1 2)
"
> -- brainless myself#2020-12-1708:01AleksYes, but I prefer literals whenever it’s possible. Usually they are easier to read and catch.#2020-12-1708:02Vincent Cantinyou misread ... that's sarcasm#2020-12-1708:03AleksOhh :)))#2020-12-1708:26nbardiuk😁 less characters and less off by one errors#2020-12-1709:25erwinrooijakkershahaha#2020-12-1709:25erwinrooijakkersi did the same#2020-12-1710:42euccastro(juxt dec identity inc)
? 😛#2020-12-1711:25mishaYes#2020-12-1712:08Daw-Ran Liou(take 3 (map dec (range)))
#2020-12-1712:27mishaNo#2020-12-1712:30Aleksjuxt: full version 😂
((juxt dec identity inc) (count []))
#2020-12-1714:41euccastrohehe, I was thinking of using that instead of adding deltas to get neighbours (I do use dec and inc in my solution), so I was actually half serious 😉#2020-12-1714:47euccastroi.e., (untested)
(defn cell-neighbors [cell]
(remove #{cell}
(apply combo/cartesian-product
(map (juxt dec identity inc) cell))))
This should work for any number of dimensions.#2020-12-1715:50pezMensa dictionary entry 8:
> Sarchasm : The gulf between the author of sarcastic wit and the person
> who doesn’t get it.#2020-12-1712:24Aleksdid it as an exercise, cause I rarely write macros#2020-12-1712:37Vincent CantinI did not realize that I could use the multi-arity of = .. thanks !#2020-12-1712:40Daw-Ran LiouHey I like your typeface! The ligature looks so amazing. What’s the typeface you’re using?#2020-12-1712:40Vincent Cantinit looks like firacode#2020-12-1712:41AleksYeah, it’s FiraCode by @U050UBKAA
https://github.com/tonsky/FiraCode#2020-12-1712:41Daw-Ran LiouThanks!#2020-12-1715:01erwinrooijakkersCan you copy the code, wondering what it does 🙂#2020-12-1715:02erwinrooijakkershard coded vector of [-1, 0 1]#2020-12-1715:02erwinrooijakkersAt compile time?#2020-12-1715:02erwinrooijakkersDepending on the n?#2020-12-1715:02Aleks(defmacro adjacent [n]
(let [ds (repeatedly n #(gensym "d"))
bindings (mapcat #(-> [% [-1 0 1]]) ds)]
`(for [
#2020-12-1715:04Aleksit calculates adjacent locations for n-dimension space.#2020-12-1715:05AleksYou can use it like
(def neighbours-3d (partial neighbours (adjacent 3)))
(neighbours-3d [0 0 0])
#2020-12-1715:10Vincent CantinYeah, the for
could be replaced by the list of literal of relative neighbor positions at compile time.#2020-12-1716:07Aleks@U8MJBRSR5 can you show how to to do that?#2020-12-1716:08Vincent CantinI am still at work, I will try to do that after.#2020-12-1716:35AleksI came up with this
(defmacro adjacent [n]
(let [ds (repeatedly n #(gensym "d"))
bindings (mapcat #(-> [% [-1 0 1]]) ds)]
(eval `(vec (for [
#2020-12-1716:38Vincent Cantinyou don’t need the eval, just evaluate the sequence (and put it in a vector) outside of the backtick.#2020-12-1716:41Vincent Cantinoh .. I see, if you want to use for
you can’t have a dynamic n
, you will have to use map
with recursion … or even better, comp/cartesian-product
#2020-12-1716:42Vincent Cantinwell .. it works with eval
so why not.#2020-12-1717:12Vincent Cantin@U067R559Q you can use this to generate the neighbors:
(defn adjacents [dimension]
(-> (iterate (fn [coords]
(mapcat (fn [coord]
(map (fn [x]
(conj coord x))
[-1 0 1]))
coords))
[[]])
(nth dimension)
(->> (remove (fn [coord]
(every? #{0} coord))))
vec))
#_(adjacents 2)
(defmacro neighbors [& coords]
(let [adj (adjacents (count coords))]
`(->> ~adj
(mapv (partial mapv + ~(vec coords))))))
#_(macroexpand-1 '(neighbors x y))
#_(neighbors 5 10)
#2020-12-1717:27AleksYeah, it’s also a good option, I saw it in @U076FM90B’s solution. However, I’m happy with two different functions I have. The macro is just for fun.#2020-12-1717:28Aleksbtw, I found
(defn ~name
fn args expr)) args))` in clojure.core.#2020-12-1717:29Vincent Cantinyeah, eval is ok during compile time#2020-12-1717:35Aleksalso, simple approach like this
(defn neighbours-4d [[x y z w]]
(for [dx [-1 0 1] dy [-1 0 1] dz [-1 0 1] dw [-1 0 1] :when (not= 0 dx dy dz dw)]
[(+ x dx) (+ y dy) (+ z dz) (+ w dw)]))
works faster then
(defn neighbours [adjacent loc]
(map #(mapv + loc %) adjacent))
even with predefined adjacent.#2020-12-1717:43Vincent CantinI made another version, for fun:
(defmacro neighbors [& coords]
(let [dimension (count coords)
adj (adjacents dimension)
coord-vars (repeatedly dimension #(gensym "coord"))
local-vars (repeatedly dimension #(gensym "local"))]
`(let [
#2020-12-1715:53pezI have lost my steam. Yesterday I had this whole-day testing session at my day work and it left me totally wasted. Stared at step 2 for hours without even understanding the problem. Only one gold star for me there. Today feels the same, with step 1. Might be enjoying this as a spectator sport from now. 😃#2020-12-1715:54andrea.crottihehe yeah I also feel like that after you lose one day is hard to recover#2020-12-1715:55andrea.crottiand I don't really have 1 hour or so every day to dedicate to this sadly (or I only do in the evening but I'm too tired to think)#2020-12-1715:56andrea.crottimaybe it should have a couple of breaks to allow people to get back on top of it#2020-12-1716:15pezI must say that picking aoc up was a great choice of mine. I've learnt so much from tackling the problems, from looking at your solutions, reading your comments, getting your feedback on my solutions, discussing the problems with you, discussing the solutions with you, I could go on. Spent tons of time on it. Do not regret one second. (Except yesterday, when I should have been wiser than to just sit there, staring at my failed reducing, instead of catching some needed sleep.) #2020-12-1716:21andrea.crottiyeah absolutely it's great for learning more about Clojure (or any other language tbf)#2020-12-1717:43Aleks[2020 Day 17] The hardest part.
https://i.redd.it/k6tlppouvq561.jpg#2020-12-1717:44AleksIndeed!#2020-12-1717:52Vincent CantinThat’s me !!!#2020-12-1721:30Average-userI never really follow sample inputs, just use them to check if my algo gives the correct output for them#2020-12-1717:45Average-userjajaja#2020-12-1719:24nateTook a look at past results. Interesting to see what day into the month there was an order of magnitude fewer gold stars than the first day:
2020: day 17
2019: day 14
2018: day 18
2017: didn't happen, but got close on day 25
2016: didn't happen, but got close on day 25
2015: day 19#2020-12-1719:31nbardiukTo get the gold star for day 25 you don't have new puzzle, it is a bonus star for solving all puzzles of the year#2020-12-1910:27misha to get *second gold star#2020-12-1911:32nbardiukyes, the colors are not consistent, one receives two gold stars per day. But there are silver and gold stars on stats page https://adventofcode.com/2020/stats#2020-12-1802:08markwI thought day 17 looked reasonably easy at first… Now my back of the envelope guess for part 2 completion is 2.5 hours#2020-12-1802:10markwguess that leaves me some time to consider my botched approach … or just be lazy and let it finish before day 18 😛#2020-12-1802:44markwonly an hour it turns out…. yay?#2020-12-1804:10curlyfryWhile I have no clue what your solution looks like, maybe you can bring that down without rewriting your logic at all by using memoize
(if you have any functions that will often have the same inputs throughout execution)#2020-12-1804:20markwyeah i was considering going in that direction, but i just scrapped version one and did a big refactor.. now it’s < 1 second for part 1 and about 10 for part 2, good enough for me#2020-12-1804:28curlyfryNice!#2020-12-1805:21Vincent CantinDay 18 answers thread - Post your answers here#2020-12-1805:50Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_18.clj#2020-12-1805:51euccastrohttps://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day18.clj#2020-12-1805:52euccastronice one @U8MJBRSR5!#2020-12-1805:52euccastromine is admittedly very hacky 🙂#2020-12-1805:58Vincent CantinI am awaiting the solution from @U067R559Q, hope to learn something new again.#2020-12-1805:58Vincent Cantinmine is tricky 🙂 .. tricks are not always available.#2020-12-1806:00euccastroI kind of knew postwalk existed but I had never used it so I stayed in string land all along 🙂#2020-12-1806:09Aleks@U8MJBRSR5 today is your turn to teach us something 🙂#2020-12-1806:10Vincent CantinNot fair, I will ask a refund. 😉#2020-12-1806:10AleksNice catch to use postwalk
, I even didn’t remember about it.#2020-12-1806:12AleksActually, I solved it in python, because it was faster for me. Now I’m going to have breakfast and go to work.#2020-12-1808:29AleksHere is my solution, based on postwalk
as well, but without tricks for part 2
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_18.clj#2020-12-1810:32nbardiukI struggled with this one https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day18.clj#2020-12-1811:59Joehttps://github.com/RedPenguin101/aoc2020/blob/main/day18.clj no post walk, just good old recursive calls to evaluate. Feels very SICP'y#2020-12-1812:46erwinrooijakkersLovely question. Defined two context-free grammars and used instaparse:
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day18.clj#2020-12-1815:30erwinrooijakkers(insta/visualize (arithmetic-parser2 "1 + (2 * 3) + (4 * (5 + 6))"))
#2020-12-1816:18Vincent Cantin@U2PGHFU5U at the end of your program, you do a map inside your reduce#2020-12-1816:20Vincent Cantinyou may also do something like
(->> input
(map (comp-> arithmetic-parser (partial insta/transform parse-tree->sexp)))
(reduce +))
#2020-12-1816:53Average-user(not mine) But I found this solution quite fun
https://github.com/elektronaut/advent-of-code/blob/main/day18/day18.clj
Don't know if this guy is here or not#2020-12-1817:19genmeblogI spent too much time on this today 😞 https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day18.clj#2020-12-1817:47nbardiukI feel you pain, I also manually processed tokens and spend too much time debugging precedence and parenthesis#2020-12-1818:13genmeblogYeah... The most frustrating moment was when all tests were passing but total result was wrong. After a while I've found that (9*((1+1))+1)
gave different result than (9*(1+1)+1)
....#2020-12-1818:43benoitInstaparse solution for me https://github.com/benfle/advent-of-code-2020/blob/main/day18.clj#2020-12-1903:45R.A. PorterI also went the grammar + instaparse route, anticipating that part 2 might be harder or, finally, tomorrow would build upon today. Made for almost no clojure code, but here are my crappy grammars
https://github.com/coyotesqrl/advent2020/blob/master/resources/day18-no-precedence.grammar
https://github.com/coyotesqrl/advent2020/blob/master/resources/day18-plus-precedence.grammar#2020-12-1908:02curlyfryShould have gone with instaparse right away, I also got all the test data working but failed on the file.
https://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day18/core.clj#2020-12-1910:34misha(defn calc
;; outer
([priority form]
(let [f (complement number?)
x (reduce
(fn [form ops]
(if (f form)
(calc priority ops form)
(reduced form)))
form
priority)]
(if (f x) (first x) x)))
;;inner
([priority OP form]
(if (number? form)
form
(loop [todo (rest form)
done [(calc priority (first form))]]
(if (empty? todo)
done
(let [[op x & todo] todo
f (eval op)
a (peek done)
b (if (list? x) (calc priority x) x)]
(if (OP op)
(recur todo (conj (pop done) (f a b)))
(recur todo (conj done op b)))))))))
(calc '[#{+} #{*}] '[(4 * (3 * 2 + 2) * (9 * 7 * 5 * 4 * 9) * (7 * 7 + 7 * 4 + 9)) + 6 * 4 + 8 + ((6 * 5) * 4 * (2 * 8 + 4 + 7 * 9 + 3) * 2 + 6) + 3])
(calc '[#{+} #{-}] '(10 + (6 * 5)))
(defn solve [input priority]
(->> input
(str/split-lines)
(map #(read-string (str "[" % "]")))
(map #(calc priority %))
(reduce +)))
(assert (= 15285807527593 (solve i '[#{+ *}])))
(assert (= 461295257566346 (solve i '[#{+} #{*}])))
#2020-12-1806:04Average-userThat was boring :c#2020-12-1806:04Vincent CantinMaybe it means that we improved.#2020-12-1806:05Average-userDon't think so. My solution is still pretty ugly, but that is because the problem is not very motivating. At least for me of course, it is a matter of taste.#2020-12-1806:17Vincent CantinSmall note about how to test the type of something that looks like a “list”:
;; Only use list? when you are sure what you want to test is a list.
(list? (map identity (list :a :b))) ; false
(list? (cons :a (list :b))) ; false
(list? `(:a :b)) ; false
;; sequential? is more generic.
(sequential? (map identity (list :a :b))) ; true
(sequential? (cons :a (list :b))) ; true
(sequential? `(:a :b)) ; true
;; Note: Strings are seqable, but not sequential?
(sequential? "foo")) ; false
#2020-12-1811:59Daw-Ran LiouTIL clojure.lang.Symbol
s are also functions! I guess the purpose of it is to look up things inside a map or a set but I’m not sure how to use this effectively. Here is the source code: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Symbol.java#L127-L133
;; surprise!
('+ 1 2)
;; => 2
('+ {'+ 1})
;; => 1
('+ {'+ +})
;; => #function[clojure.core/+]
('+ {'* *})
;; => nil
('+ {'* *} :not-found)
;; => :not-found
#2020-12-1812:03Daw-Ran LiouHad to learn this the hard way because my day 18 part 1 kept evaluating to the very last number in any given equation. picard-facepalm
('+ ('+ 1 ('* 2 3)) ('* 4 ('+ 5 6)))
;; => 6
#2020-12-1813:45Vincent CantinI did not know that. Thank you for sharing.#2020-12-1904:52AleksDay 19 answers thread - Post your answers here#2020-12-1905:50R.A. PorterWell. Looks like I made the right choice using and learning Instaparse for yesterday. That is the first time I’ve ever solved both puzzles in under an hour.
(defn advent-19
[input]
(let [[grammar input] (input->groups input)
grammar (->> (str/split grammar #"\n")
(sort-by #(Integer/parseInt (first (str/split % #":"))))
(str/join "\n"))
parser (insta/parser grammar)]
(->> (str/split input #"\n")
(map #(insta/parses parser %))
(remove insta/failure?)
count)))
#2020-12-1905:51R.A. Porter(`input->groups` is a utility function I’ve used a few times to split puzzle input on a blank line.)#2020-12-1906:24rjrayGot my best finish-placement yet. And learned about Instaparse!
https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day19.clj#2020-12-1906:41Vincent CantinTIL a few needed instaparse functions from @U01GXCWSRMW#2020-12-1906:52Vincent Cantin@U01GXCWSRMW Is that really necessary to sort the rules?#2020-12-1906:53Vincent CantinOOOOHHHH I found my bug !#2020-12-1906:54Vincent CantinI should parse from rule 0#2020-12-1906:57Vincent CantinProblem solved 🙂#2020-12-1907:05Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_19.clj#2020-12-1907:58AleksI solved it with regexs 😂#2020-12-1907:59Aleksthe second part was hard, because Java’s regexs don’t support recursion.#2020-12-1908:15mishahttps://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day19.clj#L29
@UEF091BP0 you could have just
(reduce-kv str/replace input
{"8: 42" "8: 42 | 42 8"
"11: 42 31" "11: 42 31 | 42 11 31"})
or if you don't mind repetition
(-> input
(str/replace "8: 42" "8: 42 | 42 8")
(str/replace "11: 42 31" "11: 42 31 | 42 11 31")))
#2020-12-1908:19misha(defn to-grammar [rules]
(str "S = 0\n" (str/replace rules #":" "=")))
(defn solve [input]
(let [[rules messages] (str/split input #"\n\n")
grammar (to-grammar rules)
parser (insta/parser grammar)]
(->> messages
(str/split-lines)
(map #(insta/parse parser %))
(remove insta/failure?)
(count))))
#2020-12-1908:46Aleks😁#2020-12-1909:58AleksI wonder anyone else solved it without instaparse?#2020-12-1910:10AleksMy solution with regexs
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_19.clj#2020-12-1910:13mishaI did part 1 with recursion and re-pattern, bailed on it as soon as read p2#2020-12-1911:08euccastrotoday was brutal for me... satisfying too, in the end!
https://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day19.clj#2020-12-1911:15euccastro@U067R559Q I eventually solved it without regexes or instaparse. I tried regexes, and even found a clever way to do recursive regexes in Java, but my first attempts didn't work and I decided that regexes were not the most fun thing to debug and moved on 🙂#2020-12-1911:25Joehttps://github.com/RedPenguin101/aoc2020/blob/main/day19.clj - Instaparse feels like cheating here, but the thought of building it myself filled me with horror.#2020-12-1911:26nbardiukwithout instaparse it is slow and hacky https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day19.clj#2020-12-1911:32euccastromine runs in ~300msecs#2020-12-1911:58euccastrobtw by "found" I mean I looked it up, not that I discovered it myself: https://stackoverflow.com/a/3644267#2020-12-1911:59euccastroa^n b^n is the pattern in 11. the pattern in 8 is just (42-pattern)+#2020-12-1913:57Aleksmy regex-ish version runs in 13.371895 msecs!#2020-12-1915:25erwinrooijakkersinstaparsed
https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day19.clj#2020-12-1917:20curlyfryI'm all for transforming inputs into some known problem and letting a lib do all the work (like creating a graph problem from the inputs and feeding it to loom
for example) but this time I literally didn't have to change anything about the format.
https://github.com/Dexterminator/advent-of-code-2020/tree/main/src/day19#2020-12-1917:36curlyfryThe actual file:
https://github.com/Dexterminator/advent-of-code-2020/blob/main/src/day19/core.clj#2020-12-1917:42rjrayWow. I hadn’t realized that the format was usable as-is. I really can’t wait until I can go back and clean up my code!#2020-12-2000:29genmeblogManual glueing regex as my third attempt... it's fast and dirty and eventually works... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day19.clj#2020-12-1905:14Vincent CantinI am going to take the slow path and do something with instaparse.#2020-12-1905:16Vincent Cantin.. because I am using it for another project, so I may learn something.#2020-12-1905:31Vincent Cantinnamely, I am parsing Tailwinds’s grammar using instaparse.#2020-12-1905:36Vincent CantinI hope to open source the project this weekend. Anyone who want to join the effort is welcome, I will make this project “community-built”.#2020-12-1905:43rjrayWTF… trying to checkout instaparse myself, and lein repl
keeps erroring out on the :require
…#2020-12-1905:44Vincent CantinPush your code, I can take a look if you need.#2020-12-1905:44rjray(ns advent-of-code.day19
(:require [clojure.string :as str]
[instaparse.code :as insta]))
#2020-12-1905:44Vincent Cantin.core#2020-12-1905:45rjray> _<#2020-12-1905:45rjrayDammit#2020-12-1905:45rjrayMoving too fast.#2020-12-1905:45Vincent Cantin(= 'too-fast 'slow)
#2020-12-1905:47rjrayYep 🙂.#2020-12-1905:51Vincent CantinI am learning the transform
function.#2020-12-1906:07Vincent CantinWhich instaparse function to use for checking if a string matches a parser?#2020-12-1906:08rjrayI couldn’t find one! If it matches, you get a vector, if it doesn’t you get a map. So I test with sequential?
.#2020-12-1906:09rjrayJust made 793 on the second star’s leaderboard. w00t!#2020-12-1906:09Vincent Cantinwow#2020-12-1906:09rjrayIf you hadn’t of mentioned Instaparse, I’d still be trying to hand-code a parser-generator!#2020-12-1906:15R.A. PorterThere’s no parsable?
or similar, but if you call parses
it should prove useful.#2020-12-1906:15Vincent CantinI wrote a function to transform the input into an instaparse grammar, but I have a bug somewhere.#2020-12-1906:16rjrayHere’s my code: https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day19.clj#2020-12-1906:16rjrayIt’s hacky. I plan to clean up the parts that transform the input into an Instaparse grammar tomorrow.#2020-12-1906:17Vincent CantinHere is mine. If you can spot the bug, that would be nice.
(def input-parser (insta/parser "
<input> = rules <#'\\R\\R'> messages
rules = rule+
messages = message+
rule = rule-ref <':'> disjunction
disjunction = (conjunction (<'|'> conjunction)*)
conjunction = rule-ref+ | text-literal
rule-ref = #'\\d+'
text-literal = <'\"'> #'[a-z]+' <'\"'>
<message> = #'.+'
" :auto-whitespace :standard))
(let [[rules messages] (->> (input-parser input-str)
(insta-tf/transform {:rules (fn [& rules] (vec rules))
:messages (fn [& messages] (vec messages))
:rule (fn [rule-id rule-definition]
(str rule-id " = " rule-definition "\n"))
:rule-ref (fn [rule-id]
(str "rule" rule-id))
:disjunction (fn [& args]
(let [s (str/join " | " args)]
(if (> (count args) 1)
(str "(" s ")")
s)))
:conjunction (fn [& args]
(str/join " " args))
:text-literal (fn [text-literal]
(str "'" text-literal "'"))}))
new-grammar (reduce str rules)
new-parser (insta/parser new-grammar)]
(->> messages
(map new-parser)
(filter sequential?)
count))
#2020-12-1906:17Vincent CantinI am not running for the leaderboard anymore.#2020-12-1906:18rjrayHuh. My transformation of the rules was dead-simple.#2020-12-1906:20rjrayFor each line, change “:” to ” = “. Change every number to “R<num>“. Then preface it all with “S = R0\n”.#2020-12-1906:21Vincent CantinI wanted to learn instaparse, so I chose what you see above 😛#2020-12-1906:21rjrayThat’s a valid point. I come from a Perl background, so I tend to see regexp transformations as the solution to everything 🙂.#2020-12-1906:22Vincent Cantinoh, I know … (a b | c d) should be (a b) | (c d)#2020-12-1906:23rjrayOh yeah, That’s going to make a huge diff. I didn’t see that when I looked at the code before.#2020-12-1906:24Vincent CantinI am not sure how instaparse does its grouping#2020-12-1906:27Vincent CantinIt still does not work#2020-12-1907:06Vincent CantinTIL that Instaparse places a precedence on the concatenation compared to the ‘|' operator.#2020-12-1907:45Vincent Cantin@UEF091BP0: I feel like an impostor, having used instaparse for part 2.#2020-12-1915:26erwinrooijakkers> Tailwinds’s grammar using instaparse
tell me more!#2020-12-1915:26Vincent Cantin(ns girouette.grammar.css-class
(:require [instaparse.core :as insta]))
;; Use case 1: "css class name -> corresponding css"
;; - parse a class name,
;; - find its matching rule and its variable bindings,
;; - call the css generator with the bindings,
;; - get the css corresponding to the class name.
;; Use case 2: "generate css for given combinations of rules and bindings"
;; - given a rule, some bindings between variables and a collection of values,
;; - generate the corresponding css, aggregated in order.
;; Note: the generated css could be either a string or garden format.
;; Beware: the order of the css statements matter, it should be the same as Tailwind.
(def css-class-grammar "
rule =
(* Layout Section *)
container | box-sizing | display | floats | clear |
object-fit | object-position | overflow | overscroll |
position | positioning | visibility | z-index |
(* Flexbox Section *)
flex-direction | flex-wrap | flex | order |
(* Grid Section *)
grid-template-columns | grid-column-start-end |
grid-template-rows | grid-row-start-end |
grid-auto-flow | grid-auto-columns | grid-auto-rows | gap |
padding | margin
container = <'container'>
box-sizing = 'box-border' | 'box-content'
display = 'block' | 'inline-block' | 'inline' | 'flex' | 'inline-flex' |
'table' | 'table-caption' | 'table-cell' | 'table-column' | 'table-column-group' |
'table-footer-group' | 'table-header-group' | 'table-row-group' | 'table-row' |
'flow-root' | 'grid' |'inline-grid' | 'contents' | 'hidden'
floats = <'float-'> ('left' | 'right' | 'none')
clear = <'clear-'> ('left' | 'right' | 'both' | 'none')
object-fit = <'object-'> ('contain' | 'cover' | 'fill' | 'none' | 'scale-down')
object-position = <'object-'> object-position-side
<object-position-side> = 'left' | 'left-bottom' | 'left-top' |
'right' | 'right-bottom' | 'right-top' |
'center' | 'bottom' | 'top'
overflow = <'overflow-'> (axis <'-'>)? overflow-mode
overflow-mode = 'auto' | 'hidden' | 'visible' | 'scroll'
overscroll = <'overscroll-'> (axis <'-'>)? overscroll-mode
overscroll-mode = 'auto' | 'contain' | 'none'
position = 'static' | 'fixed' | 'absolute' | 'relative' | 'sticky'
positioning = signus? positioning-mode <'-'> positioning-size
positioning-mode = 'top' | 'right' | 'bottom' | 'left' | 'inset'
positioning-size = size unit? | unit | fraction | 'auto'
visibility = 'visible' | 'invisible'
z-index = signus? <'z-'> (#'\\d+' | 'auto')
flex-direction = <'flex-'> ('row' | 'row-reverse' | 'col' | 'col-reverse')
flex-wrap = <'flex-'> ('wrap' | 'wrap-reverse' | 'nowrap')
flex = <'flex-'> (flex-shorthand | (flex-grow-value (<'-'> flex-shrink-value)? <'-'> flex-basis-value))
flex-grow = <'flex-grow'> (<'-'> flex-grow-value)?
flex-shrink = <'flex-shrink'> (<'-'> flex-shrink-value)?
flex-shorthand = '1' | 'auto' | 'initial' | 'none'
flex-grow-value = int-number
flex-shrink-value = int-number
flex-basis-value = size unit? | unit | fraction | 'auto'
order = signus? <'order-'> int-number | 'first' | 'last' | 'none'
grid-template-columns = <'grid-cols-'> (int-number | 'none')
grid-column-start-end =
<'col-'> ('auto' |
('span-' (int-number | 'full')) |
('start' (int-number | 'auto')) |
('end' (int-number | 'auto')))
grid-template-rows = <'grid-rows-'> (int-number | 'none')
grid-row-start-end =
<'row-'> ('auto' |
('span-' (int-number | 'full')) |
('start' (int-number | 'auto')) |
('end' (int-number | 'auto')))
grid-auto-flow = <'grid-flow-'> ('row' | 'col') (<'-'> 'dense')?
grid-auto-columns = <'auto-cols-'> ('auto' | 'min' | 'max' | (int-number? 'fr'))
grid-auto-rows = <'auto-rows-'> ('auto' | 'min' | 'max' | (int-number? 'fr'))
gap = <'gap-'> (axis <'-'>)? (size unit? | unit)
padding = signus? <'p'> (direction | axis)? <'-'> (size unit? | unit)
margin = signus? <'m'> (direction | axis)? <'-'> (size unit? | unit)
signus = '-' | '+'
direction = 't' | 'r' | 'b' | 'l'
axis = 'x' | 'y'
size = float-number
<int-number> = #'\\d+'
<float-number> = #'\\d+(_\\d+)?'
fraction = #'\\d+' '/' #'\\d+' | 'full'
unit = 'px' | 'em' | 'rem'
")
(def css-class-parser
(insta/parser css-class-grammar))
(comment
(css-class-parser "gap-x-37_5px")
(css-class-parser "z-7")
(css-class-parser "-order-37")
(css-class-parser "flex-0-1-auto")
(css-class-parser "overflow-x-auto")
(css-class-parser "-inset-2/3")
(css-class-parser "container")
(css-class-parser "-mx-30_5px")
(css-class-parser "pt-2px")
(css-class-parser "pt-5")
(css-class-parser "p-5"))
#2020-12-1915:27Vincent Cantinthat’s my POC#2020-12-1915:27erwinrooijakkerswhere do you use it for?#2020-12-1915:27erwinrooijakkersat work we use tailwind#2020-12-1915:27erwinrooijakkersmakes css fun#2020-12-1915:27erwinrooijakkersi mean: where do you use that parser for?#2020-12-1915:28Vincent CantinShort answer: Where you can.#2020-12-1915:28Vincent CantinLong answer: Where you can.#2020-12-1915:29erwinrooijakkersnote that you only needed to sort the numbers for instaparse in this question#2020-12-1915:29erwinrooijakkersit was already a valid grammar#2020-12-1915:29Vincent CantinI did without sorting, by adding a new root at the top.#2020-12-1915:30Vincent CantinI suspect that instaparse has an option to define which rule to use as the root.#2020-12-1915:30erwinrooijakkersyou can use =
:
:=
and ::=
to define rules#2020-12-1915:30erwinrooijakkersah yes maybe#2020-12-1915:30Vincent CantinYes, I know … I just wanted to play with the transformer.#2020-12-1915:30Vincent CantinI wanted to learn something.#2020-12-1915:31erwinrooijakkers🙂#2020-12-1915:46Charles FourdrignierAs "everyone", I used Instaparse.
Discovered afterwards that you can just prepend "valid : 0\n" to the rules, instead of "sorting" rules so 0 is the first one.
(defn sort-rules [rules] (str "valid : 0\n" rules))
(defn solve-part-1 [input]
(let [[rules messages] (str/split input #"\R\R")
parse (insta/parser (sort-rules rules))
valid? (comp not insta/failure? parse)]
(count (filter valid? (str/split-lines messages)))))
#2020-12-1915:55erwinrooijakkersaaaah#2020-12-1915:55erwinrooijakkershaha#2020-12-1916:38benoitThis one was painful. A solution without instaparse: https://github.com/benfle/advent-of-code-2020/blob/main/day19.clj#2020-12-1916:42Vincent CantinHow did you handle the infinite loops ?#2020-12-1916:42benoitIt works for part2 with the recursive rules because concat
is lazy 🙂#2020-12-1916:42Vincent Cantinah, I see … breadth search?#2020-12-1916:43Vincent Cantinor just luck of being in the right order?#2020-12-1916:43benoitI basically generate all possible paths through the grammar until I find one that matches, yes.#2020-12-1916:44Vincent CantinToday’s puzzle reminded me a lot of my library Minimallist where I did the exact same parsing.#2020-12-1916:48Vincent Cantin@U963A21SL Does it still work if you reverse the order of the alt in the data?
(assoc-in [:rules 8] [:non-terminal '((42 8) (42))])
#2020-12-1916:49benoit(assoc-in [:rules 8] [:non-terminal '((42 8) (42))])
?#2020-12-1916:49benoityes#2020-12-1916:49Vincent Cantinimpressive#2020-12-1916:59benoitActually it doesn't need to be lazy 🙂 I'm not generating the strings, I'm matching against the messages so it will stop in the success case as well.#2020-12-1917:01Vincent CantinStart matching with this evil rule, does it still work?
666: 666 | 0#2020-12-1917:06benoitThat's where you need the laziness, yes 🙂#2020-12-1917:07benoitIt stack overflows when I doall
the concat
but works otherwise.#2020-12-1917:08benoitNevermind I didn't test properly.#2020-12-1917:08benoitIt overflows, yes.#2020-12-1917:09Vincent CantinAnyway, congratz on finishing it the hard way.#2020-12-1917:13benoitI would be curious to know the solution that takes advantage of the hint in part2. I still don't understand what they meant by this hint.#2020-12-1917:15Vincent CantinWhat hint?#2020-12-1917:15benoitThis small change has a big impact: now, the rules do contain loops, and the list of messages they could hypothetically match is infinite. You'll need to determine how these changes affect which messages are valid.
Fortunately, many of the rules are unaffected by this change; it might help to start by looking at which rules always match the same set of values and how those rules (especially rules 42 and 31) are used by the new versions of rules 8 and 11.
#2020-12-1917:15benoitMaybe it's for people who did Part1 by generating all possible strings in the language?#2020-12-1917:17benoitFor part1 I had a much simpler solution where I consumed the message while traversing the grammar.#2020-12-1917:18benoitUnfortunately this didn't work for Part2 because of the recursions. I was taking just one path in the grammar. That's when I had the idea to return a seq of matches instead of the first one,#2020-12-1917:20Vincent CantinYou could have reuse your part 1 and push down the recursion a set of visited [rule matching-index] and fail a match if you are asked to match something you visited before (to detect a loop).#2020-12-1917:22Vincent CantinI don’t understand the hint, it sounds more complicated to do something custom than doing it for the general case.#2020-12-1917:23benoitWhy would you fail if you detect a cycle?#2020-12-1917:23benoitSome of the messages are only valid in part2 because those cycles are visited a few times.#2020-12-1917:24Vincent Cantinthe matching index is to be part of the state, not just the rule alone.#2020-12-1917:26benoitBut my problem with part1 was not that it was looping but that it was stopping too early with unconsumed input#2020-12-1917:27benoitBecause it was not greedy and repeating the cycles. That's where I got the idea to just generate all matches until I find one that return an empty string.#2020-12-1917:28Vincent Cantinsleeping time here, see you tomorrow~#2020-12-1917:29benoit:thumbsup:#2020-12-2000:06AdamI solved part 1 by generating a regular expression, then rewrote my solution to solve both part 1 and 2 using a handwritten parser. It came out quite https://github.com/ocisly/advent2020/blob/674ec473fe599cc081a07a7d676502138cfbc672/day-19.clj#L26-L32!#2020-12-2004:43benoitLooks great 👍 #2020-12-1907:11Vincent Cantin> “I am a good library, AoC had me tested!”
>
> — Instaparse#2020-12-1907:54joppeHaha instaparse, really the tip of the day 😄#2020-12-1908:07misharead part2 description and *insta*ntly replaced page of spaghetti embarrassment with instaparse kappa#2020-12-1910:16Aleksme and my regular expression for part 1
〜(><)〜
"(?:(?:(?:b(?:b(?:(?:b(?:(?:(?:ab|aa)b|(?:ab|bb)a)b|(?:(?:ba|bb)b|(?:ab|bb)a)a)|a(?:(?:a(?:ab)|b(?:ba|bb))b|(?:b(?:ab|aa)|a(?:aa|b(?:b|a)))a))a|(?:b(?:a(?:(?:b|a)(?:(?:b|a)b|aa))|b(?:a(?:ab|bb)|b(?:aa|b(?:b|a))))|a(?:(?:(?:ab|aa)(?:b|a))a|(?:(?:aa)b|(?:ab|aa)a)b))b)|a(?:(?:b(?:(?:(?:ba|bb)b|(?:ab|bb)a)b|(?:a(?:(?:b|a)b|aa)|b(?:ab|ba))a)|a(?:a(?:(?:ab|bb)a|(?:(?:b|a)(?:b|a))b)|b(?:(?:ab|aa)(?:b|a))))b|(?:b(?:(?:(?:(?:b|a)(?:b|a))a|(?:bb)b)b|(?:(?:ab)a|(?:ab)b)a)|a(?:a(?:(?:ab|aa)a)|b(?:b(?:(?:b|a)(?:b|a))|a(?:bb))))a))|a(?:(?:a(?:(?:(?:a(?:ab|aa)|b(?:ab|(?:b|a)a))a|(?:b(?:ab)|a(?:ab|ba))b)b|(?:(?:(?:bb|aa)a)a|(?:(?:b|a)(?:ab|(?:b|a)a))b)a)|b(?:b(?:(?:a(?:ab))b|(?:b(?:(?:b|a)b|aa)|a(?:bb|aa))a)|a(?:b(?:b(?:bb|aa)|a(?:ba|bb))|a(?:(?:aa)a|(?:bb)b))))a|(?:(?:b(?:a(?:(?:ab)a|(?:aa|b(?:b|a))b)|b(?:b(?:(?:b|a)(?:b|a))|a(?:bb)))|a(?:(?:b(?:ba|bb)|a(?:bb))b|(?:(?:(?:b|a)b|aa)a)a))b|(?:(?:a(?:(?:ab|(?:b|a)a)b|(?:ab|ba)a)|b(?:(?:(?:b|a)(?:b|a))a|(?:ab|aa)b))a|(?:a(?:a(?:ab)|b(?:(?:b|a)b|aa))|b(?:b(?:ba|bb)|a(?:bb)))b)a)b)))(?:(?:b(?:b(?:(?:b(?:(?:(?:ab|aa)b|(?:ab|bb)a)b|(?:(?:ba|bb)b|(?:ab|bb)a)a)|a(?:(?:a(?:ab)|b(?:ba|bb))b|(?:b(?:ab|aa)|a(?:aa|b(?:b|a)))a))a|(?:b(?:a(?:(?:b|a)(?:(?:b|a)b|aa))|b(?:a(?:ab|bb)|b(?:aa|b(?:b|a))))|a(?:(?:(?:ab|aa)(?:b|a))a|(?:(?:aa)b|(?:ab|aa)a)b))b)|a(?:(?:b(?:(?:(?:ba|bb)b|(?:ab|bb)a)b|(?:a(?:(?:b|a)b|aa)|b(?:ab|ba))a)|a(?:a(?:(?:ab|bb)a|(?:(?:b|a)(?:b|a))b)|b(?:(?:ab|aa)(?:b|a))))b|(?:b(?:(?:(?:(?:b|a)(?:b|a))a|(?:bb)b)b|(?:(?:ab)a|(?:ab)b)a)|a(?:a(?:(?:ab|aa)a)|b(?:b(?:(?:b|a)(?:b|a))|a(?:bb))))a))|a(?:(?:a(?:(?:(?:a(?:ab|aa)|b(?:ab|(?:b|a)a))a|(?:b(?:ab)|a(?:ab|ba))b)b|(?:(?:(?:bb|aa)a)a|(?:(?:b|a)(?:ab|(?:b|a)a))b)a)|b(?:b(?:(?:a(?:ab))b|(?:b(?:(?:b|a)b|aa)|a(?:bb|aa))a)|a(?:b(?:b(?:bb|aa)|a(?:ba|bb))|a(?:(?:aa)a|(?:bb)b))))a|(?:(?:b(?:a(?:(?:ab)a|(?:aa|b(?:b|a))b)|b(?:b(?:(?:b|a)(?:b|a))|a(?:bb)))|a(?:(?:b(?:ba|bb)|a(?:bb))b|(?:(?:(?:b|a)b|aa)a)a))b|(?:(?:a(?:(?:ab|(?:b|a)a)b|(?:ab|ba)a)|b(?:(?:(?:b|a)(?:b|a))a|(?:ab|aa)b))a|(?:a(?:a(?:ab)|b(?:(?:b|a)b|aa))|b(?:b(?:ba|bb)|a(?:bb)))b)a)b))(?:a(?:a(?:(?:b(?:b(?:b(?:ab|aa)|a(?:ba|aa))|a(?:(?:b|a)(?:ab|bb)))|a(?:(?:b(?:ab|bb)|a(?:ab|aa))a|(?:(?:ab|bb)a|(?:ab|(?:b|a)a)b)b))b|(?:a(?:b(?:a(?:ab|aa)|b(?:(?:b|a)(?:b|a)))|a(?:a(?:bb)|b(?:aa)))|b(?:a(?:b(?:aa)|a(?:bb|aa))|b(?:b(?:(?:b|a)(?:b|a))|a(?:bb))))a)|b(?:a(?:a(?:(?:a(?:ba|(?:b|a)b)|b(?:ab|(?:b|a)a))a|(?:a(?:ab|ba)|b(?:ba|bb))b)|b(?:(?:b(?:ab)|a(?:ab|ba))b|(?:b(?:ab|ba)|a(?:ab|aa))a))|b(?:b(?:b(?:(?:(?:b|a)b|aa)a|(?:aa)b)|a(?:(?:ab|bb)a))|a(?:(?:(?:aa|b(?:b|a))b|(?:ab|ba)a)a|(?:a(?:ba|(?:b|a)b)|b(?:ab|(?:b|a)a))b))))|b(?:(?:(?:(?:(?:a(?:ab|aa)|b(?:(?:b|a)(?:b|a)))a|(?:a(?:aa)|b(?:aa))b)a|(?:b(?:a(?:ab|ba)|b(?:ba|bb))|a(?:a(?:ab|aa)|b(?:ab|(?:b|a)a)))b)b|(?:(?:b(?:(?:ab|ba)b|(?:ba|aa)a)|a(?:a(?:ab|ba)|b(?:aa|b(?:b|a))))b|(?:a(?:a(?:ab|ba)|b(?:aa|b(?:b|a)))|b(?:(?:ba|bb)a|(?:ab)b))a)a)a|(?:(?:(?:(?:(?:ba|bb)b|(?:bb)a)a|(?:b(?:ab|ba)|a(?:ab|bb))b)b|(?:a(?:a(?:(?:b|a)b|aa)|b(?:ab|ba))|b(?:(?:ab|bb)a|(?:ab)b))a)a|(?:(?:a(?:(?:ba|bb)a|(?:ab)b)|b(?:b(?:bb)|a(?:ba|bb)))a|(?:(?:b(?:ab)|a(?:ba))a|(?:(?:ab|ba)a|(?:ba|aa)b)b)b)b)b))))"
#2020-12-1911:42euccastrohere's mine (I don't have one for part 2 though)
#"^(a((b(b(a(baa|(ba|a(b|a))b)|b(bba|abb))|a(b(aba|baa)|a((aa|(b|a)b)b|(ba|(b|a)b)a)))|a(a((b(b|a)|aa)(b|a)b|((aa|(b|a)b)b|(ba|(b|a)b)a)a)|b(((aa|(b|a)b)b|(ba|a(b|a))a)b|(baa|(b(b|a)|aa)b)a)))a|((a((b|a)(aa|bb)a|(ba|a(b|a))(b|a)b)|b(((ba|a(b|a))b|(ab|aa)a)b|a(aa|(b|a)b)a))b|(((b(ab|ba)|a(aa|bb))a|(baa|(ba|a(b|a))b)b)a|(((aa|ba)b|aaa)b|((ba|a(b|a))b|aaa)a)b)a)b)|b(b((b(b(baa|(ba|a(b|a))b)|a(bbb|bba))|a(a(a(aa|ba)|b(ba|a(b|a)))|ba(aa|(b|a)b)))a|(((b(ba|(b|a)b)|a(ba|a(b|a)))b|(a(aa|bb)|b(bb|ba))a)a|(babb|a(bbb|abb))b)b)|a(((b((ab|ba)b|aaa)|a(b|a)(ba|a(b|a)))a|((baa|(b(b|a)|aa)b)a|(bb|ba)bb)b)b|(((b|a)(ba|(b|a)b)a|bbab)a|(a((ab|ba)b|(ba|a(b|a))a)|b((ab|ba)b|(b(b|a)|aa)a))b)a)))(a((b(b(a(baa|(ba|a(b|a))b)|b(bba|abb))|a(b(aba|baa)|a((aa|(b|a)b)b|(ba|(b|a)b)a)))|a(a((b(b|a)|aa)(b|a)b|((aa|(b|a)b)b|(ba|(b|a)b)a)a)|b(((aa|(b|a)b)b|(ba|a(b|a))a)b|(baa|(b(b|a)|aa)b)a)))a|((a((b|a)(aa|bb)a|(ba|a(b|a))(b|a)b)|b(((ba|a(b|a))b|(ab|aa)a)b|a(aa|(b|a)b)a))b|(((b(ab|ba)|a(aa|bb))a|(baa|(ba|a(b|a))b)b)a|(((aa|ba)b|aaa)b|((ba|a(b|a))b|aaa)a)b)a)b)|b(b((b(b(baa|(ba|a(b|a))b)|a(bbb|bba))|a(a(a(aa|ba)|b(ba|a(b|a)))|ba(aa|(b|a)b)))a|(((b(ba|(b|a)b)|a(ba|a(b|a)))b|(a(aa|bb)|b(bb|ba))a)a|(babb|a(bbb|abb))b)b)|a(((b((ab|ba)b|aaa)|a(b|a)(ba|a(b|a)))a|((baa|(b(b|a)|aa)b)a|(bb|ba)bb)b)b|(((b|a)(ba|(b|a)b)a|bbab)a|(a((ab|ba)b|(ba|a(b|a))a)|b((ab|ba)b|(b(b|a)|aa)a))b)a)))(b(((b(b((b|a)(b|a)a|(b(b|a)|aa)b)|a(b|a)(ba|a(b|a)))|a((bba|a(b(b|a)|aa))a|((b|a)(b|a)a|(ab|aa)b)b))b|(b(b(aab|(ab|aa)a)|a((ab|ba)a|bbb))|a(a(bbb|abb)|b((aa|bb)b|(ba|(b|a)b)a)))a)b|((b(b((ab|aa)a|(aa|bb)b)|a(a(aa|(b|a)b)|b(bb|ba)))|a((b|a)(aa|bb)b|(abb|bab)a))b|(b(((ab|ba)b|(bb|ba)a)a|(a(bb|ba)|b(b(b|a)|aa))b)|a(a(aaa|(b|a)(b|a)b)|b((aa|(b|a)b)b|aaa)))a)a)|a(a(b((a(a(aa|ba)|b(ba|a(b|a)))|b(bba|(aa|(b|a)b)b))b|((bba|bab)b|(bba|a(b(b|a)|aa))a)a)|a((a(bb|ba)b|(aaa|bab)a)a|(aba|baa)(b|a)b))|b(((((bb|ba)a|bbb)b|(aba|b(b|a)(b|a))a)b|(b(b(b|a)(b|a)|a(ba|(b|a)b))|aa(aa|(b|a)b))a)b|((((ba|(b|a)b)b|aba)b|(a(ba|(b|a)b)|b(bb|ba))a)b|((b(b(b|a)|aa)|a(aa|ba))a|((ab|ba)b|(bb|ba)a)b)a)a)))$"
#2020-12-1911:42euccastroso did yours work without anchoring?#2020-12-1911:45euccastroaaaand yes, I guess I should make my groups non-capturing 🙂#2020-12-1919:25Aleks#2020-12-1923:02euccastrohow did you create that visualization?#2020-12-1923:46AdamI don't think it's possible to create a regular expression to solve part 2, because the rule:
11: 42 31 | 42 11 31
requires matching n times whatever rule 42 matches followed by n times whatever rule 31 matches. If n is not known, then the language described by this rule is not regular, as it would require a "memory" (i.e. a stack) to keep track of how many instances of rule 42 have already been observed.
(Your input may differ, but if you have a rule of the same "shape" the same logic applies)#2020-12-2216:12erwinrooijakkers@U067R559Q did you generate that regex??#2020-12-2217:36Aleks> how did you create that visualization?
@U65FN6WL9 https://regexper.com/#2020-12-2217:39Aleks@U2PGHFU5U hahaha, did it by hands
https://media.giphy.com/media/lCbSAbRrFEfkY/giphy.gif#2020-12-2218:08Aleks@U01GG79SA00 you’re right, it’s not possible at least in Clojure/Java. But there is a trick I used. You aren’t asked to solve general problem, what they ask is to solve a given input. In the end, I generated a regex for the part 2, which searches only five levels down.#2020-12-1910:20mishayou got to do what you got to do©#2020-12-1916:11Vincent CantinInstaparse can start at any rule, there is an option for that.
(insta/parser new-grammar :start :rule0)
#2020-12-1917:49rjrayYeah, I’ve now learned that I didn’t need to do any of the pre-processing to the rules. I wonder if Wastl knew about Clojure+Instaparse 🙂.#2020-12-1918:02curlyfryInstaparse was so so helpful when I built this old thing (about four years ago 😮) https://www.imperimetric.com/ I felt pretty dumb when I didn't use it for day 18 when I had used it so much before#2020-12-1918:02curlyfryThe grammars: https://github.com/Dexterminator/imperimetric/tree/master/src/clj/imperimetric/grammars#2020-12-1919:33mishaI did (str "S = 0\n" input)
#2020-12-1919:36mishabtw: https://akovantsev.github.io/corpus/clojure-slack/instaparse#t1582822396013800#2020-12-1919:36mishahttp://instaparse-live.matt.is/#2020-12-1922:41JoeHas anyone else seen https://www.youtube.com/watch?v=Ren_QQHM3iI Livecoding Clojure AOC?#2020-12-1923:06JoeI'd be interested in peoples thoughts. I found the results not as elegant as some of the solutions here.#2020-12-2000:07MnoHe's definitely not doing the most elegant, fancy, super smart solution and you can tell he Clojure isn't his strongest language, but he does go through most of his process step by step in a pretty entertaining way, so I definitely like seeing how he thinks through stuff.#2020-12-2000:09Mno9/10 recommendation because of the didactic part for more people that are newer to clojure#2020-12-2000:21JoeYeah, Martin has a long history of OO and Java. I think his move to clojure is relatively recent. But he’s made some quite strong statements about its good qualities. #2020-12-1922:44MnoOohh that's real nice#2020-12-2005:02Vincent CantinI think I will take the slow path and use insta-image, to learn a few new things.#2020-12-2005:54euccastroheheh, I took a shortcut for part 1 which is useless for part 2...#2020-12-2005:55euccastronow I have all work ahead of me#2020-12-2006:12Aleksstats so far
20 91 1620 **
#2020-12-2006:22Vincent CantinI am still on part1, that’s difficult.#2020-12-2006:54rjrayI've managed part 1, but also used a math shortcut and now have to start over for part 2.#2020-12-2008:15Vincent CantinDay 20 answers thread - Post your answers here#2020-12-2008:36Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_20.clj#2020-12-2012:21JoeIt seems like every border can have at most 1 possible partner. I guess that simplifies the problem to 'find the match to this edge' from 'find all possible matches for this edge, then find the only possible solution considering all possible combinations'#2020-12-2013:32AleksYou’d better not see my code today :)))#2020-12-2013:35Vincent CantinPlease share ~ it’s fine#2020-12-2013:36AleksI need to clean it up first.#2020-12-2014:34petercAll the images have either 2, 3 or 4 matching sides. Part 1: Corners are the ones with only 2 matching sides. Part 2: Couldn't find any tricks beside the fact there is only one possible solution. Surprised that the result came out really quickly though.#2020-12-2015:12euccastrohttps://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day20.clj#2020-12-2015:15euccastroruns in 91 msecs, could probably get it much lower since at some point I stopped bothering with optimizations#2020-12-2016:11peterchttps://github.com/peterhhchan/aoc2020/blob/main/src/aoc2020/day20.clj under 400ms. could probably speed up the solution by considering only edges and solving inwards, but thats too much work#2020-12-2016:23euccastrotip: in https://github.com/peterhhchan/aoc2020/blob/main/src/aoc2020/day20.clj#L123 you don't need to (remove nil)
if you use :when
in the for bindings instead of when
in the body#2020-12-2017:01nbardiukslow and long https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day20.clj#2020-12-2019:32AleksWith some magic numbers, hope I will refactor it later
https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_20.clj#2020-12-2023:19mishano core.logic solutions yet?#2020-12-2100:46euccastroI have cleaned up my solution significantly and added comments, if anyone is interested. after doing that I'm actually quite satisfied with it, despite the biggish function at the end#2020-12-2121:23erwinrooijakkersOne ugly but practical way to solve it is by counting the heads visible in your input, get the images (without borders) to count total number of #
and do:
(def char-count-sea-monster
15)
(def sea-monster-count-guess
23)
(- total-hashes (* char-count-sea-monster sea-monster-count-guess))
;; => 1576
#2020-12-2200:34rjrayFinally got part 2 done. Damn.
https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day20.clj#2020-12-2008:35fingertoeTook a few days off — quite a ways into part one of day 20.. Itching to use some datalog..#2020-12-2008:37Vincent CantinIf you can do it using Datalog, I will definitely learn something new.#2020-12-2008:49Vincent CantinToday’s puzzle is an endurance test.#2020-12-2010:28Vincent CantinI don’t see a lot of activity and I wonder if people are still trying to solve the puzzle or if they took a break.#2020-12-2010:31MnoWeekends be like that#2020-12-2010:32MnoIn my particular case I'm a bit far behind, and I'm saving a few to warm up for upcoming interviews#2020-12-2010:34euccastroI'm being interrupted a lot, but still soldiering on :)#2020-12-2022:37euccastrosome of my breakthroughs happened during those interruptions, so I can't complain#2020-12-2011:08nbardiukI've managed to do only part 1 in the morning, will try to finish second part in the evening#2020-12-2011:40Charles FourdrignierPart 1 was """easy""".
But when the part 2 seems having 3 parts, it's a bit terrific.#2020-12-2013:34AleksHere they go#2020-12-2013:40euccastroOK, got the map resolved and stitched, now to look for monsters 😛#2020-12-2014:49euccastrofound monsters in both the demo and real input, and my dash calculation works for the demo input, but somehow is too high for the real input 😕#2020-12-2015:11euccastrofinally!#2020-12-2015:18benoitI'm skipping this one. It already took me too much time.#2020-12-2015:21euccastroI'll do the rest of the puzzles on the holidays since I can't afford to spend this much time on workdays#2020-12-2015:26Vincent CantinTomorrow's problem could also be short - we don't know yet.#2020-12-2016:29euccastrocould be... but puzzles get revealed at 6AM my time, and I need to catch up on sleep too 🙂#2020-12-2016:33euccastromy solution2
function is really monstrous, keeping with the challenge theme, but https://github.com/Saikyun/miracle.save made it relatively easy to debug. It lets you work as if the definitions in the local let
were module-level (so you can just evaluate forms inside the function).
https://github.com/vvvvalvalval/scope-capture is a more powerful alternative, but I find it harder to remember how to use it#2020-12-2016:47misha@vincent.cantin why do you have only 4+4 card variants?
are you flipping only vertically?
I got 16:#2020-12-2016:48misha(defn flip [s] (-> s reverse str/join))
(defn flip-hor [[t r b l]] [(flip t) l (flip b) r])
(defn flip-ver [[t r b l]] [b (flip r) t (flip l)])
(defn turn-lef [[t r b l]] [r b l t])
(defn turn-rig [[t r b l]] [l t r b])
(def mops
(->>
[flip-hor flip-ver turn-lef turn-rig]
(map memoize)
(apply juxt)))
(defn transformations [edges]
(->> #{edges}
(iterate (fn [variants]
(->> variants
(map mops)
(reduce into variants))))
(partition 2)
(drop-while #(apply not= %))
(ffirst)))
(def edges ["...#.#.#.#" "#..#......" ".#....####" "#.##...##."])
(->> edges transformations)
=>
#{["#.#.#.#..." "......#..#" "####....#." ".##...##.#"]
[".#....####" "#.##...##." "...#.#.#.#" "#..#......"]
["#.#.#.#..." "#.##...##." "####....#." "#..#......"]
["......#..#" "...#.#.#.#" ".##...##.#" ".#....####"]
["#.##...##." "...#.#.#.#" "#..#......" ".#....####"]
["####....#." "#..#......" "#.#.#.#..." "#.##...##."]
["####....#." ".##...##.#" "#.#.#.#..." "......#..#"]
["...#.#.#.#" ".##...##.#" ".#....####" "......#..#"]
[".#....####" "......#..#" "...#.#.#.#" ".##...##.#"]
["#..#......" ".#....####" "#.##...##." "...#.#.#.#"]
["......#..#" "####....#." ".##...##.#" "#.#.#.#..."]
["...#.#.#.#" "#..#......" ".#....####" "#.##...##."]
["#.##...##." "####....#." "#..#......" "#.#.#.#..."]
["#..#......" "#.#.#.#..." "#.##...##." "####....#."]
[".##...##.#" ".#....####" "......#..#" "...#.#.#.#"]
[".##...##.#" "#.#.#.#..." "......#..#" "####....#."]}
#2020-12-2016:58Aleksthat’s enough to check#2020-12-2017:00AleksFirst you rotate a piece (4 times), it’s not matched, you flip it and do rotation again (+ 4). That’s all possible combinations.#2020-12-2017:02AleksDoesn’t matter how you flip it vertically or horizontally.#2020-12-2017:32mishaall possible are shown above: 16, no?#2020-12-2017:32misha(admittedly, those are after multiple manipulations)#2020-12-2017:34mishaunless rotated and flipped to a random orientation.
means "rotated once then flipped once", and not "rotated, flipped, rotated again, flipped again.. etc"#2020-12-2017:51Aleks(def tile [[1 2 3]
[3 4 5]
[6 7 9]])
(take 4 (iterate rotate tile))
([[1 2 3]
[3 4 5]
[6 7 9]]
[[6 3 1]
[7 4 2]
[9 5 3]]
[[9 7 6]
[5 4 3]
[3 2 1]]
[[3 5 9]
[2 4 7]
[1 3 6]])
(take 4 (iterate rotate (flip tile)))
([[6 7 9]
[3 4 5]
[1 2 3]]
[[1 3 6]
[2 4 7]
[3 5 9]]
[[3 2 1]
[5 4 3]
[9 7 6]]
[[9 5 3]
[7 4 2]
[6 3 1]])
#2020-12-2017:52petercYou can pick up a piece of paper and see there are only 8 orientations#2020-12-2017:53AleksEven better you can pick up a real puzzle piece#2020-12-2018:02nbardiukI also had doubts, but then called a set
an all flips and rotations and it was just 8#2020-12-2018:21mishamy set has 16 d#2020-12-2018:21mishaanyway, it seems like 1 flip + 1 rotation#2020-12-2018:38markw@misha unlikely it’s your problem, but I also had 16 at first… I was adding back the original, unmodified grid at the end, and forgot to wrap it in []
when concatting with the list of rotation/flips, which added each individual row (rookie mistake I know)#2020-12-2018:55markwalso, I think taking the set of rotations/flips will result in a variable number, since sometimes there is symmetry in the input. For example flipping:
[["*" " " " "]
["*" "*" "*"]
["*" " " " "]]
the top-bottom rotations will be the same.#2020-12-2018:56JoeIf you have the 8 basic symmetries of a square (4x rotational, 4x reflection), then any combination of these of the operations can be simplified to any of the basic 8.#2020-12-2019:02mishafound it:
(defn flip-hor [[t r b l]] [(flip t) l (flip b) r])
(defn flip-ver [[t r b l]] [b (flip r) t (flip l)])
(defn turn-lef [[t r b l]] [r b l t])
(defn turn-rig [[t r b l]] [l t r b])
->>
(defn flip-hor [[t r b l]] [(flip t) l (flip b) r])
(defn flip-ver [[t r b l]] [b (flip r) t (flip l)])
(defn turn-lef [[t r b l]] [r (flip b) l (flip t)])
(defn turn-rig [[t r b l]] [(flip l) t (flip r) b])
harold#2021-11-3005:40Daniel AmberYeah this would be rad! I’ll try my hardest to get a video out on this 🙂#2021-11-2916:00roelofI read on reddit some guy who did that last year and that makes me curious to try to learn clojure again#2021-11-2916:00roelof@pez#2021-11-2919:05tschadycomparing your solution to others’ in this channel on toy problems is a great way to learn#2021-11-3015:45ChaseI've been doing some old AOC problems as a warmup and am confused about why my solution for Year 2015, Day 3 isn't working. https://adventofcode.com/2015/day/3#2021-11-3015:46Chase(ns aoc.2015.day-03)
(def input
(slurp "resources/2015/day_03.txt"))
(def direction->move
{\^ [1, 0]
\v [-1, 0]
\> [0, 1]
\< [0, -1]})
(def moves
(map direction->move input))
(defn part-1 [moves]
(loop [moves moves
current [0 0]
visited #{current}]
(if (seq? moves)
(let [[x y] current
[x-delta y-delta] (first moves)
next-house [(+ x x-delta) (+ y y-delta)]]
(recur (rest moves) next-house (conj visited next-house)))
(count visited))))
(part-1 moves)
#2021-11-3015:46ChaseThis is the error I get:
; eval (root-form): (part-1 moves)
; (err) Execution error (NullPointerException) at aoc.2015.day-03/part-1 (REPL:22).
; (err) Cannot invoke "Object.getClass()" because "x" is null
#2021-11-3015:47ChaseWhen I evaluate moves
I get a seq of vecs like so:
(take 5 moves) => ([0 1] [1 0] [1 0] [-1 0] [1 0])
#2021-11-3015:48ChaseSo I'm not sure where this whole null
thing is coming from. Any tips?#2021-11-3016:00potetmis there a dangling newline in input
or something?#2021-11-3016:01ChaseI was thinking something like that could be happening but (last moves)
gives me [0 -1]
#2021-11-3016:01potetm(remove some? input)
#2021-11-3016:02potetmalternatively, (remove some? moves)
#2021-11-3016:03Chasethat is giving me an empty seq...#2021-11-3016:04potetmoh lol#2021-11-3016:05potetm(seq? (rest '([1 0]))) => ?
#2021-11-3016:08Chasehmmm, so that is evaluating to true huh#2021-11-3016:08Chasebut I would want that to be false right? I'm confused. haha. I thought it was idiomatic to use seq?
in the if conditional on ... seqs#2021-11-3016:10potetmYou’re looking for seq
I think.#2021-11-3016:10Chaseoh wait... it's idiomatic to use seq
not seq?
huh? lol. D'oh!#2021-11-3016:10potetm😄#2021-11-3016:11ChaseThis is what I get for having to leave clojure for a few months#2021-11-3016:12Chaseso what do you think of that solution (it works now btw)? I still struggle turning that whole loop/recur approach into a reduce (or better?) approach.#2021-11-3016:12ChaseI remember a year where you did some awesome videos going through that process#2021-11-3016:18potetmIt’s still up! https://potetm.com/video/aoc-2018-d01.html#2021-11-3016:18potetmI happened to have recently done most of the the 2015 problems. Let me get mine real quick.#2021-11-3016:19potetmaaah yeah#2021-11-3016:20potetmYou want me to just post my solution here?#2021-11-3016:21ChaseYeah, that would be great. Just for part 1 please. I'm about to tackle part-2.#2021-11-3016:22potetmHmmm… my part-1 basically covers part 2#2021-11-3016:22potetmAlternatively, I can give you some kind of hint if you prefer.#2021-11-3016:24potetmwhy not both?#2021-11-3016:24ChaseLet's do it. I already finished part-2 anyways.#2021-11-3016:25tschadyhere’s mine:
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2015/d03.clj#2021-11-3016:25ChaseI broke out part-1 into a separate function to give me the set of houses visited so then my part-2 becomes:
(defn part-2 [moves]
(let [santa-moves (take-nth 2 moves)
robo-moves (take-nth 2 (rest moves))
santa-houses-visited (houses-visited santa-moves)
robo-houses-visited (houses-visited robo-moves)]
(count (clojure.set/union santa-houses-visited robo-houses-visited))))
#2021-11-3016:26potetmYou can go here for my full solution to both parts: https://github.com/potetm/advent-of-code/blob/master/src/advent_2015/day_3.clj#2021-11-3016:27tschadysame idea#2021-11-3016:27potetmBut there are some fundamental questions you can ask yourself when trying to figure out whether you need recursion or reduction or sequence fns.#2021-11-3016:30potetm1. Am I working on a collection?
a. If yes, then you can maybe reduce or sequence fns
b. If no, then you either need loop/recur or iterate
2. Do I need to track state across members of the collection?
a. If yes, then you either need reduction or partition
b. If no, then you can use sequence fns
3. Do I need to control flow?
a. If yes, then you probably need loop/recur
b. If no, then you can use reduction#2021-11-3016:31potetmIn this case, you’re working on a collection, you do need to track state, but you don’t need to control flow (because you’re just going to process the entire input collection).#2021-11-3016:31potetmSo you know immediately that reduction is applicable.#2021-11-3016:31ChaseI like this!#2021-11-3016:31potetmThe only thing you might not know is there is a function reductions
which will give you every intermediate state of a reduce operation.#2021-11-3016:32ChaseI actually used reductions
for day-1 but still it didn't occur to me to use that one here. I imagine it is quite useful.#2021-11-3016:33potetm(fwiw reductions
and iterate
are extremely useful for AoC and basically useless in every other context :D)#2021-11-3016:34Chasedefn part-2 [directions]
(let [current-floor (reductions + directions)]
(inc
(.indexOf current-floor -1))))
#2021-11-3016:34Chaseit definitely made that one easy#2021-11-3016:34Chasenow I'm even more excited for AOC (well the first week at least before I burn out, lol) so I can get more tips like this#2021-11-3016:35potetm😄 I’m not sure I plan on keeping up at all this year.#2021-11-3016:35potetmHonestly, I didn’t even know .indexOf
was implemented on sequences. That’s a good tip!#2021-11-3016:38ChaseYeah I thought that was nifty. So in my solution though, I am processing the whole sequence first and then checking to see where the -1
is right? Is that a lot worse than continually checking for the solution as it's processing through lazily? Does that question make sense? haha#2021-11-3016:39potetmYeah that makes sense. The only way to know is to implement the lazy version and time it.#2021-11-3016:40potetmIf you really wanna know, you give the JIT time to warm up by running in a loop: https://github.com/potetm/advent-of-code/blob/master/src/advent/util.clj#L43-L62#2021-11-3016:41potetmBut for AoC, I generally take the attitude of, “If it finishes in a few seconds, it’s fine.”#2021-11-3016:42ChaseYep. haha. The repl returns the answer immediately so that's good for me.#2021-11-3016:43ChaseFun chat. Thanks for rubber ducking that issue with me. I felt my logic was solid so I was pulling my hair out a bit#2021-11-3016:44potetmYeah man, feel free to reach out again! It was fun for me as well.#2021-11-3019:17cdeszaqWhile not as terse as some other solutions, here’s my 2015 Day 3 as well, for comparison: https://github.com/cdeszaq-org/adventofcode/blob/main/src/com/cdeszaq/adventofcode/twenty15/day3.cljs#L13-L37
Uses reductions
as well and looks to be largely the same as some others, but makes liberal use of thread macros and named functions to break up the logic.#2021-11-3019:34potetm#nomorethreaders #nomorenames#2021-11-3018:26rjraySadly, I won’t be able to take part this year. Grad school (MSCS program), with a major project due on the 12th and a final exam on the 17th. 😞.#2021-11-3018:52tschadyin my day, that would guarantee i finish AoC 😬#2021-11-3018:53tschadymega nerd snipe#2021-11-3019:33pezI like how this channel awakens to the occasion. #2021-11-3019:41Antonio BibianoHello peeps 🙂 i was trying to re-do some problems from last year and when I try this#2021-11-3019:41Antonio Bibiano(time
(first
(for [x entries
y entries
:let [z (- 2020 x y)]
:when (< x y z)
:when (contains? entries z)]
(* x y z))))
#2021-11-3019:42Antonio Bibianoit finishes in 22 ms#2021-11-3019:42Antonio Bibianowithout first it finishes in less under 1 ms#2021-11-3019:43Antonio BibianoIs the difference because the repl takes care of printing the resulting LazySeq and so it's not counted in the time
calls?#2021-11-3019:45potetmSort of.#2021-11-3019:45potetmWhen you call first
you realize the first element of the sequence.#2021-11-3019:46potetmWhen you do not call first
you realize none of the sequence.#2021-11-3020:01Antonio Bibianonice I was a bit confused because i actually saw the result 😄#2021-12-0109:41delaguardoActually, because of chunking, you realize first 32 elements when you call first.#2021-12-0114:51potetmActually, no.#2021-12-0114:52potetmfor
returns a LazySeq
which isn’t chunked.#2021-12-0116:13delaguardouser=> (first (for [x (range 1000)] (do (prn x) x)))
0
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
0
#2021-12-0116:57potetm(first
(for [i (range)]
(do (prn i)
(inc i))))
0
=> 1
#2021-12-0117:08delaguardomy point is that for
might realize more than needed because of chunking.#2021-12-0117:09potetmYou did not say, “might.”#2021-12-0117:11delaguardoyeah, sorry )#2021-12-0119:05Antonio Bibianoand the difference here between @U04V4KLKC and @U07S8JGF7 output is due to what?#2021-12-0119:10potetm@U01HY37QQUA It’s called “chunking”#2021-12-0119:11potetmhttp://www.tianxiangxiong.com/2016/11/05/chunking-and-laziness-in-clojure.html#2021-12-0119:15Antonio Bibianoah so it's probably a different code path in for?#2021-12-0119:22Antonio Bibiano(chunked-seq? (range)) => false
(chunked-seq? (range 1000)) => true
#2021-12-0119:23Antonio Bibianothere you have it#2021-12-0119:45potetmright#2021-11-3019:44potetm@nbardiuk Is the leaderboard not adventofcode-clojurians
?#2021-11-3019:44nbardiukI've just bumped the year 😅#2021-11-3019:45potetmah gotcha#2021-11-3019:45nbardiukI think that code references adventofcode-clojurians, let me check#2021-11-3019:46nbardiukyep, the 217019-4a55b8eb
is a code to join adventofcode-clojurians
private board#2021-11-3020:53Chaseso are these private leaderboards just tracking the time to complete like the main site? I don't get to them until 8-12 hours after they are posted.#2021-11-3020:55potetmyeah#2021-11-3020:56ChaseIt would be cool to get something that ran benchmarks for submitted solutions. I am inexperienced in benchmarking stuff so could be cool to explore as a project idea#2021-11-3021:58fingertoe@U9J50BY4C The really nice thing about the Clojure leaderboard isn't so much the scorekeeping -- It's that it often links to git repositories so you can compare methods used after you get done.. @U04V15CAJ did a benchmarked repo for CLJC a few years ago. It was kinda cool.#2021-11-3022:25Phil ShapiroI wrote this code last year to benchmark my solutions. Not general, but may be interesting to some. https://github.com/pshapiro4broad/advent2020/blob/main/src/main.clj
$ clj -X main/-main
day1/part1 : "Elapsed time: 38.363232 msecs"
day1/part2 : "Elapsed time: 976.244442 msecs"
day2/part1 : "Elapsed time: 12.697295 msecs"
day2/part2 : "Elapsed time: 6.865864 msecs"
day3/part1 : "Elapsed time: 1.519996 msecs"
day3/part2 : "Elapsed time: 2.062161 msecs"
...
#2021-11-3023:04Chase@U10B0BPJP that is a good feature. I signed up.#2021-12-0102:19tschadyI put my answers in tests then use a test runner that profiles. #2021-12-0105:25normanHooray - I actually remembered advent of code on the first day.#2021-12-0105:30R.A. PorterDay 1 Solutions 🧵#2021-12-0105:32R.A. PorterTook me twice as long as it could have because I forgot the pad
for partition
was a collection. But otherwise...just partitions and filters on comparisons.#2021-12-0105:37Chasehttps://github.com/Chase-Lambert/aoc-clojure/blob/main/src/aoc/2021/day_01.clj#2021-12-0105:40ChaseThat was exciting to be there at the start. I wasted a few minutes doing something dumb and ended up at like 4000th place which is probably the best spot I'll get. lol#2021-12-0105:41Chaseand already seeing some great clojure solutions on the reddit solution thread#2021-12-0105:41kpavhttps://github.com/kwpav/advent-of-code-2021/blob/master/src/advent_of_code_2021/day01.clj#2021-12-0105:45R.A. PorterGuess I should post mine. Elided the boilerplate of reading/parsing input.#2021-12-0106:31mchampine;; part1
(defn count-incs [nn]
(count (filter pos? (map - (rest nn) nn))))
(count-incs input) ;; => 1681
;; part2
;; sliding window size 3
(-> (map #(apply + %) (partition 3 1 input))
count-incs) ;; => 1704
#2021-12-0106:42peterc(defn part1 [data]
(->> (map - (rest data) data)
(filter pos?)
count))
(defn part2 [data]
(->> (map - (rest (drop 2 data)) data)
(filter pos?)
count))
#2021-12-0106:47nbardiukHappy to use clojure alpha with parse-long
in core
https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day01.clj#2021-12-0108:16Antonio Bibianovery similar to the others.. avoided some repetition#2021-12-0108:16Antonio Bibiano(defn part1 [input]
(->> input
(partition 2 1)
(filter #(apply < %))
count))
(defn part2 [input]
(->> input
(partition 3 1)
(map #(apply + %))
part1))
#2021-12-0108:52Adam Haber(->> l
(#(map < % (rest %)))
(filter identity)
count)
#2021-12-0108:52Adam Haber(->> l
(#(map + % (rest %) (rest (rest %))))
(#(map < % (rest %)))
(filter identity)
count)
#2021-12-0109:58StuartUsing my utility function that reads a file, splits it line by line and applies a parser function to each line.
(def puzzle-input "puzzle-inputs/2021/day1")
(defn calculate-increasing [xs]
(->> (map < xs (rest xs))
(filter true?)
(count)))
(defn parser [n]
(Integer/parseInt n))
;; Part 1
(->> (f/read-all-lines-and-parse puzzle-input parser)
calculate-increasing)
;; Part 2
(->> (f/read-all-lines-and-parse puzzle-input parser)
(partition 3 1)
(map #(reduce + %))
calculate-increasing)
Easy day 1. Don't know if that's a good sign or not 😆#2021-12-0110:52tschady(def input (file-util/read-ints "2021/d01.txt"))
(defn part-1 [input]
(count (filter pos? (map - (rest input) input))))
(defn part-2 [input]
(count (filter pos? (map - (drop 3 input) input))))
#2021-12-0111:03karlisStarting off easy 🙂
(defn increase-count [i] (count (filter true? (map < i (drop 1 i)))))
(def puzzle1 increase-count)
(defn puzzle2 [input]
(increase-count (map + input (drop 1 input) (drop 2 input))))
#2021-12-0113:10Felipeexact same solution as @U01HY37QQUA, minus the thread macros
(def input (map read-string (clojure.string/split-lines (slurp ""))))
(defn increases [coll] (count (filter #(apply < %) (partition 2 1 coll))))
;; part 1
(increases input)
;; part 2
(increases (map #(apply + %) (partition 3 1 input)))
#2021-12-0116:06ianjonesheh, some of y’alls solutions are so simple. Im new so I didnt know about partition facepalm
(defn add-not-nil [& col]
(when (not (some nil? col)) (reduce + col)))
(defn optimized [col]
(reduce-kv (fn [count index value]
(let [value2 (nth col (inc index) nil)
value3 (nth col (inc (inc index)) nil)
value4 (nth col (inc (inc (inc index))) nil)
window1 (add-not-nil value value2 value3)
window2 (add-not-nil value2 value3 value4)]
(if (and (not (nil? window1)) (not (nil? window2)))
(if (< window1 window2)
(inc count)
count)
count))) 0 col))
#2021-12-0116:53cyppanTried to go lazy using transducers (using this lib https://github.com/cgrand/xforms for the missing partition transducer from the core)#2021-12-0117:00pithyless@U0CL38MU1 xforms has an x/count
and x/lines-in
- ie. (x/count (comp ,,,) (xio/lines-in resource))
That way, you wouldn't need the with-open
, and returning and adding up the 1
's from keep
#2021-12-0117:01cyppanoh thanks ! 😄#2021-12-0117:05pithylessI'd also argue that this is a little misleading:
> Tried to go lazy using transducers
I think more appropriate would be
> Tried to go super-eager using transducers
😜#2021-12-0117:08cyppanyou’re absolutely right#2021-12-0117:27Sam AdamsMy HTML solution 😉: https://samadams.dev/2021/12/01/advent-of-code-day-1.html#2021-12-0118:07Andrew ByalaMy Clojure solution, including my https://github.com/abyala/advent-2021-clojure/blob/main/docs/day01.md about how I got there.#2021-12-0118:26raicotophttps://github.com/raicotop/advent-of-code-2021/blob/main/src/advent_of_code_2021/day-01.clj#2021-12-0119:21nooga(def input [ .. ])
(def solve #(->> (map < %1 (next %1)) (filter true?) count))
(println (solve input))
(println (->> input (partition 3 1) (map #(apply + %1)) solve))
#2021-12-0208:47kj(def input ...)
(defn count-increases
[coll n]
(->> (map < coll (drop n coll))
(filter true?)
count))
;; Part 1
(count-increases input 1)
;; Part 2
(count-increases input 3)
#2021-12-0223:38euccastrosolution to day1: https://github.com/euccastro/advent-of-code-2021/blob/main/day1.clj#2021-12-0306:08Cora (she/her)https://gist.github.com/corasaurus-hex/389968ca616083ba0feb630330ba1739#2021-12-0317:26Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/increases.clj#2021-12-0317:38Benjamin@U06B54Y95 that swag#2021-12-0621:40Tero Matinlassi(ns day1
(:require [clojure.string]))
(comment
; part 1
(->> "input"
slurp
clojure.string/split-lines
(map #(Integer/parseInt %))
(reduce (fn [[c a] b]
(if (> b a)
[(inc c) b]
[c b]))
[0 0])
first
dec)
;=> 1752
)
(defn sliding-window [s]
(partition 3 (interleave s (rest s) (rest (rest s)))))
(comment
; part 2
(->> "input"
slurp
clojure.string/split-lines
(map #(Integer/parseInt %))
sliding-window
(map #(reduce + %))
(reduce (fn [[c a] b]
(if (> b a)
[(inc c) b]
[c b]))
[0 0])
first
dec)
;=> 1781
)
#2021-12-1920:26Filip Strajnar(defn
by-indicies-2
[numbers]
(->> numbers count dec range (filter #(< (nth numbers %) (nth numbers (inc %)))) count))
#2021-12-1920:26Filip Strajnarthis is the 1st part, I'm looking for suggestions how to make it shorter#2021-12-2108:05Daniel Amber@U0ETXRFEW Only 20 days later 🙂
https://www.youtube.com/watch?v=q_I3r0JGhR8#2021-12-0106:11Vincent CantinGood morning everyone, and happy new AoC !
I won't compete on the clock this year, I chose to stream while slowly solving the problems in the hope of making more people discover Clojure.#2021-12-0106:12AleksMorning!#2021-12-0106:31roelofmorning , where can I find the stream and can I look to it when you have solved the challenges ?#2021-12-0106:31roelof@U8MJBRSR5#2021-12-0106:49nbardiukVincent streams on twitch https://www.twitch.tv/greencoder#2021-12-0106:57Vincent CantinI will start the stream in about 15 min#2021-12-0107:14roelofI wait#2021-12-0111:38roelof@U8MJBRSR5 thanks for the stream but I wonder for adding the three numbers . why not use reduce for it ?#2021-12-0111:48Vincent CantinWe could, but I tried to be accessible to a wider audience#2021-12-0111:49Vincent CantinI will mention it in tomorrow's stream. Thanks for mentioning it.#2021-12-0111:50roelofnp, just wondering#2021-12-0414:37roelofhe, no coding from @U8MJBRSR5?#2021-12-0418:02Vincent CantinI did it on Twitch, but late because of the reClojure conference#2021-12-0418:04roelofoke I will look it later#2021-12-0418:04roelofand hopefully learn from it#2021-12-0418:07roelof@U8MJBRSR5 are you french and live in Europe ?#2021-12-0420:11Vincent CantinI live in Taiwan :flag-tw:#2021-12-0420:12Vincent CantinMy repo for AoC 2021 is at https://github.com/green-coder/advent-of-code/tree/master/src/aoc_2021#2021-12-0420:35roelofoke, I asked because I think I heard a french acccent , I apolize#2021-12-0420:35roelof@U8MJBRSR5#2021-12-0421:25Vincent CantinFrench people in Taiwan do not lose their French accent 😁#2021-12-0508:27roelofcoulod be, was just curious @U8MJBRSR5#2021-12-0509:33Vincent CantinYes, I am French#2021-12-0106:53misha👋 opieop#2021-12-0112:49nooga👋 Happy AoC everyone!
This year I’m solving using my own Clojure(-like-language) implementation: https://github.com/nooga/let-go
Hoping to extend the core lib and weed out some bugs as I go through AoC problems 🙂
Funnily enough, let-go seems to outperform other implementations on simple programs since it has very minimal startup time:#2021-12-0119:01noogaspoiler!
not bad for a barebones interpreter huh?#2021-12-0119:57Stuartnice!#2021-12-0120:00noogaand since AoC is about collecting stars, I wouldn’t mind some github stars ⭐ 😁#2021-12-0113:58Stuarteither will work. I can't think of any reason why you would need clojure cli tools over lein#2021-12-0118:02Andrew Byala🧵 I had a simple question about something I've seen in a few solutions for Day 1 Part 2 today. Threading to avoid partial spoilers.#2021-12-0118:03Andrew ByalaIn my solution, when I created the sum of each three-tuple, I used
(map (partial apply +) triples)
,
but I've seen some folks use
(map (partial reduce +) triples)
. Both give the same answer, so how would you choose one over the other?#2021-12-0118:14pithyless> Threading to avoid partial spoilers.
Pun intended!#2021-12-0118:18nooga@U01HHBJ56J1 I think they’re roughly the same for small colls#2021-12-0118:19pithylessFrom just an aesthetics perspective, apply X
will work for any variadic function, but reduce X
will work any monoid. I originally wrote apply +
and then converted it to reduce +
for exactly that reason: I figured there are more monoids than variadic functions, so maybe that should be the default.#2021-12-0118:22tschadyI remember reduce
had significantly better benchmarks on larger colls.#2021-12-0119:06Andrew Byala@U05476190 - your first comment was terrible, and you just made a friend today.#2021-12-0119:09Andrew ByalaOk, so in instances when both would work, reduce
is the preferred operation, even if the performance doesn't matter for smaller collection sizes. So when would you ever choose apply
then?#2021-12-0119:27Antonio BibianoLooking at the source looks like reduce
is optimized for different types of collections while apply
is just a lot of calls to cons
#2021-12-0119:28Antonio Bibianoso I would imagine when you know that the collection is going to be quite small#2021-12-0119:43Antonio Bibianoor if you have to do it a lot of times! according to my not so advanced benchmarking skills#2021-12-0119:43Antonio Bibiano(time
(loop [n 0]
(when (< n 1000000)
(apply + '(1 2 3))
(recur (inc n)))))
#2021-12-0119:43Antonio Bibianotakes ~200 ms on my machine#2021-12-0119:44Antonio Bibianoswitching to reduce takes 45 ms#2021-12-0121:07ChaseI've always liked apply +
because I think it highlights a great benefit of the lisp notation where you can have variadic args to the +
function, etc.#2021-12-0121:08ChaseIn my head, that's what I want to use because that is how I mentally solve that particular use case but then in the back of my mind I know it is less performant than reduce
and I hate that. I don't why this bothers me so much. hahaha#2021-12-0121:09ChaseThat's one thing I appreciate in Rust. I think it allows me to write code the way I want to without punishing me on performance.#2021-12-0121:12pithyless@U01HY37QQUA it's good to reach for criterium
when you need to do some quick micro-benchmarking:
(require '[criterium.core :as criterium])
(criterium/with-progress-reporting
(criterium/bench
(reduce + '(1 2 3))
;; (apply + '(1 2 3))
))
#2021-12-0121:12pithylessOn my machine, it looks like this:
;; reduce
;; Execution time mean : 25.832360 ns
;; Execution time std-deviation : 0.751152 ns
;;
;; apply
;; Execution time mean : 169.971152 ns
;; Execution time std-deviation : 9.294313 ns
#2021-12-0121:13pithylessBut really, this is a microbenchmark that doesn't really mean anything unless we're in some performance critical code; and then you probably want to worry more about boxing and unchecked math ;)#2021-12-0122:09ChaseSomeone created and posted a great resource to explore the solution threads by computer language: https://aocweb.yulrizka.com/#2021-12-0122:10ChaseAPL is such a wild language#2021-12-0123:57StuartI take it APL needs you to be really familiar with keyboard shortcuts to input those weird characters into your IDE (do APL people use an IDE?)
Or a keyboard with custom keycaps ?#2021-12-0123:58noogaThe ones I’ve seen used only notepad 😛#2021-12-0200:01StuartI have a lot of text substitutions setup in my IDE (vs code), but I still type in regular clojure, its just displayed more concisely, I have no idea how I would even type in most of those APL characaters 😄#2021-12-0214:20Phil ShapiroYes, there's an APL IDE, https://www.dyalog.com/. The UI has a palette that contains all (most?) symbols, and each symbol has a two key shortcut.#2021-12-0204:58Aleks🧵 Day 2 answers thread: post your answers here#2021-12-0205:36R.A. PorterA bit inelegant, but it got the job done.#2021-12-0205:52AleksHere is mine
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_02.clj#2021-12-0206:35mchampineSome wasted effort using maps, and could be cleaner but it got the job done.#2021-12-0206:59tylerwHere’s mine:
(def input (->> (u/day-input-source 2)
(into [] (map (comp edn/read-string #(str "{:" % "}"))))))
(defn t1
[input]
(let [combined (reduce (fn [acc x] (merge-with + acc x)) input)
{:keys [forward up down]} combined]
(* forward (- down up))))
(defn t2
[input]
(let [f (fn [acc action]
(let [[direction x] (-> action seq first)]
(case direction
:down (update acc :aim + x)
:up (update acc :aim - x)
:forward (-> acc
(update :horiz + x)
(update :depth + (* (:aim acc) x))))))
init (zipmap [:horiz :depth :aim] (repeat 0))
{:keys [horiz depth]} (reduce f init input)]
(* horiz depth)))
#2021-12-0207:01raicotopMy solution using recursion: https://github.com/raicotop/advent-of-code-2021/blob/main/src/advent_of_code_2021/day-02.clj#2021-12-0208:02nbardiukMy first implementation was similar to alekszelark, this one is already refactored https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day02.clj#2021-12-0208:44Antonio BibianoI also went with a vector instead of a map because I think the argument destructuring makes it quite clear anyway
(defn answer [[distance depth]]
(* distance depth))
(answer
(reduce
(fn [[distance depth] [direction step]]
(case direction
:forward [(+ distance step) depth]
:down [distance (+ depth step)]
:up [distance (- depth step)]))
[0 0]
input))
(answer
(reduce
(fn [[distance depth aim] [direction step]]
(case direction
:forward [(+ distance step) (+ depth (* aim step)) aim]
:down [distance depth (+ aim step)]
:up [distance depth (- aim step)]))
[0 0 0]
input))
#2021-12-0208:47Callum Oakleypart-2 aim is identical to part-1 depth, so the same reduction works for both
(defn parse [s]
(->> s (re-seq #"\w+") (map read-string) (partition 2)))
;; This covers parts 1 and 2: for part-1 treat aim as depth and ignore dep
(defn dive [commands]
(reduce (fn [[hor aim dep] [op x]]
(case op
forward [(+ hor x) aim (+ (* aim x) dep)]
down [hor (+ aim x) dep]
up [hor (- aim x) dep]))
[0 0 0]
commands))
(defn part-1 []
(let [[hor dep _] (->> "input/2021/02" slurp parse dive)]
(* hor dep)))
(defn part-2 []
(let [[hor _ dep] (->> "input/2021/02" slurp parse dive)]
(* hor dep)))
#2021-12-0208:51ajk(defn parse-input [input]
(map (fn [line]
(let [[direction amount] (string/split line #" ")]
[(keyword direction)
(Integer/parseInt amount)]))
(string/split-lines input)))
(def input (parse-input (slurp "aoc-day-2.txt")))
(defn part-one [commands]
(loop [commands commands
horizontal-position 0
vertical-position 0]
(if-let [[direction amount] (first commands)]
(case direction
:forward (recur (rest commands)
(+ horizontal-position amount)
vertical-position)
:up (recur (rest commands)
horizontal-position
(- vertical-position amount))
:down (recur (rest commands)
horizontal-position
(+ vertical-position amount)))
(* horizontal-position vertical-position))))
(defn part-two [commands]
(loop [commands commands
aim 0
horizontal-position 0
depth 0]
(if-let [[direction amount] (first commands)]
(case direction
:forward (recur (rest commands)
aim
(+ horizontal-position amount)
(+ depth (* amount aim)))
:up (recur (rest commands)
(- aim amount)
horizontal-position
depth)
:down (recur (rest commands)
(+ aim amount)
horizontal-position
depth))
(* horizontal-position depth))))
#2021-12-0209:00borkdudehttps://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_02-clj#2021-12-0209:39Stuart(defn parser [l]
(let [[dir v] (str/split l #" ")]
{:dir dir
:v (Integer/parseInt v)}))
; part 1
(->> (f/read-all-lines-and-parse puzzle-input parser)
(reduce (fn [[x y] {:keys [dir v]}]
(condp = dir
"forward" [(+ x v) y]
"up" [x (- y v)]
"down" [x (+ y v)])) [0 0])
(reduce * 1))
; part 2
(->> (f/read-all-lines-and-parse puzzle-input parser)
(reduce (fn [[x y aim] {:keys [dir v]}]
(condp = dir
"forward" [(+ x v) (+ y (* aim v)) aim]
"up" [x y (- aim v)]
"down" [x y (+ aim v)])) [0 0 0])
(take 2)
(reduce * 1))
#2021-12-0210:50Joehttps://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day02.clj
(defn parse [line]
(let [x (Long/parseLong (re-find #"\d+" line))]
(case (first line)
\f [x 0]
\u [0 (- x)]
\d [0 x])))
(->> input
(map parse)
(apply map +)
(apply *))
;; => 2073315
(defn proc [[x y aim] [p d-aim]]
[(+ x p)
(+ y (* p aim))
(+ aim d-aim)])
(->> input
(map parse)
(reduce proc [0 0 0])
(take 2)
(apply *))
;; => 1840311528
#2021-12-0210:57Antonio BibianoWhat do you think about parsing the file like this:
(->> "path"
slurp
(format "{%s}")
read-string)
#2021-12-0210:59StuartAs I understand it, its probably fine for Advent of Code, but you wouldn't want to read untrusted input with (read-string)
in real world stuff as it can execute code.#2021-12-0211:02Antonio Bibianoah right! it's right there in the docs :man-facepalming:#2021-12-0211:09nbardiukAs I understand clojure.edn/read-string
is safer alternative and works for AoC fine since input is just data, no function definitions, etc.#2021-12-0211:23noogaI’m just pasting the input data directly into my code i.e. (def input '(..data here..))
😄#2021-12-0211:58tschadyhttps://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d02.clj
same as @U01HL2S0X71#2021-12-0212:36genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day02.clj#2021-12-0212:38genmeblogbtw. thanks @borkdude, I learned that case
works on symbols without quoting...#2021-12-0214:11potetmhttps://github.com/potetm/advent-of-code/blob/master/src/advent_2021/day_2.clj#2021-12-0214:16potetmInteresting to see everyone’s slight variations on the exact same thing 😄#2021-12-0214:17potetm@U0105JJK1L3 Did one novel thing in that he resolved to a direction tuple (e.g. [-1 0]
) in the first step, which eliminated later switches.#2021-12-0214:18potetmAlso good to see how much mine looks like @borkdude’s. Apparently I’m not too far off the beaten path 😄#2021-12-0214:37ianjonesheres my solution https://github.com/theianjones/aoc_2021/blob/master/src/theianjones/aoc-2021/d02/answer.clj#2021-12-0214:58Felipe Cortezsame as everyone else's
https://github.com/FelipeCortez/advent-of-code/blob/master/2021/02.clj#2021-12-0214:59StuartHow do people decide wether to use case
, cond
or condp
?#2021-12-0215:00potetmcase
- closed value dispatch
cond
- conditional logic dispatch
condp
- never#2021-12-0215:00Felipe Cortezhaven't profiled it, but I imagine case is always faster so I use it when I can, cond when case isn't enough, condp when cond isn't enough condp when it's cleaner than cond#2021-12-0215:00borkdudeI considered making the most hacky version for 2 day by rewriting the input to s-expressions, (forward 2)
, etc and then making functions for forward
, etc so I could just run the program. ;)#2021-12-0215:01potetmI literally have no idea what condp
is good for.#2021-12-0215:01borkdudeI never use condp
, it's dead to me ;)#2021-12-0215:01potetmsame#2021-12-0215:01Felipe Cortez@borkdude same! (wrt the lispy rewriting)#2021-12-0215:01potetmI’ve seen people who make messes use it. But that’s it.#2021-12-0215:02potetm@borkdude That sounds like the best kind of over-engineering tbh.#2021-12-0215:02borkdude;-)#2021-12-0215:03Felipe CortezI recently finished https://beautifulracket.com/ and it seems like Racket really encourages this#2021-12-0215:04Felipe Cortezread strings, turn them into s-exps somehow, write your DSL logic#2021-12-0215:09gaboA little late to the party https://gist.github.com/galuque/b7d60d2f2ac4c9b4658b4d21f02b12df#2021-12-0215:19kpavDid it last night, but here it is (not at all clean or clojurey, but im still learning!) https://github.com/kwpav/advent-of-code-2021/blob/master/src/advent_of_code_2021/day02.clj#2021-12-0215:58Ben Slesshttps://github.com/bsless/clj-aoc-2021/blob/master/src/bsless/clj_aoc_2021/day2.clj
🙃#2021-12-0216:13R.A. PorterI couldn't resist reimplementing part 1 after @borkdude mentioned it...#2021-12-0216:15borkdude@U01GXCWSRMW awesome ;)#2021-12-0216:39noogaNote that this won’t work in Clojure. ⭐ for the one who tells me why.
I still don’t have proper assoc
/`update` and destructuring so it looks a bit weird 🤷#2021-12-0216:42borkdude@UJEK1RGJ0 case
doesn't expect you to quote the symbols#2021-12-0216:42borkdudethey are literals, not evaluated#2021-12-0216:42borkdudeso in clojure you're basically matching against (quote forward)
#2021-12-0216:48borkdude(case 'foo
foo 1) ;;=> 1
#2021-12-0217:08Chasehttps://github.com/Chase-Lambert/aoc-clojure/blob/main/src/aoc/2021/day_02.clj Oh man, some of the answers here are great. I could not figure out how to use reduce
for part-2 because I kept thinking I needed a 2 arity function but I have to track 3 things so I had to resort to my usual ugly loop/recur method#2021-12-0217:09ChaseThis Python solution for Day 2 seems so clean to me: https://www.reddit.com/r/adventofcode/comments/r6zd93/2021_day_2_solutions/hmwbtbe/#2021-12-0217:09ChaseThey made the connection that aim
for part 2 could just be your depth for part 1.#2021-12-0217:33Andrew ByalaI refactored mine to create a "mover" function which knows how to move forward, down, and up for both parts, and then plugged the mover into a common solver function that uses reduce. Curious about anyone's thoughts.
https://github.com/abyala/advent-2021-clojure/blob/main/src/advent_2021_clojure/day02.clj#2021-12-0217:37Ben SlessAnother sexpr oriented solution is to just compile the instructions:
(reduce comp (map (fn [[d n]] (fn [sub] (move sub d n))) moves))
#2021-12-0217:39Ben SlessIf you compile it, you just get function(s). Why does it matter when you do it?#2021-12-0217:57Mario C.My solution for day2. Maybe too much abstraction :thinking_face: 😅
(def puzzle-input
(->> (str/split (input "day2.txt") #"\n")
(mapv (fn [instruction]
(let [[direction steps] (str/split instruction #" ")]
[(keyword direction) (read-string steps)])))))
(def instruction-map
{:forward [(fn [{:keys [x] :as current-position} steps]
(assoc current-position :x (+ x steps)))]
:down [(fn [{:keys [y] :as current-position} steps]
(assoc current-position :y (+ y steps)))]
:up [(fn [{:keys [y] :as current-position} steps]
(assoc current-position :y (- y steps)))]})
(def instruction-map-z
{:forward [(fn [{:keys [x] :as current-position} steps]
(assoc current-position :x (+ x steps)))
(fn [{:keys [y z] :as current-position} steps]
(assoc current-position :y (+ y (* z steps))))]
:down [(fn [{:keys [z] :as current-position} steps]
(assoc current-position :z (+ z steps)))]
:up [(fn [{:keys [z] :as current-position} steps]
(assoc current-position :z (- z steps)))]})
(defn move-sub [instruction-map input]
(reduce (fn [current-position [direction steps]]
(reduce (fn [cp f] (f cp steps))
current-position
(get instruction-map direction)))
{:x 0 :y 0 :z 0}
input))
(defn solution [instruction-map input]
(let [{:keys [x y]} (move-sub instruction-map input)]
(* x y)))
(comment
;; Part 1
(solution instruction-map puzzle-input)
;; Part 2
(solution instruction-map-z puzzle-input))
#2021-12-0218:27Sam AdamsMy unoriginal take: https://samadams.dev/2021/12/02/advent-of-code-day-2.html#2021-12-0219:40Antonio Bibianolove the blogging approach 🙂#2021-12-0219:53tschady@U016C0EGHUN which tool do you use to process your source to create that blog? i was looking at marginalia but it didn’t quite fit.#2021-12-0219:54borkdude@tws If you're looking for a home-made solution: https://blog.michielborkent.nl/writing-clojure-highlighter.html#2021-12-0220:27Ben SlessSolved with awk for fun
BEGIN {
x=0;
y=0;
a=0
#
t["forward"]=0;
t["up"]=-1;
t["down"]=1;
#
h["forward"]=1;
h["up"]=0;
h["down"]=0;
#
v["forward"]=1;
v["up"]=0;
v["down"]=0;
}
{
a = a + t[$1]*$2
x = x + h[$1]*$2;
y = y + v[$1]*$2*a;
}
END {
print x*y;
}
#2021-12-0220:28borkdudeawkful! :)#2021-12-0220:30Ben Slessminified!
BEGIN {x=0; y=0; a=0 t["f"]=0; t["u"]=-1; t["d"]=1; h["f"]=1; h["u"]=0; h["d"]=0; v["f"]=1; v["u"]=0; v["d"]=0;} {c=substr($1,1,1) a = a + t[c]*$2 x = x + h[c]*$2; y = y + v[c]*$2*a;} END {print x*y;}
#2021-12-0220:30Ben SlessFits in a tweet#2021-12-0220:30borkdudedo it.#2021-12-0220:31Ben Slesshttps://twitter.com/_bsless/status/1466505316363821059#2021-12-0220:32Ben SlessReminds me of the annoying questions from intro to C, "do it without conditionals"#2021-12-0220:33borkdudeand now write an awk interpreter that fits in a tweet. so we can combine both tweets using tweet-def?#2021-12-0220:35Ben SlessI think I'll first need to bootstrap it with tweet-def itself as a dep, then just chain it, but that's cheating#2021-12-0220:36Ben SlessWhich reminds me I wanted to solve it with core.logic#2021-12-0221:23ordnungswidrigBabashka and pointless (threading style)
# part one
pbpaste | bb -I -e '(->> *input* (partition 2) (reduce (fn [[x y] [c v]] (case (keyword (name c)) :forward [(+ x v) y] :down [x (+ y v)] :up [x (- y v)])) [0 0]) (apply *))'
# part two
pbpaste | bb -I -e '(->> *input* (partition 2) (reduce (fn [[x y a] [c v]] (case (keyword (name c)) :forward [(+ x v) (+ y (* a v)) a] :down [x y (+ a v)] :up [x y (- a v)])) [0 0 0]) butlast (apply *))'
#2021-12-0221:52borkdudeAwesome :)#2021-12-0223:57euccastromy solution to day2. I'll read your solutions now; I know there are some crazy people who avoided using reduce 🙂
https://github.com/euccastro/advent-of-code-2021/blob/main/day2.clj#2021-12-0300:31euccastroyeah, I had forgotten about the joys of using re-seq
or wrapping the whole input to read it as edn...#2021-12-0306:08Cora (she/her)I'm real boring https://gist.github.com/corasaurus-hex/389968ca616083ba0feb630330ba1739#2021-12-0403:52Sam Adams@tws thanks! I’m interspersing the code with markdown line-comments like ;; # Header
, like one does with [Clerk](https://github.com/nextjournal/clerk), and then I have a little [script](https://github.com/samharad/samharad.github.io/blob/master/src/script/aoc.clj) for transforming the namespace into a markdown file. Then [Jekyll](https://jekyllrb.com/) takes it from there.#2021-12-0411:20Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day2.clj still learning#2021-12-0621:37Tero MatinlassiLittle bit late to the game, but here goes, nevertheless…
(ns day2
(:require [clojure.string]))
(comment
; part 1
(->> "input"
slurp
clojure.string/split-lines
(map #(clojure.string/split % #" "))
(map (fn [[command value]] [command (Integer/parseInt value)]))
(reduce (fn [[pos depth] [command value]]
(case command
"forward" [(+ pos value) depth]
"down" [pos (+ depth value)]
"up" [pos (- depth value)]))
[0 0])
(apply *))
;=> 1698735
)
(comment
; part 2
(->> "input"
slurp
clojure.string/split-lines
(map #(clojure.string/split % #" "))
(map (fn [[command value]] [command (Integer/parseInt value)]))
(reduce (fn [[pos depth aim] [command value]]
(case command
"forward" [(+ pos value) (+ depth (* aim value)) aim]
"down" [pos depth (+ aim value)]
"up" [pos depth (- aim value)]))
[0 0 0])
(take 2)
(apply *))
;=> 1594785890
)
#2021-12-0214:26potetmhttps://twitter.com/mononcqc/status/1466405806094622721#2021-12-0214:27potetm(It’s technically a solution, but I doubt most can read awk.)#2021-12-0214:31roelofI cannot read and understand it#2021-12-0214:32potetmYou want me to explain them?#2021-12-0214:32potetmday-2 is pretty straightforward#2021-12-0214:34roelofyou mean the awk syntax. No need to#2021-12-0214:35potetmToo late#2021-12-0214:35potetm# For lines that start with "u", subtract the second token (i.e. the number)
# from variable "d".
/^u/ {d-=$2}
# For lines that start with "d", add the second token (i.e. the number)
# to variable "d".
/^d/ {d+=$2}
# For lines that start with "f", add the second token (i.e. the number)
# to variable "h".
/^f/ {h+=$2}
# At the end, print the product of "d" and "h"
END {print d*h}
#2021-12-0214:36roelof😢 again too late#2021-12-0214:45Stuartits like someone saw regex and thought, that should be an entire programming language in of itself.#2021-12-0214:46StuartI can't tell yet if I love it or hate it#2021-12-0214:47potetmOh awk is actually awesome.#2021-12-0214:47potetmI use it less than I used to, but you can really do a lot of work w/ it if you want.#2021-12-0214:47potetmWell… circumstantially.#2021-12-0214:48StuartPeople at my work when they saw some CLojure were like "NOPE!, NOT HAPPENING"#2021-12-0214:48StuartI can't imagine if I showed something I'd written in AWK or APL#2021-12-0214:49StuartHell, they even said no chance to F##2021-12-0214:49roelofalso I also not. Can read clojure a little bit and some ruby#2021-12-0214:50StuartI've basically realised they aren't willing to entertain trying to learn something unless the syntax basically looks like C#2021-12-0214:50potetmWild to me how close-minded some people are.#2021-12-0214:51potetmLike, if I see something I don’t like, I just say, “Yeah I don’t really like that or want to spend my time on that.”
But to respond, “NOOO. THAT’S TERRIBLE. ARE YOU KIDDING?” is nuts.#2021-12-0214:51roelofim afraid a lot of people are closed minded. Even if I look at the dicussion take a vaccin or not. Looks like there are 2 sides and both said there are right and will not listen to the other side#2021-12-0214:54potetmYeah just a general lacking of curiosity/willingness to be ignorant.#2021-12-0214:54potetmWillingness to be ignorant is actually a sort of superpower imo.#2021-12-0214:54roelofor believing a source on facebook more then a expert#2021-12-0214:54StuartTo be fair, they do seem to be happy to hack away on just completely awful code, mainly because I don't think they know any better.#2021-12-0214:56potetmSee. The real problem is that usually when people are “just hacking away on completely awful code” very little (or nothing) is actually getting done.#2021-12-0214:56Stuartlike a program we had internally that downloaded a zip file, and extracted it to disc and ran an exse in the folder was 1000+ lines of code.#2021-12-0214:56roelofWAUW#2021-12-0516:20max minoSnice! saw your solution and it just makes my solution more horrible#2021-12-0516:29StuartIt probably takes me a minute to parse the question and understand what I need to do, then no way can i code it up in 2 minutes... The leaderboard times are incredible#2021-12-0516:29StuartFrom start to submitting right answer to part 2 today probably took me an hour ish#2021-12-0516:47max minoSmine took 9 minutes to run, couple hours to write probably#2021-12-0516:48max minoSmade the mistake of creating the map and plotting each point to the map, now i see that many people just found the frequency of the points and could get the solution#2021-12-0516:53StuartThese threads are great, Its really helpful being able to see other peoples solutions in clojure after I finish mine. Can pick up some neat functions#2021-12-0516:58gabomy (slow) solution for today https://gist.github.com/galuque/b0a932f8b262c3b6b9f993383ae61ea5#2021-12-0517:59Callum Oakleyre: avoiding having to deal with infinite slope
You don’t have to work in terms of slope at all. To be clear I don’t think there’s anything wrong with using slope and handling the divide by zero explicitly, but here’s another way of thinking about it that avoids the infinite slope awkwardness:
Given a line starting at s
and finishing at f
(`s` and f
vectors), the line segment between them is
s + t * (f - s) for t real between 0 and 1
I like this representation for problems like this, because there’s no special case for the vertical line (unlike if you try to use y = m*x + c
).
Now the only awkward thing is that we want integer coordinates. (f - s)
is always of the form [n 0]
, [0 n]
, [n n]
, [n -n]
for integer n
since we’re given that the line is always horizontal, vertical, or at 45deg. In every case we get integer coordinates exactly when t
is k/n
for some integer k
between 0
and n
inclusive. So we can rewrite our line segment as
s + k * (f - s) / n for k in {0, 1, ..., n}
or, if you want to expand it out
[sx + k * (fx - sx) / n, sy + k * (fy - sy) / n] for k in {0, 1, ..., n}
#2021-12-0518:01Callum Oakley(and it just so happens that n
is the “length” of the line if you use the Chessboard Distance as I mentioned above, but that’s besides the point really)#2021-12-0518:39tschadyno infinity problems if you convert to polar, ha
(defn theta [[[x1 y1] [x2 y2]]]
(Math/atan2 (- y2 y1) (- x2 x1)))
#2021-12-0519:09euccastromy solution for today would be marginally nicer if range
behaved as one would guess from the docstring
When step is equal to 0, returns an infinite sequence of
start. When start is equal to end, returns empty list.
but it turns out that if step is zero and start equals end, you get the empty list.
https://github.com/euccastro/advent-of-code-2021/blob/main/day5.clj#2021-12-0519:19euccastro@U076FM90B: great one! if you want to use more standard functions, (compare end start)
is the same as your (direction start end)
, and (complement diagonal?)
would be the same as (comp not diagonal?)
#2021-12-0519:24nbardiukcompare
is cool, but I was woried about edge case when 2 numbers are equal, the range
function needs non zero step. Another concern was that compare
does not guarantee 1 or -1 just positive or negative number. In the end I didn't try it because of those concerns#2021-12-0519:24Aleks@U65FN6WL9 not exactly, (compare end start)
will return 0 if start and end are equal, whereas (direction start end)
will return 1.#2021-12-0519:25AleksAlso, what is wrong with complement
? It is from the core. ^_^#2021-12-0519:27Antonio Bibianooh boy.. now I wanna know when it doesn't resturn 1 or -1 😄#2021-12-0519:27potetmYeah @U076FM90B brings up a legit concern w/ compare
. I didn’t say it earlier and should have, but there’s nothing in the contract w/ compare that says it will return -1 or 1.#2021-12-0519:29nbardiuk@U01HY37QQUA I saw that for strings it returns bigger numbers https://clojuredocs.org/clojure.core/compare#2021-12-0519:29potetmFrom the Comparable
docstring:
> Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.#2021-12-0519:30potetmPeople do things like (- this that)
.#2021-12-0519:30potetmIt’s not a big deal for AoC, but people should probably be aware of the general applicability.#2021-12-0519:41euccastrothanks! and sorry, I should have read the whole thread before commenting at least; there was already talk about range and compare#2021-12-0519:47euccastro@U067R559Q are you asking me or @U076FM90B? I do suggest using complement
#2021-12-0519:48nbardiukI have a silly reason, comp not
is just shorter than complement
😂#2021-12-0520:08genmeblogwhat a mess!#2021-12-0520:14genmebloglate solution: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day05.clj#2021-12-0520:25StuartWasnt aware of Clojure2d, looks cool#2021-12-0520:26genmeblog(I'm the author btw)#2021-12-0520:37danielgrosseNice to see I have come to a similar solution than others and not that ugly mess I did the last days. 😆#2021-12-0520:59Sam AdamsLate again: https://samadams.dev/2021/12/05/advent-of-code-day-5.html#2021-12-0521:29vnczhttps://github.com/XVincentX/aoc/blob/master/2021/src/day5.clj#2021-12-0521:34Felipeafter day 3 and 4, really happy with how clean mine came out https://github.com/FelipeCortez/advent-of-code/blob/master/2021/05.clj#2021-12-0522:31karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day5.clj - went fairly quickly, but then got wrong results for part2 and lost traction for a while but then noticed that my naive algorithm of conversion straight line -> points generates way too much points for diagonals so wrote another naive algo to generate points for diagonals 😄#2021-12-0522:32Mario C.Day 5. Couldn't figure out how to solve without brute forcing and generating all coordinates on the line.
(def puzzle-input
(-> (str/split (input "day5.txt") #"\n")))
(defn coordinate [coord-str]
(let [[x1 y1 x2 y2] (mapv read-string (re-seq #"\d+" coord-str))]
{:x1 x1 :y1 y1
:x2 x2 :y2 y2}))
(defn vertical-or-horizontal? [{:keys [x1 y1 x2 y2]}]
(or (= x1 x2) (= y1 y2)))
(defn *range [a b]
(if (> b a)
(range a (inc b) 1)
(range a (dec b) -1)))
(defn generate-line-coords [{:keys [x1 y1 x2 y2]}]
(->> (cond
(= x1 x2) [(repeat x1) (*range y1 y2)]
(= y1 y2) [(*range x1 x2) (repeat y1)]
:else [(*range x1 x2) (*range y1 y2)])
(apply mapv (fn [x y] {:x x :y y}))))
(defn overlapping-points [coordinates]
(->> coordinates
(mapcat generate-line-coords)
(sort-by (juxt :x :y))
(partition-by identity)
(filter #(>= (count %) 2))
(count)))
(defn part-one [puzzle-input]
(->> (mapv coordinate puzzle-input)
(filter vertical-or-horizontal?)
(overlapping-points)))
(defn part-two [puzzle-input]
(->> (mapv coordinate puzzle-input)
(overlapping-points)))
(comment
(part-one puzzle-input)
(part-two puzzle-input))
#2021-12-0604:19Aleks@U65FN6WL9 oh, sorry, I didn’t parse it correctly 😊#2021-12-1017:23Sidestephttps://gitlab.com/sidestep/advent-of-code-2021/-/blob/master/day5/src/scratch.clj#2021-12-0516:31StuartDo we think the avent of code leaderboards time are in any way indicative of how fast people get code written at work?#2021-12-0516:36nbardiukFrom one perspective code at work is just code, they are fast there too. But code at work is a team activity if team cannot read the code it slows down everybody#2021-12-0516:40sarcilavAlso the starting time doesn't help everyone, I don't think everyone stays up until midnight or wakes up at 6am (GMT+1 europe for example) to tackle the challenges#2021-12-0516:45StuartLast task I had at work, it took me 2days. That was from nothning to finishing the coding (day and a half), testing (1/4 day), writing documentation (1/4 day).
I'm just wondering if these people that top the leaderboards would be able to code up in an an hour or so what took me a day and a half#2021-12-0516:59Antonio BibianoI suspect they have a very specific setup for quickly manipulating the types of inputs you typically get in the AoC#2021-12-0517:03Antonio Bibianolast year I read this blogpost https://blog.vero.site/post/advent-leaderboard#2021-12-0520:25petercWelcome to the world of competition coding! There are definitely some skills of competition coders that carry over: familiarity with the IDE, knowledge of the language, deep understanding of many different algorithms and data structures (and able to implement them), and perhaps most importantly, passion for coding.
Speed doesn't necessarily equate with value though. In practice, we often trade speed for quality.#2021-12-0520:50euccastroI think this came up in clojureverse or somewhere in a similar context: https://catonmat.net/programming-competitions-work-performance#2021-12-0520:53euccastromaybe watch the video but don't read the article; there's a huge caveat to it: Norvig is talking about Google employees, which sets a pretty high baseline for programming performance already#2021-12-0603:30fingertoe1 - The leaderboard probably correlates to time zones more than anything else..
2 - I can (and do) often get a right answer with a very incomplete program, especially with the REPL.
I think the leaderboard is nice for chasing down folks github repos to see if you can learn anything from their approaches though.. It also may give some motivation to keep going..#2021-12-0516:41potetmIt might be indicative of how fast people can write code, but it’s definitely not related to productivity/adding value/anything that other people actually care about.#2021-12-0519:57petercnot knowing anything else, would you hire a random programmer or a random person from the leaderboard? and why?#2021-12-0520:00potetmThis is a really good question. Let me think on it.#2021-12-0521:17potetmOk. I don’t think you realize what you’ve done. You’re about to get a lot of opinions.#2021-12-0521:19potetmFirst, the answer to your question: Realistically, I would hire neither. That would be irresponsible.
But the interesting bit of the question is: Are you closer to hiring a leaderboarder or a rando?#2021-12-0521:19potetmI think the answer both are equally close to being hired, but in different ways.#2021-12-0521:21potetmOne necessity of a programmer is, well, the ability to program. Obviously a leaderboarder proves this ability.
Rando might possibly be in that far-left tail that actually cannot program at all. More likely that they are somewhere close to the median, but you never know.
So in this regard, the leaderboarder is ahead.#2021-12-0521:22potetmHowever, there is a non-trivial subset of programmers that are very good at talking to the computer and very bad at actually solving problems.#2021-12-0521:25potetmThese people go by different names. I often call them “tinkerers.” I heard Bryan Cantrill refer to them “compiler people” in a talk.#2021-12-0521:28potetmI have found that these people usually cause far more harm than good. And they’re far more nefarious, because they are often very, very busy-looking.
They hurl code, knock out cards, pull late nights, get the job done.
In other words, they are extremely attractive to a certain kind of manager. That makes it extremely difficult to reasonably discuss the long term effects of their behavior.#2021-12-0521:29potetmThe fact that someone can finish an AoC in 3:50 puts them firmly in the “might be a tinkerer” category.#2021-12-0521:31potetmThe downside risks of people in this category are so high, that it completely negates any advantage they have compared to the rando who might not be able to code at all.#2021-12-0517:23solfNot strongly related, but I’d be hard pressed to believe that the people on top of the leaderboard aren’t better at coding in general (this is a very vague notion) than the average programmer.
The only way that would make sense, is that if those people write code at work the same way they do at competitions, which isn’t a charitable view of them.#2021-12-0519:21potetmI don’t think there’s any conflict between this and what I said.#2021-12-0519:21potetm(Not sure if you thought there was or not.)#2021-12-0604:30Aleks🧵Day 6 answers thread: post your answers here#2021-12-0605:26Fredrik#2021-12-0605:34normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day6/main.clj#2021-12-0605:36solf(defn parse [input]
(->> input
u/parse-comma-separated-list
(map parse-long)))
(defn next [l]
{0 (get l 1 0)
1 (get l 2 0)
2 (get l 3 0)
3 (get l 4 0)
4 (get l 5 0)
5 (get l 6 0)
6 (+ (get l 7 0) (get l 0 0))
7 (get l 8 0)
8 (get l 0 0)})
(->> (parse #_"3,4,3,1,2"
(u/get-input 2021 6))
frequencies
(iterate next)
(take (inc 256))
last
vals
(reduce +))
#2021-12-0605:38normanLooking at the other solutions, I realize I didn't have to resort to a recursive memoized solution #2021-12-0605:44Miķelis Vindavs(defn step [fish]
(->> fish
(reduce (fn [res [k v]]
(if (= k 0)
(-> res
(update 6 (fnil + 0) v)
(assoc 8 v))
(update res (dec k) (fnil + 0) v)))
{})))
(defn solve [n input]
(->> input
(find-ints)
(frequencies)
(nth-iter n step)
(vals)
(reduce +)))
(def solve1 (partial solve 80))
(def solve2 (partial solve 256))
#2021-12-0605:51johnnyhttps://github.com/jhny/adventofcode2021/blob/main/src/day6.clj#2021-12-0606:18Mario C.Pretty much the same as others
(def puzzle-input
(mapv read-string (str/split (input "day6.txt") #",|\n")))
(defn apply-fish-creation [index state]
(if (= index 0)
(-> (update state 8 (constantly (get state index)))
(update 6 (partial + (get state index))))
state))
(defn update-state [state]
(->> (reduce (fn [{:keys [state carry-over]} index]
{:state (-> (apply-fish-creation index state)
(update index (constantly carry-over)))
:carry-over (get state index)})
{:carry-over 0
:state state}
(range 8 -1 -1))
(:state)))
(defn lantern-state [fish-states]
(reduce (fn [state f-state]
(update state f-state inc))
(vec (repeat 9 0)) fish-states))
(defn part-one [puzzle-input days]
(let [state (lantern-state puzzle-input)]
(apply + (reduce (fn [s _] (update-state s)) state (range days)))))
(comment
;; day1
(part-one puzzle-input 80)
;; day2
(part-one puzzle-input 256))
#2021-12-0606:27misha@U7S5E44DB
(take (inc 256))
last
->
(drop 256)
(first)
#2021-12-0606:42ACsigh.. I wasted way too much time reading about exponential growth functions for part 2 before the "aha" moment came.#2021-12-0607:41petercI wish I implemented @U7S5E44DB solution for speed, simple and gets it done#2021-12-0607:44fingertoehttps://github.com/jreighley/aoc2021/blob/master/src/day6.clj#2021-12-0608:06babardohttps://github.com/v-garcia/aoc_2021/blob/main/day_six.clj#2021-12-0608:10nbardiukI was very happy to find/remember that clojure has memoize, otherwise I would waste another hour caching intermediate results https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day06.clj#2021-12-0608:40Antonio Bibianothis is my solution for today#2021-12-0608:40Antonio Bibiano(def small "3,4,3,1,2")
(def large (slurp "/home/antbbn/aoc_2021/input_6.txt"))
(defn parse [input]
(as-> input _
(re-seq #"\d+" _)
(map #(Integer/parseInt %) _)
(frequencies _)
(mapv #(get _ % 0) (range 9))))
(defn step [fishes]
(conj (update (subvec fishes 1) 6 + (first fishes))
(first fishes)))
(reduce + (nth (iterate step (parse small)) 80))
(reduce + (nth (iterate step (parse large)) 80))
(reduce + (nth (iterate step (parse small)) 256))
(reduce + (nth (iterate step (parse large)) 256))
#2021-12-0608:41Antonio Bibianowas pretty cool to keep thinking of a way to avoid creating the list of fishes 🙂#2021-12-0610:58Mikko KoskiGreat that 1.11.0-alpha3 came right before AoC 🙂 I've been heavily using the new core functions, parse-long
, update-keys
, update-vals
etc.
My solution for today:
https://github.com/rap1ds/advent-of-code-2021/blob/main/src/day6.clj#2021-12-0611:44gaboThis day is a nice little one https://gist.github.com/galuque/25e5adf15976ea36023cf69af43c7310
(ns io.github.galuque.aoc-2021.day-6
(:require [ :as io]
[clojure.string :as str]))
(def input (->> "day_6/input.txt"
io/resource
slurp))
(def sample-input "3,4,3,1,2")
(def init-ages (into [] (repeat 9 0)))
(defn ages-vec [coll [v f]]
(update coll v + f))
(defn parse-input [input]
(->> (str/split (str/trim input) #",")
(map parse-long)
frequencies
(reduce ages-vec init-ages)))
(defn day-passed [ages]
(reduce conj [(subvec ages 1 7)
(+ (nth ages 7) (nth ages 0))
(nth ages 8)
(nth ages 0)]))
(defn count-fish [days ages]
(->> ages
(iterate day-passed)
(take (inc days))
last
(apply +)))
(def part-1 (partial count-fish 80))
(comment
(part-1 (parse-input sample-input))
;; => 5934
(part-1 (parse-input input))
;; => 374994
)
(def part-2 (partial count-fish 256))
(comment
(part-2 (parse-input sample-input))
;; => 26984457539
(part-2 (parse-input input))
;; => 1686252324092
)
#2021-12-0611:58genmeblogand my solution... I don't know why it's so obfuscated :/, very close to @U076FM90B. Also love @U01HY37QQUA step
function. So clever! https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day06.clj#2021-12-0612:33AleksAlmost forgot about memoize
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_06.clj#2021-12-0612:35Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day6.clj#2021-12-0612:43Aleks@https://app.slack.com/team/U01HY37QQUA, I am amazed by your solution :star-struck:#2021-12-0613:04JoeAnother fun one, but I'm sure there's a more elegant to implement the method I tried in part 2:
https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day06.clj
https://github.com/RedPenguin101/aoc2021/blob/main/day06.md#2021-12-0613:10Vincent CantinMy solution: https://github.com/green-coder/advent-of-code/blob/master/src/aoc_2021/day_6.clj
I used the new update-keys
function, yeah ^_^ 🎉#2021-12-0613:15tschadyi admit to stealing @U01HY37QQUA’s init-state function, I originally used reduce-kv
. my next-gen
was original
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d06.clj#2021-12-0613:18tschadycheckout my coworkers thinking:
> This problem can also be done as a matrix multiplication of an “evolution” matrix `M`:
> {
> {0, 1, 0, 0, 0, 0, 0, 0, 0},
> {0, 0, 1, 0, 0, 0, 0, 0, 0},
> {0, 0, 0, 1, 0, 0, 0, 0, 0},
> {0, 0, 0, 0, 1, 0, 0, 0, 0},
> {0, 0, 0, 0, 0, 1, 0, 0, 0},
> {0, 0, 0, 0, 0, 0, 1, 0, 0},
> {1, 0, 0, 0, 0, 0, 0, 1, 0},
> {0, 0, 0, 0, 0, 0, 0, 0, 1},
> {1, 0, 0, 0, 0, 0, 0, 0, 0},
> }
> times a vector `v[0..8]` where `v[i]` indicates how many fish with internal timer value `i`. Then the problem reduces to computing `M⁸⁰⋅v` then summing the elements in the resulting vector.
>
> That technique is especially interesting if the number of days is super large, because you can raise a matrix to an arbitrary power much more quickly than actually multiplying that many times.#2021-12-0613:23Antonio Bibiano@U1Z392WMQ very nice the next-gen
with the thread first i also thought about using a let statement to avoid calling first
two times, do you think that's better practice?#2021-12-0613:25tschadywhenever it helps describe the domain i do it.#2021-12-0613:32Antonio Bibianoah yeah i'll keep that in mind#2021-12-0613:34Antonio Bibiano@U1EP3BZ3Q but with your solution you can now make a nice animation of fishes slowly gestating and giving birth to new fishes :D#2021-12-0613:38genmeblognot enough pixels 🙂#2021-12-0614:43StuartI initially started with just trying to add to vectors... THis worked for part1 and failed miserably for part 2
(defn puzzle-input []
(->> (slurp "puzzle-inputs/2021/day6")
(u/str-split #",")
(mapv #(Integer/parseInt %))
(frequencies)
#_(into (sorted-map))))
(defn reset [idx-to-rest xs]
(vec (reduce (fn [acc i] (assoc acc i 6)) xs idx-to-rest)))
(defn spawn [to-spawn xs]
(vec (concat xs (repeat to-spawn 8))))
(loop [input (puzzle-input), day 0]
(prn day)
(if (= day 256)
(count input)
(let [to-spawn (keep-indexed #(when (zero? %2) %1) input)
updated (->> input
(mapv dec)
(reset to-spawn)
(spawn (count to-spawn)))]
(recur updated (inc day)))))
I then tried to use transients, but I couldn't get this to work at all. I kept getting type mismatches between lazy-seq and transients. I couldn't understand why, so gave up with this. I need to learn more about transients.
Then I realised I could just keep track of the number of fishes at each life stage in a hash-map like others here have done.
(loop [stages (puzzle-input)
days 0]
(if (= days 256)
(->> stages
vals
(reduce +))
(recur {0 (stages 1 0)
1 (stages 2 0)
2 (stages 3 0)
3 (stages 4 0)
4 (stages 5 0)
5 (stages 6 0)
6 (+ (stages 7 0) (stages 0 0))
7 (stages 8 0)
8 (stages 0 0)}
(inc days))))
Couldn't figure out a way to do this with reduce-kv
, so just did it the long winded way.#2021-12-0614:44StuartALthough seeing the final result, I doubt transients would even help much, the vector would be HUGE#2021-12-0615:21StuartGot it with iterate too, but I don't like this solution as much
(defn update-fish [stages]
(->> (map (fn [n]
(case n
8 {8 (stages 0 0)}
6 {6 (+ (stages 7 0) (stages 0 0))}
{n (stages (inc n) 0)}))
(range 0 9))
(into {})))
(->> (puzzle-input)
(iterate update-fish)
(take 257)
(last)
(vals)
(reduce +))
I don't like the take 257, is their a way to do this where you "overwrite" the stages each time and dont end up with a big list. Like a function that keeps a function f over and over n times and feeds its output back in as its input, without making the collection?#2021-12-0615:27Callum Oakley@U013YN3T4DA you could (apply comp (repeat 256 f))
, but since take
is lazy, you’re not actually retaining the full list in memory anyway#2021-12-0616:10mchampine#2021-12-0616:51euccastrothere's probably a more lucid shortcut using math, but I got this working quickly and I didn't need to change it for part 2 or clean it up later:
https://github.com/euccastro/advent-of-code-2021/blob/main/day6.clj#2021-12-0616:57pavlosmelissinosHas anyone found a solution that runs in O(1)? Or at least in linear time to the number of fish states? I feel like it should be possible.#2021-12-0616:58AleksJust played a bit with @U06B54Y95 solution :star-struck:
(defn step [m]
(-> (mapv m [1 2 3 4 5 6 7 8 0])
(update 6 (fnil + 0 0) (m 0))))
(defn fish [input n]
(let [fish-seq (iterate step (frequencies input))]
(reduce + (nth fish-seq n))))
#2021-12-0616:59Callum Oakley@UEQPKG7HQ the matrix solution @U1Z392WMQ posted above is O(log(n))
with repeated squaring to do the exponentiation#2021-12-0617:04euccastroI think my solution is missing a declare
but it worked in the repl because I somehow defined the name to something nonrecursive first? 😛#2021-12-0617:27Sam AdamsI like the memoized per-fish solutions, totally different than how I thought about it.
My rotating-array solution: https://samadams.dev/2021/12/06/advent-of-code-day-6.html#2021-12-0618:07Felipe Cortezgave up on trying to do it mathematically and just ran the simulation instead. before the clean up:
(defn one [population]
(reduce-kv (fn [m k _v]
(assoc m k
(cond (= 6 k) (+ (get population 7)
(get population 0))
(= 8 k) (get population 0)
:else (get population (inc k)))))
{}
population))
(defn init [m] (merge (zipmap (range 9) (repeat 0)) m))
(reduce + (vals (last (take 257 (iterate one (init (frequencies input)))))))
#2021-12-0618:16Miķelis Vindavs@U013YN3T4DA not that it matters too much in this case but (->> (drop 256) (first))
should be faster than (->> (take 257) (last))
because last
is always O(n)
#2021-12-0618:17Miķelis Vindavsfor this use case I have a small helper function which avoids seqs altogether
(defn nth-iter [^long n f x]
(if (pos? n)
(recur (dec n) f (f x))
x))
#2021-12-0618:18Miķelis Vindavsso (->> seed (iterate f) (drop n) (first))
becomes (->> seed (nth-iter n f))
#2021-12-0618:40mchampine@U067R559Q
> “(mapv m [1 2 3 4 5 6 7 8 0])”
Awesome, love it! So clever that your version of the step function works with the output of frequencies AND a vector (because in this case they’re both functions from number to value - and that number can just as well be an index). Very concise code!#2021-12-0622:01borkdudeBetter late than never.
https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_06-clj#2021-12-0622:04borkdudeBoth run under a millisecond with babashka.#2021-12-0623:43karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day6.clj starting day6 rather late into a night wasn't good idea as it seems this is the first tricky one advent of code this year
wasted a bit time trying to devise a formula of growth of single fish to be then used for others but then somehow clicked that all the fishes behave the same based on their state and not position on the array so it doesn't need to be preserved in whole#2021-12-0700:20euccastroas usual I got envious of your frequencies-based solutions, so I did two things:
• make a note to ask myself "what would frequencies do?" in every AoC day going forward, and
• try and make a frequencies-based solution that rotates only some reference index, not the frequencies data structure itself#2021-12-0700:20euccastroso here is it: https://github.com/euccastro/advent-of-code-2021/blob/main/day6b.clj#2021-12-0700:21euccastroit borrows liberally from various of the other solutions#2021-12-0704:55kevincpleased with how brief it came out 🙂 https://github.com/kconner/advent-of-code/blob/master/2021/6b.clj#2021-12-0609:50Benjamincan somebody give a tip for day6 part2#2021-12-0609:52Benjaminlike how to make an efficient algorithm#2021-12-0610:02Benjaminnow I'm trying to think about each fish in isolation, instead of the list of fish.
I guess there should be a function f(age,t) -> fish count#2021-12-0610:14Björn EbbinghausThe tip is:
frequencies
#2021-12-0610:36petercthere's an iterative approach that does not require brute-force#2021-12-0610:59Miķelis VindavsThe order of the fish doesn’t matter, and there’s only ever 9 types of fish. Which means you don’t have to store all of them individually#2021-12-0611:11genmeblogmy hint: cache is your friend#2021-12-0612:33Benjamindid something with frequencies that is around 5ms 🙂#2021-12-0612:34Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day6.clj#2021-12-0613:09Björn Ebbinghaus@U02CV2P4J6S Nice!
Here is my solution, if you are interested:
https://github.com/MrEbbinghaus/advent-of-code/blob/master/2021/day06.clj#L26#2021-12-0613:27Benjaminsick @U4VT24ZM3#2021-12-0704:52kevincMy tip: Don't follow the explanation too literally. And, you can eliminate unnecessary steps if you start with the end result you need to calculate, and build backward toward the input. https://github.com/kconner/advent-of-code/blob/master/2021/6b.clj#2021-12-0609:59hanyuone#2021-12-0610:49Antonio Bibianomaybe a nested map
(defn bingo-mark [board draw]
(map (fn [row]
(map
(fn [[col _]]
[col (= col draw)])
row))
board))
#2021-12-0610:56Miķelis VindavsNested vectors are usually not very convenient, perhaps try using a hashmap where the key is a tuple of coords [x y]
and the value is the count.#2021-12-0610:56petercIf you want to use a nested vector, something like this will work:
(defn board-coords [n]
(for [x (range n)
y (range n)]
[x y]))
(def coords (board-coords 5))
(defn bingo-mark [board mark]
(->> coords
(filter #(= mark (get-in board (vec %))))
(reduce #(assoc-in %1 %2 true) board)))
#2021-12-0610:57Miķelis VindavsBut you could do
(for [row (range SIZE)
col (range SIZE)]
...)
edit: oh, jinx#2021-12-0610:57petercThe point is that you dont want to rebuild the vector(s) each time (like in the nested map solution)#2021-12-0610:59petercBut yeah, a hash-map is much more convenient!#2021-12-0611:17hanyuonei ended up doing this instead:
(defn find-draw
[board draw]
(let [coords (for [x (range SIZE) y (range SIZE)] [x y])]
(->> coords
(filter (fn [[x y]] (= (get-in board [x y 0]) draw)))
first)))
(defn bingo-mark
"Given a Bingo board and a drawn number, 'mark' that number on the board."
[board draw]
(if-let [[row col] (find-draw board draw)]
(assoc-in board [row col 1] true)
board))
#2021-12-0611:22hanyuoneseems a bit more idiomatic - not sure about a hashmap, wouldn't it make more sense to have a 1d vector in that case then?#2021-12-0611:26Miķelis VindavsIn this case it probably doesn’t matter too much, but in other years on tasks where the “board” can grow in all directions and is usually quite sparse (e.g. the Conway’s game of life type puzzles) a hashmap is much much faster. But probably a matter of taste 🙂#2021-12-0611:27hanyuonei see, thank you!#2021-12-0613:56tschadyfor updating nested data structures, i suggest you use a purpose built library. my fav is https://github.com/redplanetlabs/specter . How much time it saves you helps get over the non-clojurey feel:
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d04.clj#L17-L20#2021-12-0613:57tschadythat navigator says ALL cards, ALL rows, ALL columns, then find our number.#2021-12-0610:58StuartOH dear, my sln for part 2 is running very, very slowly. It was fastish up to day 110 ish, then started really creeping along at day 120ish, now its ticking up a day every 10 seconds or so...#2021-12-0611:01Miķelis VindavsWould you like some hints on how to speed it up?#2021-12-0611:02StuartNot yet, I have an idea of using a hashmap to store the number of fish at each state, e.g. start would be
{0 0
1 1
2 1
3 2
4 1
5 0
6 0
7 0
8 0}
THen update each val by dec
, then spawn just can update the number of 8s to the number of zeros each time. Is this dumb?#2021-12-0611:03Miķelis VindavsI’d say you’re on the right track! 🙂#2021-12-0611:03Stuartcan you iterate through a hash map to update each val ?#2021-12-0611:03StuartIs their a core function to do this?#2021-12-0611:04Miķelis Vindavsyou can create a new map
(->> old-map
(map (fn [[old-key old-val]]
[new-key new-val]))
(into {}))
#2021-12-0611:04Stuartthanks!#2021-12-0611:05Miķelis Vindavsor if you want a bit more control over the result, you can use reduce
(->> old-map
(reduce (fn [new-map [old-key old-val]]
(assoc new-map ...))
{})
#2021-12-0613:00Björn Ebbinghaus@U013YN3T4DA You can map over a map.
Tip:
[3 42] -> {2 42}
[0 13] -> {6 13, 8 13}
#2021-12-0614:02tschadysee reduce-kv
#2021-12-0620:10borkdudeSee solution is a few milliseconds, even in bb.
https://twitter.com/mknoszlig/status/1467768132521627648#2021-12-0620:11borkdudeI was stuck in a foolish solution of exploding the list like it was graphically presented in the puzzle :)#2021-12-0621:52sebastianI am renaming the keys in the hashmap. does part 2 in 1.5ms#2021-12-0623:07lreadEek, the problem description drew me into a brute force solution. But I guess that was its fiendish aim!
I was actually mired until I got the frequencies tip here. Bah!#2021-12-0623:11borkdudeSame#2021-12-0623:11borkdudeBut now both answers run under 1ms in bb :)#2021-12-0701:00rmprescottWhat editor is this? I'm guessing it's displaying "f(" for "#("#2021-12-0701:04StuartYou can do this in vscode, with prettify symbols plugin. Can setup your own substitutions.#2021-12-0707:20sebastianspacemacs with a fancy symbol plugin. an you are right.#2021-12-0614:00nbardiukThe exponential growth. Brightness represents internal timer of a fish, new fishes are added to the tail of spiral#2021-12-0614:03tschadysource? love to see it.#2021-12-0614:05nbardiukit's quilclojure2d code with some magic numbers https://github.com/nbardiuk/adventofcode/blob/master/2021/dev/sketches/day06.clj#2021-12-0614:14Benjaminpogg#2021-12-0620:37genmeblogGlad you've reached for Clojure2d @U076FM90B Yay!#2021-12-0620:41nbardiukI am very glad I've migrated to Clojure2d, I could not setup quil to run fast on my machine and Clojure2d just worked. The performance difference was very big. Thank you for the library#2021-12-0701:13rmprescottToo bad they didn't go a bit larger. ;D
(time (part-2 input 500))
"Elapsed time: 3.192168 msecs"
=> 2759581742718205387412N
#2021-12-0704:54Aleks🧵Day 7 answers thread: post your answers here#2021-12-0705:24normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day7/main.clj#2021-12-0705:27johnnyhttps://github.com/jhny/adventofcode2021/blob/main/src/day7.clj#2021-12-0705:33mchampine(defn fuel [ex n] (apply + (map #(util/abs (- % n)) ex)))
(apply min (map (partial fuel input) (range (apply max input)))) ;; 335271
;; Part 2 (incfuel improved by mikelis observation)
(defn incfuel [n] (/ (* n (inc n)) 2))
(defn fuel2 [ex n] (apply + (map #(incfuel (util/abs (- % n))) ex)))
(apply min (map (partial fuel2 input) (range (apply max input)))) ;; 95851339
#2021-12-0705:34Miķelis VindavsBy the way 1 + 2 + 3 + … + n
== n * (n + 1) / 2
#2021-12-0705:59AleksJust brute force
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_07.clj#2021-12-0706:03Miķelis Vindavsnice use of frequencies
to skip over duplicates#2021-12-0706:03kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/7a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/7b.clj#2021-12-0706:06Miķelis Vindavshttps://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/y2021/day07.clj#2021-12-0706:52Pradeep B(def example-input-list (list 16,1,2,0,4,2,7,1,2,14))
(def example-input-frequencies (sort-by val (frequencies ex)))
(defn calculate-diff [n pos]
(if (> pos n) (- pos n) (- n pos)))
(first (sort
(map (fn [input]
(reduce + (map #(calculate-diff %1 (first input)) example-input-list)))
example-input-frequencies)))
feedback is more than welcome, what else can be done to optimize (part1 only, understanding formula to calculate cost for part2)#2021-12-0707:03peterc#2021-12-0707:14fingertoehttps://github.com/jreighley/aoc2021/blob/master/src/day7.clj#2021-12-0707:28nbardiukAfter solving using brute force, I've noticed that positions are very close to median and mean, and looks like for a lot of people on reddit it also works https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day07.clj#2021-12-0707:41petercNot the most idiomatic, but you can do something like this @U01BDUH28V7
(defn cost-fn-1 [start end]
(abs start end))
(defn cost-fn-2 [start end]
(let [n (abs start end)]
(/ (* n (inc n)) 2)))
(defn cost [data cost-fn n]
(reduce + (map (partial cost-fn n) data)))
(defn mid [a b]
(int (+ a (/ (- b a) 2))))
(defn min-cost [f]
(let [d (parse-data)]
(loop [mn 0
mx (apply max d)
best (cost d f (mid mn mx))]
(if (= mn mx)
best
(let [md (mid mn mx)
lower (cost d f (mid mn md))
higher (cost d f (mid md mx))]
(if (< lower higher)
(recur mn md (min lower best))
(recur (inc md) mx (min higher best))))))))
(def part-1 (min-cost cost-fn-1))
(def part-2 (min-cost cost-fn-2))
#2021-12-0707:42Pradeep Brealised after looking at part2 that mean will be good approach/ thanks @U1NLKFVC4#2021-12-0707:45petercThere are a bunch of bugs in my code actually, my the input is nice enough to give me the correct solution.#2021-12-0707:45petercSpits out an answer in about ~200ms on my machine#2021-12-0708:04euccastrofor day 7 I happened to remember the math trick to sum the 1..n integers. I tried an optimization (involving frequencies
, of course) of the first thing I thought of, but that was hardly worth the trouble:
https://github.com/euccastro/advent-of-code-2021/blob/main/day7.clj#2021-12-0708:10euccastro@U067R559Q nice one! If you have already calculated the frequencies it's slightly more efficient and concise to iterate over the keys of that instead of (range min-pos (inc max-pos))
?#2021-12-0708:22euccastroanyway, I was surprised about how little time is saved by reducing the number of positions to compare against, either with frequencies or range from min to max#2021-12-0708:30jacoelhobrute force solution, memoize fuel calculations https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day07.clj#2021-12-0708:32Aleks@U65FN6WL9 that was my first thought, and it worked for my part 1. But for part 2 there is no position in the input which is the best to choose. So I ended up with a full range of the all positions.#2021-12-0708:33euccastrooh, great catch!#2021-12-0708:33peterctossing in a pmap
seems like the easiest win#2021-12-0708:34euccastroI interpreted the problem as picking the cheapest position from the given crab positions, so I guess I just got lucky with my puzzle input#2021-12-0708:40jherrlinYeah I used a pmap
, dont know if it was totally necessary but it felt cool 🙂 https://github.com/Kodkollektivet/advent-of-code-2021/blob/main/clojure/jherrlin/day7/problem2.clj#2021-12-0709:05petercIs this right? For part 1, sorting the input, and calculating the cost at the midpoint yields the first solution. (There are two midpoints, so use the min).#2021-12-0709:06petercSolution looks like this:
(defn part1 []
(let [data (sort (input))
mid (/ (count data) 2)]
(min (cost data (nth data mid))
(cost data (nth data (dec mid))))))
#2021-12-0709:09petercupon reflection, i think the answer can lie between the two points#2021-12-0709:23Callum Oakleybinary search ~50ms https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/07.clj#2021-12-0709:23tschady@U076FM90B your floor-median
should probably be floor-mean
?#2021-12-0709:48nbardiukthank you! fixed#2021-12-0710:26babardoAvoided doing too much maths 😅
https://github.com/v-garcia/aoc_2021/blob/main/day_seven.clj#2021-12-0710:27Antonio BibianoI have to admit I solved mine with raw brute force 😄
(defn cost-1 [pos crab]
(Math/abs (- pos crab)))
(defn cost-2 [pos crab]
(let [dist (Math/abs (- pos crab))]
(/ (* dist (inc dist)) 2)))
(defn brute-min-cost [crabs cost]
(let [far (apply max crabs)]
(apply min
(map (fn [pos]
(reduce +
(map #(cost pos %) crabs)))
(range (inc far))))))
(brute-min-cost crabs cost-1)
(brute-min-cost crabs cost-2)
#2021-12-0710:28Antonio Bibianothen I wikipedia the shit out of the problem and found that median was the solution to part 1 and a friend suggested that the average is the solution to part 2 so here they are#2021-12-0710:29Antonio Bibiano(defn median [l]
(let [len (count l)
middle (/ len 2)
sorted (sort l)]
[(nth sorted (dec middle)) (nth sorted middle)]))
(defn avg* [crabs]
(/ (apply + crabs) (count crabs)))
(defn avg [crabs]
(let [res (avg* crabs)]
[(int res) (inc (int res))]))
(defn cost-1 [pos crab]
(Math/abs (- pos crab)))
(defn cost-2 [pos crab]
(let [dist (Math/abs (- pos crab))]
(/ (* dist (inc dist)) 2)))
(defn min-cost [crabs cost candidates]
(apply min
(map (fn [pos]
(reduce + (map #(cost pos %) crabs)))
candidates)))
(def crabs (parse large))
(min-cost crabs cost-1 (median crabs))
(min-cost crabs cost-2 (avg crabs))
#2021-12-0710:29Antonio Bibianoi decided to return two candidates for median and average just in case#2021-12-0711:11genmeblogand code: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day07.clj#2021-12-0711:19Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day7.clj#2021-12-0711:40genmeblogups, sorry, density was wrong... had to delete previous message
above - submarine trace, below - initial density of submarines 🙂#2021-12-0712:13borkdudeDay 7 in #babashka and #clojure
https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_07-clj#2021-12-0712:38Felipebrute forced part 1 expecting part 2 to force me to think of a better solution, but my laziness paid off
https://github.com/FelipeCortez/advent-of-code/blob/master/2021/07.clj#2021-12-0712:40borkdude@UA2U3KW0L Awesome! How fast is yours?#2021-12-0712:41borkdudeNot that it matters, just wondering#2021-12-0712:43Felipehuh, time says "Elapsed time: 0.235105 msecs"
, but it's definitely more#2021-12-0712:44borkdudethis is because of laziness probably which escapes the time
call#2021-12-0712:44Felipeyeah, mapv yields "Elapsed time: 11779.226753 msecs"#2021-12-0712:45borkdudeThis guy has optimized it so it runs in tens of milliseconds in both clojure and babashka: https://github.com/mknoszlig/aoc2021/blob/76ef20928dd59d3810ca5e04f7f879357389268b/src/aoc2021/day7.clj#2021-12-0712:46Felipenice! https://github.com/mknoszlig/aoc2021/commit/76ef20928dd59d3810ca5e04f7f879357389268b this is surprising for me#2021-12-0712:49borkdudeMath/abs
reflects in the absence of type hints#2021-12-0712:49Felipeoh! makes sense#2021-12-0712:50borkdudeuser=> (set! *warn-on-reflection* true)
true
user=> (defn foo [x] (Math/abs x))
Reflection warning, NO_SOURCE_PATH:1:15 - call to static method abs on java.lang.Math can't be resolved (argument types: unknown).
#'user/foo
#2021-12-0713:16nbardiuksomebody worked out that correct answer differs from mean by up to 0.5 https://www.reddit.com/r/adventofcode/comments/rawxad/2021_day_7_part_2_i_wrote_a_paper_on_todays/#2021-12-0713:18borkdudewoah! :)#2021-12-0713:22tschadywelp, time to update my code 🙂#2021-12-0713:25tschadyoh, to be young again#2021-12-0713:25Callum Oakleyif you have an intcode computer handy, there’s an easter egg in today’s puzzle :o#2021-12-0713:37genmeblogsolution with optimizer (sometimes it can give wrong answer, mainly due to discrete domain):
(defn dist [a b] (int (m/abs (- a b))))
(defn fuel-burn [data cost-fn m] (reduce #(+ %1 (cost-fn %2 m)) 0 data))
(defn cost [d] (/ (* d (inc d)) 2))
(def target1 (comp (partial fuel-burn data dist) int))
(def target2 (comp (partial fuel-burn data (comp cost dist)) int))
(defn optimizer [target]
(->> {:bounds [[0 2000]] :N 100}
(fastmath.optimization/scan-and-minimize :cmaes target)
(second)
(int)))
(optimizer target1)
;; => 336040
(optimizer target2)
;; => 94813675
;; --- also valid
(target1 (fastmath.stats/median data))
;; => 336040
(target2 (fastmath.stats/mean data))
;; => 94813675
#2021-12-0713:46tschadycheater version with credit given:
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d07.clj#2021-12-0713:53Antonio Bibianoadding the type hints really changes the performance!! thanks @U04V15CAJ for pointing that out#2021-12-0713:53Antonio Bibianobut I found this a bit odd when I tried to define the cost like this
(defn cost-1 [^int pos ^int crab]
(Math/abs (- pos crab)))
#2021-12-0713:53Antonio Bibiano; Syntax error (IllegalArgumentException) compiling fn* at (/home/antbbn/aoc_2021/day7.clj:63:1).
; Only long and double primitives are supported
#2021-12-0713:54genmeblogyes, that works this way (I mean Clojure type hinting)#2021-12-0713:55genmeblogonly longs can be used and these are possible up to arity 4#2021-12-0713:56Antonio Bibianobut on the reference it says that int
is acceptable#2021-12-0713:57genmeblogbut not as a type hint for a function arguments, you can use type hinting in any other places and there ^int
is possible.#2021-12-0713:59genmeblogfor example, this is ok:
(defn cost-1 [[^int pos ^int crab]]
(Math/abs (- pos crab)))
#2021-12-0714:00genmeblogor this:
(defn cost-1 [pos crab]
(Math/abs (- ^int pos ^int crab)))
#2021-12-0714:04Antonio BibianoAh I see, I guess it's a bit off topic but do you know the reason for that?#2021-12-0714:12genmeblogyep, there is a stub for a function for every combination of arguments and returning value#2021-12-0714:19genmeblog@U01HY37QQUA it's here: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java#L97#2021-12-0714:27Antonio Bibianooh wow#2021-12-0714:27Antonio Bibianothanks 🙂#2021-12-0716:43karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day7.clj it was much easier for me than day7. Not very performant but when checking day6 solutions afterwards and seeing people using memoize it reminded me how nice of a function this is and basically used it today for part2#2021-12-0717:43Sam AdamsBest I could come up with (through trial and error) for part 2 was that the solution position seemed to be bounded by the median and rounded mean. Apparently that’s faulty… unless the median indicates which direction the mean is pulled by up to 1/2…? That’s a question for later 🙂
https://samadams.dev/2021/12/07/advent-of-code-day-7.html#2021-12-0718:31gaboI brute forced it and part2 was taking ~20 s, just changing the naive summing of ranges for the gauss formula got me to 200ms 😳
https://gist.github.com/galuque/fdeba14c6103bf6482b6f7c53fd645db#file-aoc2021_day_7-clj#2021-12-0719:44StuartPart 2 got a bit messy for me:
(ns stuartstein777.2021.day7
(:require [stuartstein777.file :as f]
[stuartstein777.utils :as u]))
(defn get-distances [hps n]
(mapv (fn [h] (Math/abs (- h n))) hps))
(let [input (f/parse-csv-ints "puzzle-inputs/2021/day7")
minimum (apply min input)
maximum (apply max input)
h-positions (u/range-inclusive minimum maximum)]
(->> input
(mapv (partial get-distances h-positions))
(apply mapv vector)
(mapv #(reduce + 0 %))
(apply min)))
;; part 2
(defn build-row [min max n]
(let [to-max (if (= n max) [] (reductions + (u/range-inclusive 1 (- max n))))
to-min (reverse (reductions + (u/range-inclusive min n)))]
(concat to-min to-max)))
(let [input (f/parse-csv-ints "puzzle-inputs/2021/day7")
minimum (apply min input)
maximum (apply max input)]
(->> input
(mapv (partial build-row minimum maximum))
(apply map vector)
(mapv #(reduce + 0 %))
(apply min)))
I built a table up of the distance to each possible horizontal position, then rotated it 90 degrees, summed each row and took the min.
I expected it to be too slow but it runs in a couple of seconds or so for part 2.#2021-12-0723:22Björn EbbinghausI derived the sum of the consumption of the crabs for an alignment x
https://twitter.com/MrEbbinghaus/status/1468359022453612549#2021-12-0705:48Miķelis VindavsI can share a pro tip I figured out for myself today: Running today’s code on yesterday’s input is most likely not going to work 😄#2021-12-0708:18euccastroI got bitten by that mistake after reading this!#2021-12-0717:55lreadI also stated with this “tactic”.#2021-12-0706:59fingertoeAll caught up! My bingo card computation was buggy and overcomplicated. Rewrote it successfully today. Burnt out at about 23 stars last year. Better momentum this time..#2021-12-0708:47Alekshttps://twitter.com/algrison/status/1468129198128648193#2021-12-0709:54AleksHaha, it reminds me about day 22 last year
https://adventofcode.com/2020/day/22#2021-12-0717:51lreadUh oh, for me, part 1 test and real data work, part 2 test data works and real data fails. Hmm… dang.#2021-12-0718:16Antonio BibianoWhat was your approach?#2021-12-0718:20lreadFor part1 I found pos via the median of positions, then calced cost.
For part2 I started with brute force calcing cost for each possible pos, but found this slow, so I optimized via a binary-search-ish strategy.
This leads me to same wrong answer for real-data, only faster. simple_smile#2021-12-0718:28Antonio BibianoAh I see I did also a brute force approach but not optimized at all :D#2021-12-0718:35sarcilavI also did binary search, it could be either and error on the cost function or on the stop condition of the binary search#2021-12-0718:36sarcilavare you doing binary search over the range from min to max pos or just on existing positions?#2021-12-0718:39lreadI’m guessing it must be my cost function because my brute force also fails in same way.#2021-12-0718:40lreadBut costs all look good for test data. So… must be something silly… but I don’t know what yet.#2021-12-0718:49lreadOh yeah, very silly! I don’t know why I was, but I was answering the with the position and not the fuel cost.#2021-12-0718:51lreadI have no excuses. simple_smile#2021-12-0719:13StuartCan someone help with my code for part 2 today, I'm getting an arrity exception and I've not idea why. Code in thread in case it's a spoiler.#2021-12-0719:14Stuart(defn build-row [min max n]
(let [to-max (reductions + (u/range-inclusive 1 (- max n)))
to-min (reverse (reductions + (u/range-inclusive min n)))]
(concat to-min [0] to-max)))
(let [input (f/parse-csv-ints "puzzle-inputs/2021/day7-test")
min (apply min input)
max (apply max input)]
(->> input
(map (partial build-row min max) input)
#_(apply map vector)
#_(mapv #(reduce + 0 %))
#_(sort)
#_(first)))
I'm getting arrity exception in the call to to build-row
, it says its getting 4 arguments#2021-12-0719:14Stuartbut i thought with partial, it will get min and max, that leaves one. Then it will get 1 from input.
input here is a list like (1 0 16 2 1 0 4)
#2021-12-0719:15pithylessthe input
inside map#2021-12-0719:15pithyless(->> input
(map (partial build-row min max) input)
#2021-12-0719:15Stuartoh balls! I missed that! so input is going in twice isnt it#2021-12-0719:15Stuartthank you#2021-12-0719:15pithylessHappy to duckie :)#2021-12-0810:36Pradeep Bgood catch @U05476190 and nice to see you around.#2021-12-0720:06tschadymy 💰 is on a grid problem tonight#2021-12-0720:11sarcilavmine on a graph one#2021-12-0720:20Stuartplease god, no graphs#2021-12-0720:11Antonio Bibianoahaha i bet on a "puzzle" thing#2021-12-0721:08Phil ShapiroI'm hoping for another interpreter / mini machine language one, those are pretty fun.#2021-12-0722:13tschadyi’m still working on assembunny
interpreter from 2016#2021-12-0721:49Cora (she/her)I might mess with fennel for days 6 and 7#2021-12-1112:02Sidestephow come? how does it help?#2021-12-1112:48Cora (she/her)just to learn something new ¯\(ツ)/¯#2021-12-0723:32lreadIs that your fennel answer?#2021-12-0804:56Aleks🧵Day 8 answers thread: post your answers here#2021-12-0805:58mchampine(defn procline [l]
(->> (str/split l #"\|")
(map str/trim)
(util/split-all-spaces)))
(def input
(->> (util/load-lines "resources/day08.data")
(map procline)))
;; part 1
(->> (map second input)
(map #(map count %))
(map #(filter #{7 4 2 3} %))
(apply concat)
count)
;; => 421
;; part 2
(defn num-common [a b]
(count (filter (set (sort a)) (sort b))))
(defn decoderfn [gbc]
(zipmap
(->> (select-keys gbc [2 3 4 7])
vals
(map first))
[1 7 4 8]))
(defn nmaps [sharemap gbc decode-em n]
(let [codeslen-n (get gbc n)
nums (map sharemap (map decode-em codeslen-n))]
(zipmap codeslen-n nums)))
(def sharemap5 {'(1 2 2) 2 '(2 3 3) 3 '(1 2 3) 5})
(def sharemap6 {'(1 2 3) 6 '(2 3 4) 9 '(2 3 3) 0})
(defn outval [[signals patterns]]
(let [gbc (group-by count signals)
decoder (decoderfn gbc)
vk147 (map first (vals (select-keys gbc [2 3 4])))
decode-em (fn [code] (map (partial num-common code) vk147))
mapper (merge decoder
(nmaps sharemap5 gbc decode-em 5)
(nmaps sharemap6 gbc decode-em 6))]
(Integer/parseInt (apply str (map mapper patterns)))))
(reduce + (map outval input)) ;; 986163
#2021-12-0806:19normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day8/main.clj Crude first pass, but it works. whee#2021-12-0807:13petercCould set/subset?
have helped you in your has-all
function?#2021-12-0807:14Aleksa terrible one but it does its job 👻
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_08.clj#2021-12-0807:21R.A. PorterIt's...adequate.
https://coyotesqrl.github.io/advent-of-code/2021/#/src%2Fcoyotesqrl%2F2021%2Fday8.clj#2021-12-0807:36raicotophttps://github.com/raicotop/advent-of-code-2021/blob/main/src/advent_of_code_2021/day-08.clj#2021-12-0808:22nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day08.clj#2021-12-0809:50delaguardohttps://github.com/DeLaGuardo/adventofcode2021/blob/main/src/aoc/day_8.cljc#2021-12-0810:02genmeblogWent a path of segments difference https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day08.clj#2021-12-0810:10delaguardo;; 0 2 3 5 6 9
(frequencies '(a b c e f g a c d e g a c d f g a b d f g a b d e f g a b c d f g))
(into (sorted-map) '{a 6, b 4, c 4, e 3, f 5, g 6, d 5})
;; => {a 6, b 4, c 4, d 5, e 3, f 5, g 6}
;; 1 4 7 8
(frequencies '(c f b c d f a c f a b c d e f))
(into (sorted-map) '{c 4, f 4, b 2, d 2, a 2, e 1})
;; => {a 2, b 2, c 4, d 2, e 1, f 4}
looks like it is possible to solve second part using frequencies only, without set operations#2021-12-0810:29delaguardoyep ) it is definitely possible )
(let [data (:input (first input-data))
{a 2
b 4
c 3
d 7
e 5
f 6} (group-by count data)]
(ml/matches (ml/matcher '[{?a 2, ?b 2, ?c 4, ?d 2, ?e 1, ?f 4}
{?a 6, ?b 4, ?c 4, ?d 5, ?e 3, ?f 5, ?g 6}])
[(frequencies (flatten (concat a b c d)))
(frequencies (flatten (concat e f)))]))
;; => ({?a \c, ?b \e, ?c \d, ?d \g, ?e \f, ?f \b, ?g \a})
#2021-12-0812:31Aleks@U04V4KLKC amazing! It seems you missed ?g 1 in the first map, or am I wrong?#2021-12-0812:33delaguardoOops, you are right)#2021-12-0813:53erdossolved with core logic:
https://gist.github.com/erdos/e2a704552532554a209e8a7e23d8491e#2021-12-0814:09Callum Oakleybrute forced the permutations since there are only 7! (5040) of them https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/08.clj
takes 700ms#2021-12-0814:56tschadyI took a hybrid approach between freqs and string diffs. I really wanted to try logic programming, but I was way past the Ballmer peak at that point last night.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d08.clj#2021-12-0815:11gaboUsing sets https://gist.github.com/galuque/fdeba14c6103bf6482b6f7c53fd645db#file-aoc2021_day_8-clj#2021-12-0816:09tschadytoo bad it’s not a line parsing competition:
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d08.clj#L9#2021-12-0816:13AleksRewrote my solution with freqs
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_08.clj#2021-12-0819:43Antonio Bibianooh man i'm really struggling today#2021-12-0820:05Mikko Koskihttps://github.com/rap1ds/advent-of-code-2021/blob/main/src/day8.clj#2021-12-0820:23StuartI just had to brute force, even doing it on paper I couldn't see how to deduce the test input to get all the values.
Part 1
(defn parser [line]
(let [[xs ys] (str/split line #" \| ")]
[(str/split xs #" ") (str/split ys #" ")]))
;; part 1
(let [input (f/read-all-lines-and-parse "puzzle-inputs/2021/day8" parser)]
(->> input
(map second)
(apply concat)
(map count)
(filter #(some #{2 3 4 7} #{%}))
(count))) ; 247
#2021-12-0820:23StuartPart 2
(defn parser [line]
(str/split line #" \| "))
(def numbers {#{\c \f} 1
#{\a \c \d \e \g} 2
#{\a \c \d \f \g} 3
#{\b \c \d \f} 4
#{\a \b \d \f \g} 5
#{\a \b \d \e \f \g} 6
#{\a \c \f} 7
#{\a \b \c \d \e \f \g} 8
#{\a \b \c \d \f \g} 9
#{\a \b \c \e \f \g} 0})
(defn all-combos [xs]
(combo/permutations xs))
(defn get-replacer [[a b c d e f g]]
{"a" a, "b" b, "c" c, "d" d, "e" e, "f" f, "g" g})
(defn decoded->int [decoded]
(Integer/parseInt (str/join "" decoded)))
(defn to-display-num [num]
(map set (str/split num #"\s")))
(defn solve-line [[input to-solve]]
(loop [[perm & rest] (all-combos ["a" "b" "c" "d" "e" "f" "g"])]
(if (nil? rest)
:not-found
(let [replacements (get-replacer perm)
input' (str/replace input #"a|b|c|d|e|f|g" replacements)
nums (to-display-num input')]
(if (every? numbers nums)
(->> (str/replace to-solve #"a|b|c|d|e|f|g" replacements)
(to-display-num)
(map numbers)
(decoded->int))
(recur rest))))))
(let [input (f/read-all-lines-and-parse "puzzle-inputs/2021/day8" parser)]
(->> input
(map solve-line)
(reduce +)))
#2021-12-0820:28jacoelhoUsing mainly exclusions https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day08.clj
separate based on the old clojure-contrib, not sure if there is a replacement#2021-12-0820:31Sam AdamsMy (rough) core.logic-based solution: https://samadams.dev/2021/12/08/advent-of-code-day-8.html#2021-12-0821:20Vincent CantinAfter running out of heap memory by trying to solve it via constraint propagation via recursion, I solved it in this simpler way:
(ns aoc-2021.day-8
(:require [ :as io]
[clojure.string :as str]
[clojure.set :as set]
[aoc.util :refer [comp->]]))
(def input
(->> (io/resource "2021/day8.txt")
slurp
str/split-lines
(mapv (fn [line]
(vec (re-seq #"\w+" line))))))
;; Part 1
(->> input
(mapcat (fn [line]
(subvec line 10)))
(filter (comp-> count #{2 4 3 7}))
count)
;; Part 2
(defn solve [line]
(let [digits (subvec line 0 10)
secrets (subvec line 10)
count->digits (group-by count (mapv set digits))
mapping {1 (-> 2 count->digits first)
7 (-> 3 count->digits first)
4 (-> 4 count->digits first)
8 (-> 7 count->digits first)}
mapping (assoc mapping 3 (-> 5 count->digits
(->> (filter #(set/superset? % (mapping 7))))
first))
mapping (assoc mapping 2 (-> 5 count->digits
(->> (remove #{(mapping 3)}))
(->> (filter #(= (count (set/intersection % (mapping 4))) 2)))
first))
mapping (assoc mapping 5 (-> 5 count->digits
(->> (remove #{(mapping 3) (mapping 2)}))
first))
mapping (assoc mapping 9 (-> 6 count->digits
(->> (filter #(set/superset? % (mapping 4))))
first))
mapping (assoc mapping 0 (-> 6 count->digits
(->> (remove #{(mapping 9)}))
(->> (filter #(set/superset? % (mapping 1))))
first))
mapping (assoc mapping 6 (-> 6 count->digits
(->> (remove #{(mapping 9) (mapping 0)}))
first))
rmapping (into {} (map (fn [[k v]] [v k])) mapping)]
(->> secrets
(map set)
(map rmapping)
(apply str)
parse-long)))
(transduce (map solve) + input)
; => 936117
#2021-12-0821:22Andrew ByalaI'm feeling ok about my solution. I threw together a few letfn
definitions to make my solution for each signal a bit easier on the eyes.
• https://github.com/abyala/advent-2021-clojure/blob/main/docs/day08.md
• https://github.com/abyala/advent-2021-clojure/blob/main/src/advent_2021_clojure/day08.clj#2021-12-0821:27Andrew ByalaI'm making my way through the code, but I really like @U016C0EGHUN' parsing logic, calling (map #(partition-by #{"|"} %) lines)
to split both sides of the input line. I never thought of using a set of the delimiter to split the data sides (`false`) from the delimiter itself (`true`).
And I hope you liked that little compliment, because I don't understand core.logic and it looks rather intimidating!#2021-12-0822:36Antonio Bibiano#2021-12-0822:37Antonio Bibianodone, a mix of segment frequency and a check with the number 4 to solve one ambiguity..#2021-12-0822:37Sam AdamsThanks Andrew! And that makes two of us 😁#2021-12-0822:40karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day8.clj
really enjoyed today task. the first part was quite a breeze, the second one took more time. The core idea was that I made a function that given the input creates a possible substition map like:
{\a #{\c \f}
\b #{\g \d \c}}
etc. which was then just the case of substituting code looking for easy substitutions (where there is only one possibility in set) and removing them from other possibilities. If there were no easy substitution the code would make a "guess" and fork on possible substitutions based on that guess
I made an assumption that until substitution is solved or there is an easy pick (one which has only one possibility to substitute) there will be always at least one substitution that have only 2 possibilities and then did a fork on each of those substitutions when looking up for solutions. It proved to be enough but would really like to later modify my code so when it has to guess it will fork on the lowest guess count needed
Fixing this assumption went much faster than I thought, so the code now if there is no easy substitution selects the ones with the lowest guesses needed and calls fn again recursively with each guess substituted in possibilities#2021-12-0822:53Sam Adams@U01HHBJ56J1 your writeup flows very smoothly, and I like that the your code bits stand on their own with the commentary beforehand — I should not have mixed mine together in today’s blog#2021-12-0823:47Björn EbbinghausI think I have a good solution. Just based on set cardinality / intersection / difference
https://github.com/MrEbbinghaus/advent-of-code/blob/master/2021/day08.clj#L40
5ms for task 2 with slurp + parse + execute in babashka#2021-12-0900:57euccastroafter some fumbling around I went for brute force in this one (takes about 15sec): https://github.com/euccastro/advent-of-code-2021/blob/main/day8.clj#2021-12-0900:59kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/8a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/8b.clj. Brief, but I wonder how I could improve the second part.#2021-12-0901:16euccastro@U1UHFHABV: you can use (let [{matches true misses false} (group-by f all)] ,,,)
for separate
#2021-12-0905:41Vincent Cantin@U067R559Q I think you deserve the achievement title "Mr. frequencies" 🙂#2021-12-1101:57Felipehttps://github.com/FelipeCortez/advent-of-code/blob/master/2021/08.clj#2021-12-1101:58Felipehonestly relieved to see everyone else's solutions aren't like 10 lines#2021-12-0814:28Benjaminday8 spoilers#2021-12-0814:28Benjamindoes it make sense to use core.logic?#2021-12-0814:29erdosNot really, or at least not in a naive way. I have a https://gist.github.com/erdos/e2a704552532554a209e8a7e23d8491e in it but it is horribly slow.#2021-12-0817:09nbardiukShort animation how algorithm slowly converges on answer#2021-12-0817:09nbardiukBrightness of yellow represents certanty in output, brighter green is processed input#2021-12-1308:43jaihindhreddyLooks very interesting. Mind sharing the code? (Or describing the algorithm?)#2021-12-1308:52jaihindhreddyNevermind. Found it on your github 😃#2021-12-0817:19Alekshttps://twitter.com/algrison/status/1468541254455771139#2021-12-0904:44Aleks🧵Day 9 answers thread: post your answers here#2021-12-0905:45mchampinePart 1 quick and hacky but it works:
;; part 1
(def input
(->> (util/load-lines "resources/day09.data")
(util/split-lines-re #"")
(mapv util/parse-ints)
(map vec)
(into [])))
(defn addpairs [[x1 y1] [x2 y2]] [(+ x1 x2) (+ y1 y2)])
(def surround [[1 0] [0 1] [-1 0] [0 -1]])
(defn neighbors [posn] (map addpairs (repeat posn) surround))
(defn adjs [brd pt]
(remove nil? (map (partial util/getxy brd) (neighbors pt))))
(defn islowest? [brd pt]
(< (util/getxy brd pt) (first (sort (adjs brd pt)))))
(defn low-points [brd]
(for [x (range (count (first brd)))
y (range (count brd))
:when (islowest? brd [x y])] (util/getxy brd [x y])))
(reduce + (map inc (low-points input)))
;; => 530
;; part 2
(defn neighbors-on-board [brd pt]
(filter #(util/getxy brd %) (neighbors pt)))
(defn step [brd acc-basin]
(let [bn (map (partial neighbors-on-board brd) acc-basin)
dac (distinct (apply concat bn))
nn (filter #(not= 9 (util/getxy brd %)) dac)]
(into acc-basin (set nn))))
(defn basin-size-at [brd pt]
(count (util/fixed-point (partial step brd) (set [pt]))))
(->> (map (partial basin-size-at input) (low-ptsxy input))
sort
reverse
(take 3)
(reduce *))
;; => 1019494
#2021-12-0906:06normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day9/main.clj#2021-12-0906:07Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_09.clj#2021-12-0907:05Vincent CantinSimple solution, nothing special ... didn't even use frequencies
.
(ns aoc-2021.day-9
(:require [ :as io]
[clojure.string :as str]
[aoc.util :as util :refer [comp->]]))
(def input
(->> (io/resource "2021/day9.txt")
slurp
str/split-lines
(mapv (fn [line]
(mapv (comp-> str parse-long) line)))))
;; Part 1
(defn adjacents [[y x]]
[[y (dec x)]
[y (inc x)]
[(dec y) x]
[(inc y) x]])
(->> (for [[y row] (util/seq-indexed input)
[x n] (util/seq-indexed row)
:let [min-adj (->> (adjacents [y x])
(keep (fn [position]
(get-in input position)))
(reduce min))]
:when (< n min-adj)]
(inc n))
(reduce +))
;=> 631
;; Part 2
(->> (for [[y row] (util/seq-indexed input)
[x n] (util/seq-indexed row)
:let [min-adj (->> (adjacents [y x])
(keep (fn [position]
(get-in input position)))
(reduce min))]
:when (< n min-adj)]
(loop [basin #{}
edges #{[y x]}]
(if (seq edges)
(let [new-edges (into #{}
(comp (mapcat adjacents)
(remove (fn [pos]
(= (get-in input pos 9) 9)))
(remove basin))
edges)]
(recur (into basin new-edges)
new-edges))
(count basin))))
(sort-by identity >)
(take 3)
(apply *))
; => 821560
#2021-12-0907:09Aleks> didn’t even use `frequencies` #2021-12-0907:24nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day09.clj#2021-12-0908:48genmebloglava!#2021-12-0908:55nbardiuksmoke settles down#2021-12-0909:05genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day09.clj#2021-12-0909:19Callum Oakley#2021-12-0909:19delaguardohttps://github.com/DeLaGuardo/adventofcode2021/blob/main/src/aoc/day_9.cljc#2021-12-0909:23delaguardobooooring day, couldn't find how to use frequencies (#2021-12-0910:49genmeblog@U01HL2S0X71 check out this: https://stackoverflow.com/questions/3906831/how-do-i-generate-memoized-recursive-functions-in-clojure#2021-12-0911:32Joehttps://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day09.clj#2021-12-0911:33borkdudeDay 9 in #babashka and #clojure
https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_d09-clj#2021-12-0912:18miikkaIt was a bit too complicated to do in REPL but I did it anyway... here are the choice parts from my REPL history 😎 https://gist.github.com/miikka/48bab1596937814048d0c9fce9f1e4c2#2021-12-0912:21miikkaOne day I will start doing the thing where you have a scratch file in the editor and you send to REPL from there... but not today.#2021-12-0912:22borkdude@U1NDXLDUG It's a sunk cost once you start typing right. But with Rebel Readline you might stay there forever ;)#2021-12-0912:24miikkaThat's a good point, I should set up Rebel again. I used to use it, but then I got a new computer at some point and forgot about it#2021-12-0912:26borkdudeto be honest, I haven't used it much either. when I find myself in a console REPL, I just use load-file
. But with babashka, I just run the entire file every time... The shell is my REPL :)#2021-12-0912:26miikkaHeh, yeah, that's nice about bb#2021-12-0913:18tschadypretty psyched i was able to only need my grid library from prior years. neigbors
, build-grid
, connected-adjacency-map
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d09.clj#2021-12-0913:18borkdudeyou were waiting for the grid, weren't you :)#2021-12-0913:19tschadyhttps://clojurians.slack.com/archives/C0GLTDB2T/p1638907616410900#2021-12-0913:19tschady1 day off 🙂#2021-12-0914:25genmeblogbasins!#2021-12-0914:28Vincent Cantin@U1Z392WMQ next, a bestagon-based problem#2021-12-0914:28tschadybest shape!#2021-12-0915:13Callum Oakleytime for the annual spike in traffic to https://www.redblobgames.com/grids/hexagons/ ?#2021-12-0916:36tschadysame with https://oeis.org#2021-12-0917:24Sam AdamsMine’s on the slower side — I didn’t realize that a basin couldn’t have more than one local minimum inside it https://samadams.dev/2021/12/09/advent-of-code-day-9.html#2021-12-0917:45ACI also didn't think about the "one local minimum" fact -- I would have probably done something different.
instead I painted each square with a color based on what was "up" or "left" of it and occasionally merging paint colors (when connecting two previously disjoint basins).#2021-12-0918:24Antonio Bibianoi struggled a lot with stackoverflows a bad recursion 😄 https://gist.github.com/antbbn/5907c3c2f733e5156140420b2cb49568#file-day9-clj#2021-12-0920:09Antonio Bibianovery nice write-up @U016C0EGHUN#2021-12-0920:40StuartPart 1
(defn parser [s]
(->> (str/split s #"")
(mapv #(Integer/parseInt %))))
(defn find-low-points [input]
(let [height (count input)
width (count (first input))]
(for [w (range 0 width)
h (range 0 height)
:let [n (get-in input [h w])
u (get-in input [(dec h) w] 10)
d (get-in input [(inc h) w] 10)
l (get-in input [h (dec w)] 10)
r (get-in input [h (inc w)] 10)]
:when (and (< n u) (< n d) (< n l) (< n r))]
{[h w] n})))
;; part 1
(let [input (->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day9" parser))]
(->> input
(find-low-points)
(mapcat vals)
(map inc)
(reduce +)))
#2021-12-0920:41StuartPart 2: I find it so confusing working with 2d vectors and reversing the [x y]
to [y x]
(defn get-neighbours [input [y x]]
(let [yx' [[y (dec x)] [y (inc x)] [(dec y) x] [(inc y) x]]]
(remove (fn [yx] (= 9 (get-in input yx 9))) yx')))
(defn walk-basins [input visited size to-visit]
(if (empty? to-visit)
size
(let [yx (first to-visit)
neighbours (->> (get-neighbours input yx)
(remove (fn [yx] (or (visited yx) ((set to-visit) yx)))))]
(recur input (conj visited yx) (inc size) (into (rest to-visit) neighbours)))))
(let [input (f/read-all-lines-and-parse "puzzle-inputs/2021/day9" parser)
walk-basin-fn (partial walk-basins input #{} 0)]
(->> input
(find-low-points)
(mapcat keys)
(map vector)
(map walk-basin-fn)
(sort >)
(take 3)
(reduce * 1)))
#2021-12-0921:45karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day9.clj
here is mine solution for day9, nothing fancy, but this day it helped me to do some crude drawings by using print and println to see that basins are properly covered (a protip (str some-char \u0333)
will print this char with a double underscore directly under it so you can print the whole array easily and mark selected elements).
It wasn't really that hard but in part 2 I had to realize that you can't too eagerly append cells to visited history as the same cell visited from different neighbours can both count as basin part and not#2021-12-0921:46Stuart> (str some-char \u0333)
will print this char with a double underscore directly under
Woah! Nice!#2021-12-0922:04karolyeah, gotta love unicode 😄 I am developing mostly using Emacs REPL so not resorting to external tools when doing visualizations is a big plus. this is how it looked printed:#2021-12-0922:05karol#2021-12-0922:24euccastrotoday I flooded basins with loop/recur: https://github.com/euccastro/advent-of-code-2021/blob/main/day9.clj#2021-12-1004:54kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/9a.clj Identified low points by rows and by columns, then intersected the sets
https://github.com/kconner/advent-of-code/blob/master/2021/9b.clj Flood filling with sets; each recursive step expands the complete border#2021-12-1117:43Felipesuper mutable flood fill
https://github.com/FelipeCortez/advent-of-code/blob/master/2021/09.clj#2021-12-1118:41Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day9.clj man your solutions are so simple. Learning a lot#2021-12-0905:50samedhiJust finished day 6 and I think the clojure solutions definitely beat out the SQL ones -> https://github.com/mitchellh/advent-2021-sql/blob/main/day06/answer_p2.sql#2021-12-0912:11mauricio.szaboAre you doing in SQL too? 😄#2021-12-0912:43mauricio.szabo@U0532BYNC my solution in SQL is incredibly faster than Clojure, to be honest: https://gitlab.com/mauricioszabo/advent-of-code-2021/blob/master/src/day-06.sql#2021-12-0915:56samedhiNo, I'm doing Clojure. And wow, your solution seems much less noisy than the one I linked. Impressive.#2021-12-0915:57samedhiI was talking more on whether I could understand it, yours is much more legible. (Though I have to squint as I am not great at SQL, haha)#2021-12-0905:50samedhiSQL definitely had a lead on the earlier days... :]#2021-12-0911:29StuartSQL gives me nightmares. I've been hurt by too much bad batshit insane SQL at work.#2021-12-0916:01samedhiHonestly I very rarely do more than select, insert, update, delete in the most basic ways.#2021-12-0916:03samedhiI know SQL can be crazy performant if you can ask the right question, but often I just
1. pull all of the data that I need (maybe 1 WHERE clause)
2. convert them to clojure data structures (maps)
3. do some sequence processing stuff
4. write them back to the dabase
5. all within a transaction#2021-12-0912:23mauricio.szaboCan someone help me with Day 08? I can't understand exactly the problem to be solved, why there are 10 measurements and 4 results, etc...#2021-12-0912:25StuartThe ten measurements are the clues you have to use to figure out what the 4 numbers are after the |
YOu don't have enough info using just the 4 values#2021-12-0912:27Stuartacedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf
So here, we know that ab
is 1 since it only has 2 "segments"
and we know that eafb
is four, as it has 4 segments.
However, we still don't know what a
or b
is in 1, a
is c
or f
, and b is c
or f
.#2021-12-0912:27StuartYou need to figure out what all the numbers on the left of the bar are.
Once you have figured that out, you can then match them to the four parts after the bar. This will give you a 4 digit number#2021-12-0912:29Stuart8 7 4 1
acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf
So you know 4 of the numbers, how will you work out the rest ?#2021-12-0912:30StuartAn important thing is that every line in the puzzle input is an individual problem to solve. The segments are mixed up differently for every line#2021-12-0912:53mauricio.szaboYeah, I still don't get it. I know that the left side is supposed to be measurements, and the right side, what's displayed. But why there are 10 measurements to 4 digits?#2021-12-0912:55StuartIf there were only the 4 measurements I don't think you would have enough information to figure out what the four digits are.
e.g. if you only had cdfeb fcadb cdfeb cdbaf
, then i believe their is no way to work out which digits those are#2021-12-0912:55Stuartbut given the 10 examples on that row, you can work out what the 10 examples are then just match them to the 4#2021-12-0912:55Stuartbasically you need to only work out the 4 digits to the right, but you need the 10 digits to the left to figure that out#2021-12-0912:58Stuartso in the example in this thread, the 4 digits after the bar are 5353. You couldn't figure that using only the 4, I mean, it could be 3535. But with those 10 you can figure out that its 5353#2021-12-0912:58mauricio.szaboAh, ok, so the measurements mean that "I gave this measurements, and some of these displayed these numbers, but I don't know which one displayed which number"?#2021-12-0912:58Stuartyes#2021-12-0912:58Stuartyou know ab
is 1 as 1 is only the digit that has only 2 segments#2021-12-0912:59Stuartbut a 1 should be
....
. c
. c
....
. f
. f
....
So you need to figure out if a
is c
or f
#2021-12-0913:00Stuarthint: Certain numbers are subsets of other numbers, and some numbers are supersets of other numbers.#2021-12-0913:04StuartYou don't actually need to figure out exactly what characters match to what segments. You can just figure out what "words" relate to what numbers#2021-12-0913:30tschadythe left side represents the digits 0->9 (in some order), in that lines’ particular cipher#2021-12-0915:29mauricio.szaboAh, ok, thanks 🙂.#2021-12-0912:59Antonio Bibianosorry peeps, i need some help with day 9 potential spoilers in thread#2021-12-0913:00Antonio Bibianofor part 2 I ended up with this recursive function#2021-12-0913:00Antonio Bibiano(defn get-basin [heightmap points]
(into #{}
(mapcat (fn [point]
(let [basin-neighbors (get-basin-neighbors heightmap point)]
(if (empty? basin-neighbors)
[point]
(conj (get-basin heightmap basin-neighbors) point))))
points)))
#2021-12-0913:01Antonio Bibianoget-basin-neighbors
returns a list of neighbors that can be in the basin, ie no 9 and not the point itself#2021-12-0913:02Antonio Bibianothe heightmap
is a nested vector of the numbers#2021-12-0913:02Antonio Bibianoworks for the example input but i get a stack overflow error on the large input#2021-12-0913:09miikkaHmm; I'm a bit surprised that it works with the small input since it looks like it would end up in an infinite loop in both cases#2021-12-0913:10miikkaIf you have a point and then you call get-basin on its neighbours, doesn't that call end up calling get-basin on the original point?#2021-12-0913:13Antonio Bibianoi only get the neighbors where the number is higher than the current one#2021-12-0913:15Antonio Bibianoit's true that it does some unnecessary calculations#2021-12-0913:15Antonio Bibianobut it should end up in an infinite loop#2021-12-0913:15miikkaOh, okay#2021-12-0913:17miikkaI wonder if the big one just has too big basins, then, for the recursion to work (without using loop
/`recur` )#2021-12-0913:19genmeblogthe biggest basin in my dataset is 98#2021-12-0913:19Antonio Bibianodoes the fact that I pass the heightmap
as an argument make things worse?#2021-12-0913:20genmeblograther not#2021-12-0913:28miikkaWith mapcat in play, I don't have super clear feel about the recursion depth but seems like it could work :man-shrugging:#2021-12-0913:28genmeblogget-basin-neigbours
can return the same neighour for diffent input#2021-12-0913:29genmeblogand you visit the same points many times#2021-12-0913:30miikkaHmm, if get-basin-neighbors
only goes uphill, seems like you'd get wrong result for a basin with two low points. But that's a separate issue from the stack overflow#2021-12-0913:34Antonio Bibianoyeah @U1EP3BZ3Q i thought it would be harmless, but maybe not ..#2021-12-0913:34Antonio Bibianoi'll try a loop/recur refactor and to make it less wasteful#2021-12-0913:35miikkaOh, the problem statement says that each point belongs to only one basin, so what I said is not an issue#2021-12-0913:42Aleks@U01HY37QQUA BFS#2021-12-0914:12sarcilavmaybe this it the problem
> i only get the neighbors where the number is higher than the current one#2021-12-0914:14sarcilavwhat it is the output of something like
012190
232299
111111
#2021-12-0914:14sarcilavon your code @U01HY37QQUA#2021-12-0914:14sarcilavor your basins better#2021-12-0918:04Antonio Bibianothanks for your help! I did it
(defn get-basin-new [heightmap points]
(loop [ret #{} points points]
(if (empty? points)
ret
(let [cur-point (first points)
basin-neighbors (remove ret (get-basin-neighbors heightmap cur-point))]
(recur (conj ret cur-point) (concat (rest points) basin-neighbors))))))
#2021-12-0918:06Antonio Bibianoturns out visting the same place many times was really messing with the recursion!#2021-12-0918:07Antonio Bibiano@U0C5L73ST that's a very valid concern, but I think the input is simpler for today#2021-12-0918:16Antonio Bibianoah wait the second if is not necessary! refactored#2021-12-0918:24Antonio Bibiano@U067R559Q is that similar to what you pointed me to with BFS?#2021-12-0919:06Aleks@U01HY37QQUA, yes https://en.wikipedia.org/wiki/Breadth-first_search#2021-12-0919:11Antonio Bibianoah yeah that's where I ended up#2021-12-0919:12Antonio BibianoLooks like I could have used a queue here#2021-12-0919:12Antonio Bibianobut didn't see any solution using queues#2021-12-0919:19AleksOnce, I implemented my own a minesweeper game. Does it look similar to today’s problem? 🙂#2021-12-0919:12StuartFor day 9 part 2, when walking the basins, do you want to only include the squares that are within 1 of the current square, e.g.
If you were at 5 here, would valid neighbours for the walk be only the 6s or the 8s too ?#2021-12-0919:14peterc6s and 8s#2021-12-0919:14Stuartthanks!#2021-12-0920:38StuartEverytime you refresh the 2021 page the waves change 🙂#2021-12-0920:56tschadyfor extra motivation. when you complete the year you get that continual animation#2021-12-0921:39lreadThis is my first year trying the Advent of Code. I am finding the puzzles tremendous good fun. For all you veterans, do you typically complete all 25 days?#2021-12-0921:46tschadyi do 50-100% depending on my schedule, then chip away at problems that interest me during the year. i think i’ve done 2/3 of all so far.#2021-12-0921:47tschadythere’s a considerable time ramp up around the 15th#2021-12-0921:47StuartThe best I've ever done was last year, 36 stars.#2021-12-0921:47StuartAnd a chunk of those 36 were done this year#2021-12-0921:49lreadGood to know, thanks, so it is a gift that can keep on giving, even into the new year!#2021-12-0921:55tschady2015 is the easiest year, i think. good place to start.#2021-12-0921:58lreadOh right... I could visit puzzles of advents past. Interesting...#2021-12-0922:10Phil Shapiro2020 seemed easier to me than 2019 and 2018. Or maybe I'm getting better at writing advent code :). Most people don't complete the full calendar, you can look at the stats for each year to see completion rates per day. #2021-12-0922:16StuartYeah, I agree 2020 feels the easiest year so far.#2021-12-0922:17StuartThis year feels easier than 2020 though, up until this point.#2021-12-1000:08fingertoeThe first year I did 7, the second year, 13, This year I am 10 for 10.. As the holidays approach, there is a lot more competition for attention.. (also my wife isn't fond of obsessed coding guy).#2021-12-1013:20Vincent CantinI did all the stars last year while being busy because I failed at giving up.#2021-12-1013:21Vincent CantinThat's addictive after a couple of weeks.#2021-12-1016:45miikkaI usually do only the quick ones. If the top list times are >15 minutes, then I probably won't bother 😛#2021-12-1019:40lreadI feel kind of hooked right now. But the shine might come off after the puzzles become much more puzzling.#2021-12-1004:33samedhiI think I set a new land speed record for slowest possible code on Day 8 -> https://github.com/samedhi/advent-of-code-2021/blob/main/16.clj#2021-12-1004:59Aleks🧵Day 10 answers thread: post your answers here#2021-12-1005:26Fredrik#2021-12-1005:38normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day10/main.clj#2021-12-1006:05Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_10.clj#2021-12-1006:38kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/10a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/10b.clj. Feels good to me :)#2021-12-1008:34nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day10.clj#2021-12-1008:58genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day10.clj#2021-12-1009:03StuartDay 10 Part 1
(def scores {\} 1197
\) 3
\] 57
\> 25137})
(defn parser [line]
(map identity line))
(defn find-syntax-error [opens [f & r]]
(if (empty? r)
nil
(cond (#{\{ \( \[ \<} f)
(recur (conj opens f) r)
(#{\} \) \] \>} f) ;
(if (= f (matching (peek opens)))
(recur (pop opens) r)
f))))
(->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day10" parser)
(map (partial find-syntax-error []))
(remove nil?)
(map scores)
(reduce +))
#2021-12-1009:04StuartThis day is confusing calvas syntax highlighting!#2021-12-1009:24genmeblogI like your substitutions! Need to introduce some in emacs.#2021-12-1010:31Antonio Bibiano#2021-12-1010:32Antonio BibianoI noticed i'm using remove a lot#2021-12-1011:07cyppan#2021-12-1011:16cyppanswitching to transients is pretty easy 👌#2021-12-1011:24Callum Oakleyhooray for reduced
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/10.clj#2021-12-1012:39JoeFun puzzle! https://github.com/RedPenguin101/aoc2021/blob/main/day10.md, and https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day10.clj#2021-12-1013:14petercThis worked well for me:
(defn parse [l]
(loop [line l]
(let [new (-> line
(str/replace #"\[\]" "")
(str/replace #"\{\}" "")
(str/replace #"\<\>" "")
(str/replace #"\(\)" ""))]
(if (= (count new) (count line))
line
(recur new)))))
#2021-12-1013:38tschadySame stack based approach. I didn’t flag the results, just used the fact that if a coll is returned, it’s the unbalanced stack, if it’s a single char it’s the bad one.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d10.clj#2021-12-1014:16tschadyI wonder if he threw the <, >
in there just so you couldn’t use the clojure reader somehow#2021-12-1014:23Antonio Bibianothis is my regex approach#2021-12-1014:23Antonio Bibiano(defn fixed-point [f a]
(let [r (f a)]
(if (= r a)
a
(recur f r))))
(defn validate [line]
(let [fp (fixed-point #(string/replace % #"\(\)|\[\]|\{\}|\<\>" "") line)
invalid (re-find #"\)|\]|\}|\>" fp)]
[invalid (map open->close (string/reverse fp))]))
#2021-12-1016:34Sam Adamshttps://samadams.dev/2021/12/10/advent-of-code-day-10.html#2021-12-1016:39JLol => https://clojuredocs.org/clojure.core/pop#example-5a7e1ab7e4b0316c0f44f8b4#2021-12-1017:05StuartWell, that was a bit embarrasing how long it took to find the bug in (find-middle-score)
😖
Part 2
(def scores {\} 3
\) 1
\] 2
\> 4})
(def matcher {\{ \}
\[ \]
\< \>
\( \)})
(defn get-remaining [open [c & r]]
(if (nil? c)
open
(cond (#{\{ \[ \< \(} c)
(recur (conj open c) r)
(#{\} \] \> \)} c)
(if (= c (matcher (peek open)))
(recur (pop open) r)
nil))))
(defn score [auto-completes]
(reduce (fn [acc i]
(+ (* acc 5) (scores i))) 0 auto-completes))
(defn auto-complete [line]
(map matcher line))
(defn get-middle-score [scores]
(let [sorted-scores (sort scores)]
(nth sorted-scores (dec (Math/ceil (/ (count scores) 2.0))))))
(->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day10" parser)
(map (partial get-remaining []))
(remove nil?)
(map auto-complete)
(map reverse)
(map score)
(get-middle-score))
#2021-12-1018:38Antonio BibianoI found very surprising that this works just fine (nth [1 2 3] (/ 3 2))
#2021-12-1018:56tschadyi think because this casts it to int
: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L894#2021-12-1019:05Antonio Bibianopretty cool!#2021-12-1019:44mchampineLate to the party today.#2021-12-1019:49karolhttps://github.com/kfirmanty/advent-of-code-2021 found day10 to be much easier than few last ones. Will check other people solution but I guess most used list as stack to keep track of opened parens#2021-12-1021:45borkdudeMy day 10:
https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_d10-clj#2021-12-1022:27Travis Jeffersonhttps://github.com/tjefferson08/advent-of-code/blob/main/2021/10/core.clj#2021-12-1022:29borkdudeTweaked mine a little, both solutions run in about 1ms in babashka#2021-12-1023:01euccastrotoday's puzzle seemed relatively mundane, and so does my solution: https://github.com/euccastro/advent-of-code-2021/blob/main/day10.clj#2021-12-1118:20Felipeyeah, pleasant surprise! https://github.com/FelipeCortez/advent-of-code/blob/master/2021/10.clj#2021-12-1420:29Sidesteppart 1 (inspired by @U1NLKFVC4)#2021-12-1420:31SidestepCan somebody compare the performance of it to stack based implementation?#2021-12-1008:20borkdudeWatch a script and run tests while developing with babashka. Should come in handy for Aoc :)
https://github.com/babashka/babashka/discussions/1102#2021-12-1010:44nbardiuk#2021-12-1011:17Antonio BibianoVery nice! I wonder if <> where valid bracket a clojure ide could solve it#2021-12-1011:17Antonio BibianoAlso could would be to see a regex solution #2021-12-1012:13zxspectrrHi, I just want to say that as a beginner in clojure, I've learnt so much from this thread and peoples answers. :thumbsup:#2021-12-1012:14zxspectrrit has been breaking my brain a bit trying to decipher some of the solutions, but once I understand them I feel like I learned something new#2021-12-1016:28Nick McAvoyIf you like Clojure, and if you like Advent of Code, you might be interested in joining our remote Advent of Code meetup at Clojadelphia, next Thursday at 5pm EST. https://www.meetup.com/Clojadelphia/events/282565898/#2021-12-1017:10Sidesteplooks like day3 part2 was a breaking point for lots of peeps#2021-12-1017:10Sidestepmeaning number of devs gave up after that#2021-12-1017:10Sidestephttps://adventofcode.com/2021/stats#2021-12-1017:16Darin Douglassi could honestly see that, i was frustrated (mainly with how it was worded/presented) with that one the most#2021-12-1017:17StuartI think a lot of people don't know that if you don't complete a day, you can still do the next#2021-12-1017:17Sidestepha, actually I just found out that today#2021-12-1017:18Sidestepafter clicking next day willy nilly#2021-12-1017:30Sidestepdamn this slack is a mess#2021-12-1017:30Sidestepusability sucks#2021-12-1023:58samedhiFirst time in my life I have written a double barreled recur statement -> https://github.com/samedhi/advent-of-code-2021/blob/main/18.clj (problem 9 second section)#2021-12-1104:22R.A. PorterI needed Day 10. I still haven't been able to solve part 2 of Day 9 (I'm going to punt for now) even though I know how to solve it. I just can't seem to write an implementation that doesn't either short-cut in a way that breaks or blows out my stack in skipping shortcuts. But Day 10? That was built for Lispers.#2021-12-1118:34Jeff Evansagreed. day 10 was a joy#2021-12-1104:58Aleks🧵Day 11 answers thread: post your answers here#2021-12-1106:02normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day11/main.clj#2021-12-1106:04normanfastest time from part 1 to part 2 yet - it's always nice when that happens#2021-12-1106:59Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_11.clj#2021-12-1107:01AleksNeed to think if I can apply frequencies
here 😆#2021-12-1108:43AleksHere we go
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_11.clj#2021-12-1110:09nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day11.clj#2021-12-1112:00tschadyhttps://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d11.clj
17ms / 28ms#2021-12-1112:34Callum Oakleynot my most concise solution… avoids scanning the whole map any more than once per step by checking if an octopus is ready to flash at increment time and pushing it on a stack. lots of passing state around to make that work though. I was expecting part 2 to be “simulate for a really long time” 🤷 (I also didn’t look at the input and see that it was tiny facepalm)
13ms/42ms
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/11.clj#2021-12-1112:47JoeDay 11 https://github.com/RedPenguin101/aoc2021/blob/main/day11.md and https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day11.clj
One of those things where the code started out pretty messy, but I got into a 'virtuous spiral' of refactoring, ending up with a quite readable (I think) solution.
Definitely not fast! But sub-second, which is good enough I think.#2021-12-1114:34karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day11.clj - my first pass at solution - nothing fancy on my side, just plain loop
through the board but seems to do the trick and executes part-2 in 163ms
on my machine#2021-12-1117:02kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/11a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/11b.clj and yes you can use frequencies
🙂#2021-12-1117:14genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day11.clj#2021-12-1119:21Andrew ByalaWrote mine last night, and then rewrote it this morning. I used a recursive cascade-flashes
function instead of keeping track of which points I had already flashed; it was a little less efficient than my original loop-recur
, but I think it looks cleaner.
• https://github.com/abyala/advent-2021-clojure/blob/main/docs/day11.md
• https://github.com/abyala/advent-2021-clojure/blob/main/src/advent_2021_clojure/day11.clj#2021-12-1119:41Antonio BibianoMy solution for today#2021-12-1119:42Antonio BibianoI was really bummed that update-in
throws when given an invalid array position like [-1 0]#2021-12-1119:43Antonio Bibianoand at some point i learned that get-in
returns the whole coll if the key is nil#2021-12-1121:42Sam Adamsmy basic solution: https://samadams.dev/2021/12/11/advent-of-code-day-11.html#2021-12-1201:42StuartHorrible solution by me today. For whatever reason I couldn't get my head around grids, so I represented it as a flat vector. I also think I compensated for my brain not working by building it into a way too complicated data structure.
Each cell looked like this
{:n 0 :flashed false :flashes 0 :xy [0 0] :i 0}
I know, dumb.
BUt at least it's done, and it runs instantly.
https://gist.github.com/stuartstein777/65179a928273e201af0b256a7b024487#file-2021-day-11-clj-L7
Definitely one I need to rethink when my brain is working better and re-work#2021-12-1217:13euccastroI couldn't get to this yesterday. I expected second half to be harder; I was glad I had built step 1 on top of iterate
so I could just reuse it for step 2. I guess I could clean it up but I have to do day 12 first: https://github.com/euccastro/advent-of-code-2021/blob/main/day11.clj#2021-12-1107:16Alekshttps://twitter.com/algrison/status/1469555494461313026#2021-12-1119:23Andrew ByalaVery cool, @U067R559Q! What did you use for visualization?#2021-12-1204:56Aleks@U01HHBJ56J1 I didn’t do it. It is made by @UE27GJZR8
https://github.com/agrison/advent-of-code#2021-12-1110:33borkdudeI'm skipping today's one, I think. Another grid puzzle ;)#2021-12-1112:11SidestepSome devs suggested Fennel, which is Lua based, for some AOC challenges#2021-12-1112:11Sidestephow come? how does Fennel help?#2021-12-1112:48Cora (she/her)I was just trying it out, it doesn't really help#2021-12-1117:02genmeblogDay 11 animation, it's flashing (epilepsy warning) so I hid it in a thread. Cubic interpolation is used to generate bigger image.#2021-12-1117:04genmeblog#2021-12-1117:20genmeblogand code for that: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day11.clj#L75#2021-12-1117:33tschadyadvent-of-animations, I’m inspired.#2021-12-1117:48NoahTheDukethanks for the threaded animation! looks very cool but nice to not have flashing by default#2021-12-1119:34genmeblogYeah, I know it may be problematic for some people.#2021-12-1317:01winsomeI feel like I would be able to navigate even when the octopi aren't all synced up :p#2021-12-1119:54Antonio Bibianowhat's the plural of octopus? octopi?#2021-12-1120:50Cora (she/her)it's complicated #2021-12-1120:50Cora (she/her)https://www.merriam-webster.com/words-at-play/the-many-plurals-of-octopus-octopi-octopuses-octopodes#2021-12-1120:48StuartCan someone confirm something about Day 11 for me. Question in thread#2021-12-1120:48StuartFor the small example input
1 1 1 1 1
1 9 9 9 1
1 9 1 9 1
1 9 9 9 1
1 1 1 1 1
Does this eventually end up as
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
?#2021-12-1120:51nbardiukyes, octopuses eventually syncronize, all the values in the grid became the same#2021-12-1204:57Aleks🧵Day 12 answers thread: post your answers here#2021-12-1206:25normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day12/main.clj If I wrote code this ugly for work, I'd fire myself :)#2021-12-1206:44ACI’m not proud of mine either, but fortunately it got the job done. I need to do some refactoring - my part2 takes 2.5s which seems too long.#2021-12-1206:46normanYou have me beat by about 25s. #2021-12-1206:49kevincJust part one for now: https://github.com/kconner/advent-of-code/blob/master/2021/12a.clj#2021-12-1208:51AleksI will probably refact it later on. Solving of part 2 takes ~2366 msecs
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_12.clj#2021-12-1209:47nbardiukPart 2 is slow, although I've put some optimizations ~1.4s https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day12.clj#2021-12-1211:07jacoelhoEnd up using a map to track (and decrement) small caves visits. In part02 brute force explore with an increased allowance. Felt a bit cheating returning strings when reached the end, but I wasn't able to flatten it correctly.
Part 02 runs in like 1.4s on my machine
https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day12.clj#2021-12-1213:04Miķelis Vindavshttps://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/y2021/day12.clj#2021-12-1213:05Miķelis VindavsI initially misread the question and thought any cave can be visited twice per run, not just one#2021-12-1213:05Miķelis Vindavsbut only 1 cave makes it pretty easy to track, you don’t even have to track which one was visited twice#2021-12-1213:48Antonio BibianoThis is my attempt today..kinda unoptimized brute force :(#2021-12-1213:50JoeDay 12 https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day12.clj and https://github.com/RedPenguin101/aoc2021/blob/main/day12.md
My part 2 is extremely slow, but it's ~16 LOC, and I love how the solution code came out as just a statement of the problem:
(count (all-paths with-no-lc-revisits graph))
(count (all-paths with-one-lc-revisit graph))
#2021-12-1214:31tschady22ms/820ms. I use a map of number of times each cave can be visited, with big caves as ##Inf
, which you can dec
forever.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d12.clj#2021-12-1214:38Antonio Bibiano@U1Z392WMQ mine is similar to yours in the looping, but I was wondering what makes it slower, is it mostly the "check" that I do every time, while yours only checks the allowances and it's much faster?#2021-12-1214:43tschady@U01HY37QQUA couple things I can see at quick glance (might be wrong):
• (big one) I stop recursing on “end”, you keep going which is going to be a bigger search space.
• (small?) your .indexOf
is checking a vector for the current node, I use a map which is much faster.
• (small?) lots of repeat work in your part 2 allowed function#2021-12-1214:58Callum Oakleyrecursion counting the leaves, avoids actually building the paths
18ms/352ms
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/12.clj#2021-12-1215:09Antonio Bibiano@U1Z392WMQ thanks for checking! i think i also stop on "end" because in my graph "end" has no children#2021-12-1215:27Antonio BibianoI like these counting solutions!#2021-12-1216:26genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day12.clj#2021-12-1216:47Callum Oakleydown to 10ms/135ms with transduce
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/12.clj#2021-12-1217:18kevincBack with part 2: https://github.com/kconner/advent-of-code/blob/master/2021/12a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/12b.clj#2021-12-1217:27Sam AdamsSeparate DFS functions for parts 1 and 2… ?/340ms: https://samadams.dev/2021/12/12/advent-of-code-day-12.html#2021-12-1218:49ACMemoizing my lower-case? function sped up my part2 from 2.5s to 800ms.
Further refactoring of my logic got me to 228ms. Unfortunately it’s still pretty ugly code..#2021-12-1218:55Charles Comstockhttps://github.com/dgtized/advent-of-code/blob/master/2021/day12/passage_pathing.clj#2021-12-1220:01euccastrohttps://github.com/euccastro/advent-of-code-2021/blob/main/day12.clj#2021-12-1220:06euccastro500ms in my machine; I didn't do anything special to optimize it#2021-12-1220:24karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day12.clj here is a first solution that came to my mind, obviously unoptimized but even part-2 executes in 2 seconds which is not that bad. From the first reading of description when I saw that it will be graph based I got worried that it will be much harder than it was in reality as I managed to solve it without problems, but again this might be advent of code practice kicking in 😄
And this day definitely gets a shortest solve-2
definition, by it just being:
(defn solve-2 []
(with-bindings {#'can-visit-twice? true}
(solve-1)))
😄#2021-12-1220:24karolObviously got lazy and did not want to rewrite fns to get this flag passed on as argument as then it will be even shorter ;d#2021-12-1220:35StuartPart 1, Takes about 25 seconds
(defn parser [line]
(let [[start end] (str/split line #"-")]
[[start end] [end start]]))
;; input -> [{"start" "A"} {"start" "b"} {"A" "c"} {"A" "d"}]
;; output -> {"start" ["A" "b"], "A" ["c" "d"]}
(defn merge-vector-of-maps [xs]
(reduce (fn [acc [k v]] (update acc k conj v)) {} xs))
;; path-so-far -> {:path ["start" "A" "b"] :finished false}
;; given a map of continuations it gets the continatuations for the last item in the path-so-far path.
;; it excludes those that are lower-case and have already appeared in (:path path-so-far)
;;
;; Continuations looks like this:
;; {"start" '("b" "A")
;; "A" '("end" "b" "c" "start")
;; "b" '("A" "end" "d" "start")
;; "c" '("A")
;; "d" '("b")
;; "end" '("b" "A")}
(defn find-continuation [continuations path-so-far]
(let [possible-caves (continuations (last (:path path-so-far)))]
(remove (fn [cave] (and (= (str/lower-case cave) cave)
(not= (.indexOf (:path path-so-far) cave) -1))) possible-caves)))
;; Given a path-so-far, it gets all possible continuations and returns a
;; list of the path-so-far with continuations.
(defn next-path [continuations path-so-far]
(let [next-caves (find-continuation continuations path-so-far)]
(if (empty? next-caves)
[(assoc path-so-far :finished true)]
(mapv (fn [nc] (update path-so-far :path conj nc)) next-caves))))
;; Marks the :finished key in a path as true if the last item in the path is "end"
(defn mark-finished [paths]
(mapv (fn [{:keys [path] :as cur-path}]
(if (= (last path) "end")
(assoc cur-path :finished true)
cur-path)) paths))
;; Finds all the paths for the given map of continuations.
(defn find-paths [paths continuations]
(let [{:keys [path] :as first-unfinished} (first (filter (fn [{:keys [finished]}] (false? finished)) paths))]
(if (nil? first-unfinished)
paths
(recur (->> (remove (fn [p] (= path (:path p))) paths)
(concat (next-path continuations first-unfinished))
(mark-finished))
continuations))))
;; Needed because their is a bug where dead-ends end up as two vectors intead of maps.
(defn count-paths [paths]
(->> (mapv :path paths)
(remove (fn [path] (not= "end" (last path))))
(count)))
(time
(->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day12" parser)
(apply concat)
(merge-vector-of-maps)
(find-paths [{:path ["start"] :finished false}])
(count-paths)))
Part 2 is... running... Might have an answer some time Xmas day#2021-12-1221:36StuartIt's still running.🙃
But if I cancel it, I know it will have been seconds away from finishing.
Is this what people call the sunk cost fallacy ?#2021-12-1222:08StuartI just realised, it could be possible to do something like
"start->A->C->A->C->....->A->C" infinite loop.
Is this something that I need to code against?#2021-12-1222:09genmeblogit's rather not possible, there should be no such path I believe#2021-12-1222:12StuartON the one hand, that's good, my code isn't stuck in an infinite loop.
On the other hand, my code is really slow.
Approaching 2 hours.#2021-12-1222:39kevincI found that none of the examples, nor my input, had any big cave - big cave lines. that alone should prevent infinite loops if it's only big caves you let run unrestricted.#2021-12-1302:04Travis Jefferson13s hoo boy but it works! https://github.com/tjefferson08/advent-of-code/blob/main/2021/12/core.clj#2021-12-1302:27ACafter some cleanup and refactoring to speed things up --
(my pre-game warmup is to refactor the previous day’s solution)
(ns aoc21.day12
(:require [ :as io]))
;; part 1
(defn input-data [filename]
(reduce (fn [m [k v]]
;; add a->b; b->a edges
;; but skip _->start to make logic below simpler
(cond-> m
(not (= v "start")) (update k conj v)
(not (= k "start")) (update v conj k)))
{}
(->> (slurp (io/resource filename))
(re-seq #"\w+")
(partition 2))))
(def lower-case?
(memoize
(fn [s]
(Character/isLowerCase (first s)))))
(defn walk
([m]
(walk m #{"start"} '("start")))
([m seen [p & _ps :as path]]
(if (= p "end")
1
(let [poss (remove #(seen %) (get m p))]
(reduce #(+ %1 (walk m
(if (lower-case? %2) (conj seen %2) seen)
(conj path %2)))
0
poss)))))
(defn soln-1 [filename]
(walk (input-data filename)))
;; part 2
(defn walk-2
([m]
(walk-2 m false #{"start"} '("start")))
([m bonus seen [p & _ps :as path]]
(if (= p "end")
1
(let [poss (get m p)]
(if bonus
;; we've already doubled-up, so only unseen nodes
(reduce #(+ %1 (walk-2 m
bonus
(if (lower-case? %2) (conj seen %2) seen)
(conj path %2)))
0
(remove #(seen %) poss))
;; no restrictions, but bonus=true if it's a previously seen node
(reduce #(+ %1 (walk-2 m
(if (seen %2) true false)
(if (lower-case? %2) (conj seen %2) seen)
(conj path %2)))
0
poss))))))
(defn soln-2 [filename]
(walk-2 (input-data filename)))
#2021-12-1302:27Björn EbbinghausI have a solution that needs 50ms for Task 1 and 1,5s for Task 2. (After parsing)
https://github.com/MrEbbinghaus/advent-of-code/blob/master/2021/day12.clj#L54
I first built up a prefix tree and then counted the number of leaves. (tree-seq)
is nice for that. This took 3s for Task 2.
But just recursively counting and summing the number of paths and not building the paths themselves is at least twice as fast.#2021-12-1318:43StuartMy initial attempt at part 2 took at least 4 hours to run (maybe a lot longer, I cancelled it.)
After some thinking and sleeping on it, I've got something that is still slow (~9.5 seconds), but it works!
(ns stuartstein777.2021.day12b
(:require [stuartstein777.file :as f]
[stuartstein777.utils :as u]
[clojure.string :as str]
[clojure.set :as set]))
(defn parser [line]
(let [[start end] (str/split line #"-")]
[[start end] [end start]]))
(defn merge-vector-of-maps [xs]
(reduce (fn [acc [k v]] (update acc k conj v)) {} xs))
(defn find-continuation [continuations path-so-far allowed-twice]
(let [possible-caves (continuations (last path-so-far))]
(remove (fn [cave]
(cond (= cave allowed-twice)
(-> path-so-far
(frequencies)
(get allowed-twice 0)
(>= 2))
:else (and (= (str/lower-case cave) cave)
(not= (.indexOf path-so-far cave) -1)))) possible-caves)))
(defn next-paths [continuations [path finished? allowed-twice]]
(let [next-caves (find-continuation continuations path allowed-twice)]
(if (empty? next-caves)
[]
(mapv (fn [nc] [(conj path nc) finished? allowed-twice]) next-caves))))
(time
(let [continuations (-> (->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day12" parser)
(apply concat)
(merge-vector-of-maps))
(u/remove-it-from-all-vals "start"))
lower-case-caves (->> continuations
(keys)
(filter #(= (str/lower-case %) %))
(filter (fn [s] (and (not= "start" s)
(not= "end" s)))))
starts (mapv (fn [x] [["start"] false x]) lower-case-caves)]
(loop [possible-paths starts
finished []]
(if (empty? possible-paths)
(count (set (map first finished)))
(let [cur-path (nth possible-paths 0)
new-paths (set (next-paths continuations cur-path))
new-finished (set (filter (fn [[path _ _]] (= "end" (last path))) new-paths))
unfinished (set/difference new-paths new-finished)]
(if (empty? new-paths)
;; got no new paths for this path, so just drop it and recur (it's a dead end.)
(recur (rest possible-paths)
finished)
;; otherwise, drop it and add on all the new unfinished paths and add the finished paths to finished.
(recur (apply conj (rest possible-paths) unfinished)
(apply conj finished new-finished))))))))
My slowest solution so far this year#2021-12-1213:37StuartHavent' got a clue where to start today.#2021-12-1213:56JoeMy starting point was to google "graph algorithm all paths" and go from there 🙂#2021-12-1217:15StuartThis is annoying
'({:path ["start" "A" "c" "A" "b" "A" "end"], :finished true}
[:path ["start" "A" "c" "A" "b" "d"]] [:finished true] ;; <<< WTF
{:path ["start" "A" "c" "A" "b" "end"], :finished true}
{:path ["start" "A" "c" "A" "end"], :finished true}
{:path ["start" "A" "b" "A" "c" "A" "end"], :finished true}
{:path ["start" "A" "b" "A" "end"], :finished true}
[:path ["start" "A" "b" "d"]] [:finished true] ;; << WTF
{:path ["start" "A" "b" "end"], :finished true}
{:path ["start" "A" "end"], :finished true}
{:path ["start" "b" "A" "c" "A" "end"], :finished true}
{:path ["start" "b" "A" "end"], :finished true}
[:path ["start" "b" "d"]] [:finished true] ;; <<< WTF
{:path ["start" "b" "end"], :finished true})
At some point sometimes I'm going from a map to vectors, and I can't find why!#2021-12-1219:23Antonio Bibianodid you find the problem in the end?#2021-12-1219:24StuartYes, I expected my next-cave
function to return a vector of paths, but when there was no possible paths I was returning a map. SO I stuck that map in a vector and it works.#2021-12-1219:24StuartGot part 1 solved, but it takes 25 seconds to run!#2021-12-1218:37BenjaminIs the puzzle input 25 lines?#2021-12-1218:39Stuartmines is 24#2021-12-1218:39Stuartfor day 12 (if that is what you are asking)#2021-12-1218:40Benjaminyea#2021-12-1304:49Aleks🧵Day 13 answers thread: post your answers here#2021-12-1305:38normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day13/main.clj#2021-12-1306:09ACthis was a fun one..
(ns aoc21.day13
(:require [ :as io]
[clojure.string :as s]))
;; part 1
(defn parse-fold [s]
(let [[_ var line] (re-matches #"fold along (.)=(\d+)" s)]
[(keyword var) (Integer/parseInt line)]))
(defn make-grid [dots]
(reduce (fn [g xy] (assoc g xy \X)) {} dots))
(defn input-data [filename]
(let [[dots folds] (s/split (slurp (io/resource filename)) #"\n\n")]
[(make-grid (partition 2 (map #(Integer/parseInt %) (re-seq #"\d+" dots))))
(map parse-fold (s/split-lines folds))]))
(defn fold-y [grid offset]
(into {} (map (fn [[[y x] _]] (cond (= x offset) nil
(< x offset) [[y x] \X]
(> x offset) [[y (- offset (- x offset))] \X]))
grid)))
(defn fold-x [grid offset]
(into {} (map (fn [[[y x] _]] (cond (= y offset) nil
(< y offset) [[y x] \X]
(> y offset) [[(- offset (- y offset)) x] \X]))
grid)))
(defn fold [grid [axis offset]]
(if (= axis :x)
(fold-x grid offset)
(fold-y grid offset)))
(defn soln-1 [filename]
(let [[grid folds] (input-data filename)]
(count (fold grid (first folds)))))
;; part 2
(defn dump-grid [grid]
(let [[max-y max-x] (reduce (fn [[my mx] [[y x] _]]
[(max my y) (max mx x)])
[0 0]
grid)]
(doseq [x (range (inc max-x))]
(doseq [y (range (inc max-y))]
(print (get grid [y x] \.)))
(print "\n"))))
(defn soln-2 [filename]
(let [[grid folds] (input-data filename)
text (reduce (fn [g move] (fold g move)) grid folds)]
(dump-grid text)
(count text)))
#2021-12-1306:22Miķelis Vindavshttps://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/y2021/day13.clj#2021-12-1307:26Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_13.clj#2021-12-1308:58genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day13.clj#2021-12-1309:18nbardiukI've enjoyed folding
https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day13.clj#2021-12-1309:22Antonio BibianoI'm happy about my folding 🙂 not as much about my rendering :D#2021-12-1309:42genmeblog#2021-12-1309:55Aleks@U076FM90B I also enjoyed your solution, nice trick to avoid any if’s#2021-12-1310:11nbardiukthe fold-one trick is from @U1EP3BZ3Q https://clojurians.slack.com/archives/C0GLTDB2T/p1639387722093500#2021-12-1311:05drowsyparsing and drawing could be more concise but I'm fine with the folding in one line of specter https://github.com/IamDrowsy/aoc-2021/blob/main/src/aoc2021/d13.clj#2021-12-1313:32tschadyNothing new to offer really, I originally did a map, but copied @U44SHEP4N’s specter since I’m a fan.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d13.clj#2021-12-1314:15JoeBleh, not super happy with it. But it does work fine.
On reflection, I made life difficult for myself by making the calculation for the post-fold coordinates based on the size of the paper, which meant I had to keep track of the size of the paper (since you can't determine it from the coordinates alone, though I didn't realize that at first)
https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day13.clj#2021-12-1314:28JoeIn fact, I just refactored that out, now it's much nicer 🙂 thanks @U1EP3BZ3Q#2021-12-1314:56drowsy@U1Z392WMQ you don't actually need the turn the transform result into a set. As long as the initial input is already a set. specter will keep types.#2021-12-1315:22Sam AdamsI liked this one too; printing the letters was very satisfying. https://samadams.dev/2021/12/13/advent-of-code-day-13.html#2021-12-1318:26euccastrohttps://github.com/euccastro/advent-of-code-2021/blob/main/day13.clj#2021-12-1319:53karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day13.clj day13 solution judging from if you want to avoid if...
message identical to others 😄 Just printing the board for part2 and reading it manually felt like kind of cheating but I guess that is what most of the people did 😄#2021-12-1320:16tschadyin years past i considered doing an “OCR” on the text by comparing to a fingerprint, but he changes the letter size and font often so it’s not worth it.#2021-12-1320:52Antonio BibianoMaybe one can generate an image and send it off to an OCR api :D#2021-12-1322:22StuartPretty easy one today
(ns stuartstein777.2021.day13
(:require [stuartstein777.file :as f]
[stuartstein777.utils :as u]
[clojure.string :as str]
[clojure.set :as set]))
(defn parse-coord [line]
(->> (str/split line #",")
(map #(Integer/parseInt %))))
(defn parse-folds [line]
(let [[xy n] (u/frest (re-seq #"fold along (x|y)=(\d+)" line))]
[xy (Integer/parseInt n)]))
(defn folder [xy n [x y]]
(cond (and (= xy "x") (> x n))
[(- n (Math/abs (- n x))) y]
(and (= xy "y") (> y n))
[x (- n (Math/abs (- n y)))]
:else
[x y]))
(defn row->str [max-x row]
(let [xs (set (map first row))]
(map (fn [n] (if (xs n) "⭐" "⬛")) (range (inc max-x)))))
(defn print [coords]
(let [max-x (apply max (map first coords))]
(->> coords
(group-by #(second %))
(sort-by key)
(vals)
(map (partial row->str max-x))
(map (partial apply str))
(str/join "\n")
(println))))
(defn fold [coords [xy n]]
(map (partial folder xy n) coords))
(let [input (->> (slurp "puzzle-inputs/2021/day13")
(str/split-lines))
coords (->> input
(take-while #(not= "" %))
(map parse-coord))
folds (->> input
(drop (inc (count coords)))
(map parse-folds)
#_(take 1))] ; uncomment to solve part 1
(->> (reduce fold coords folds)
distinct
#_count ; uncomment to solve part 1
print))
#2021-12-1323:50StuartOh, i see from @U1EP3BZ3Q, I don't actually need the ((and (= xy "x") (> x n))
statements inside my cond in folder
! Nice#2021-12-1323:51StuartI just need the (= xy "x")
and (= xy "y")
#2021-12-1402:48Andrew ByalaGreat solution, @U89SBUQ4T. I enjoyed both how you parsed your data with partition
and especially with re-seq
, without splitting the lines. For the fold
function, your fold'
made the map
really clear. Thanks - I learned a lot from your tiny bit of code!#2021-12-1402:49kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/13a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/13b.clj. I was inspired by one of yesterday's posts to compose all the folds into one, though I didn't go as far as using a transducer.#2021-12-1404:59Miķelis VindavsThanks @U01HHBJ56J1, that’s nice to hear! I only picked the partition idea up myself a few days ago from another solution 🙂. Normally I also approach things top-down.#2021-12-1305:44petercTook me too long to render my result - spoiler in thread#2021-12-1305:45peterc#2021-12-1305:45petercThis is what I started with#2021-12-1306:23Miķelis VindavsThe console is rotated 90deg? 😄#2021-12-1306:37petercand mirrored 😄#2021-12-1306:49Aleksfold along day=13:christmas_tree:#2021-12-1316:37Aleks#2021-12-1309:28genmeblogif you want to avoid if
for folding (day13) you can use below formula (spoiler in thread)#2021-12-1309:29genmeblog(- a (m/abs (- v a)))
- v - value, a - axis (edited a little bit)#2021-12-1402:21tschadyInspired by @sam.h.adams I made my own blog page explaining my solutions, built into AsciiDoc from source. I tag interesting comments and code from the source and only pull those in. After I cleanup the generation script I’ll add a section explaining it
https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#2021-12-1404:55Aleks🧵Day 14 answers thread: post your answers here#2021-12-1405:56Fredrik#2021-12-1406:32normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day14/main.clj so ugly. I hope my eyes don't bleed when I try to read this in the morning#2021-12-1407:15karlishttps://github.com/skazhy/advent/blob/master/src/advent/2021/day14.clj#2021-12-1407:19Miķelis VindavsBtw,
(->> foo
((juxt #(apply max (vals %)) #(apply min (vals %)))))
can be replaced with
(->> (vals foo)
(apply (juxt max min))
#2021-12-1407:22Miķelis Vindavshttps://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/y2021/day14.clj#2021-12-1407:25Miķelis VindavsThat’s a super clean and short solution @U0CKR20TW#2021-12-1407:59Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_14.clj#2021-12-1409:41nbardiukI've spend too much time figuring out what to memoize
https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day14.clj#2021-12-1413:39tschady1ms / 4ms. Similar to others. Writeup: https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#aoc2021d14
code: https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d14.clj#2021-12-1414:34JoeMore fun with matrices, so my part 2 is fast for once:
Edit: Relatively fast 😓
https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day14.clj
https://github.com/RedPenguin101/aoc2021/blob/main/day14.md#2021-12-1416:07genmeblogand me: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day14.clj#2021-12-1417:59kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/14a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/14b.clj. Big computations over a narrow domain are ideal for memoization!#2021-12-1418:08Sam Adamson the verbose side: https://samadams.dev/2021/12/14/advent-of-code-day-14.html#2021-12-1418:09Sam AdamsLooking at @U0CKR20TW and @U067R559Q solutions — why don’t you need to bump the count for (first template)
in addition to (last template)
?#2021-12-1418:13kevincOh but in this case, I could have done one order better by using a multiply instead of memoization's many adds. I didn't use the fact that counting squashes a dimension to its fullest advantage#2021-12-1418:19Aleks@sam.h.adams a good question, bc we get only the first letter from the pairs. By doing it you miss only the last letter in the the last pair.
I’ll give you an example of it.
Original template: NNCB.
After split into pairs it looks like
NN 1
NC 1
CB 1
After replacing:
NC 1
CN 1
NB 1
BC 1
HB 1
Now if we want to count freqs, we need to take only first one from each pair plus the second one from the last pair because we miss it during reduce.#2021-12-1420:05Antonio BibianoI have a solution #2021-12-1420:05Antonio BibianoBut I don't understand why it works :D#2021-12-1420:05Antonio BibianoI just noticed that I was getting roughly double the answer #2021-12-1420:16Antonio BibianoAh I got it now!#2021-12-1420:19Antonio BibianoDouble counting all letters except the ones at the beginning or the end #2021-12-1420:29Sam Adams@U067R559Q I see now, thanks for the explanation 🙂#2021-12-1422:01euccastrohttps://github.com/euccastro/advent-of-code-2021/blob/main/day14.clj#2021-12-1422:13euccastrosame idea as many of yours, just with some uglier ends 🙂#2021-12-1422:15Antonio BibianoI went too far with threading :D#2021-12-1422:18Antonio Bibiano#2021-12-1422:23Antonio Bibianoin the end I made my life harder creating the new pairs beforehand#2021-12-1422:39karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day14.clj must admit - took me longer than it should have. the first part was a breeze but the second one not so much 😄 I should have remembered a lesson from day6 to calculate final solution as I go through iterations instead of trying to reduce it at the end. At the beginning though that there might be some formula to growth or maybe substrings repeat but nope, just wasted time 😄#2021-12-1422:53tschadyfor a lot of these, the hint is “OK, the final answer only wants counts, not the whole string, so what don’t we need to track?”#2021-12-1522:26StuartI had a LOT of issues with this one!
Thanks to the people on here who helped, love you guys!
(ns stuartstein777.2021.day14
(:require [clojure.string :as str]))
(defn parser [line]
{(subs line 0 2) [(str (subs line 0 1) (subs line 6))
(str (subs line 6) (subs line 1 2))]})
(defn solve [a b m]
(->
(reduce-kv (fn [acc [k1 k2] v]
(as-> acc o
(merge-with + o {k1 v})
(merge-with + o {k2 v}))) {} m)
(update a inc)
(update b inc)))
(defn react [reactions m]
(reduce (fn [acc [k v]]
(let [[r1 r2] (reactions k)]
(-> acc
(update r1 (fnil + 0) v)
(update r2 (fnil + 0) v)))) {} m))
(let [input (->> (slurp "puzzle-inputs/2021/day14")
(str/split-lines))
polymer-template (first input)
reactions (->> input
(drop 2)
(map parser)
(apply merge))
reactors (->> (partial react reactions)
(repeat 40)
(apply comp))
final-pairs (->> (partition 2 1 polymer-template)
(map (partial apply str))
(frequencies)
(reactors))
final-vals (->> final-pairs
(solve (first polymer-template) (last polymer-template))
(vals)
(map #(/ % 2)))
max-c (apply max final-vals)
min-c (apply min final-vals)]
(- max-c min-c))
I was getting caught out by the fact there are duplicate pairs in the real data, but not in test data!#2021-12-1413:44tschadyAdvent of iterate
, Advent of frequencies
#2021-12-1414:04Marc O'MorainWith a reduce
and group-by
new year.#2021-12-1417:52Sam Adams@tws nice! I like the succinct approach, it differentiates your writeups from the source itself. Cool use of var metadata too.#2021-12-1418:02tschadygot my first clojure monkeypatch in there too:
(in-ns 'marginalia.parser)
(defn strip-docstring [_ raw] raw)
(in-ns 'blogify)
#2021-12-1418:12Sam Adamsclojure is powerful!#2021-12-1510:15erwinrooijakkersnicely done!#2021-12-1504:52Aleks🧵Day 0xF answers thread: post your answers here#2021-12-1506:43normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day15/main.clj #2021-12-1506:50ACI have a lot of code clean-up and optimization to do.. 17s for part 2.#2021-12-1507:43Aleks> However, risk levels above `9` wrap back around to `1`.
@U0954HGDQ why do you wrap it back when n is equal to 9, not above?
(if (= n 9) 1 (inc n)))
#2021-12-1507:45petercI think its because the function is increasing n (`n` hasn't been increased yet)#2021-12-1507:47AleksOh, thank you, I see#2021-12-1508:05Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_15.clj#2021-12-1509:36AleksThe same result could be gotten with #(inc (mod % 9))
#2021-12-1509:37AleksI slept not much today, so my brain’s working badly 🤯#2021-12-1510:13erwinrooijakkersWat does (Character/digit n 10)
do?#2021-12-1510:17Miķelis Vindavsparses a char into an integer#2021-12-1510:18Miķelis Vindavsuser=> (Character/digit \9 10)
9
user=> (type \9)
java.lang.Character
user=> (type (Character/digit \9 10))
java.lang.Integer
#2021-12-1512:58tschady280ms / 9s, used ubergraph
doc: https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#aoc-2021-d15
code: https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d15.clj
I did Djikstra once, ain’t nobody got time to type that out all day.
I also assume input is a square, easy enough to change for rects.#2021-12-1513:20cyppanDjikstra indeed! I’ve used https://github.com/clojure/data.priority-map which is a pretty nice way of using a priority queue in Clojure (~ 100ms / 2500ms)#2021-12-1513:29genmeblogDijkstra here (with slow second part, 13s)! https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day15.clj#2021-12-1513:52nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day15.clj#2021-12-1517:37euccastroI no longer have the time to try and factor nicely across parts, so ugly redefs will have to do: https://github.com/euccastro/advent-of-code-2021/blob/main/day15.clj#2021-12-1517:39euccastrouses A*#2021-12-1517:44euccastro... but it actually implements it in the code, instead of using it from a library (nothing wrong with that, I just felt like using the opportunity to have a refresher)#2021-12-1517:46euccastroand this also allowed me not to compute the paths, just the cost of the result#2021-12-1517:47euccastroso it runs in <4s#2021-12-1517:51Callum Oakleyhad a dijkstra function ready to go from previous years. 72ms/1.7s
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/15.clj
there goes my sub 1s total runtume (for the year) 😞 was fun while it lasted. 2.5s total now, 740ms before today#2021-12-1520:56Antonio BibianoWow my dijkstra takes 98 seconds on the second grid :(#2021-12-1521:02sarcilav@U01HY37QQUA? how? maybe wrong data structure implementation?#2021-12-1521:04AC@U01HY37QQUA are you keeping track of all the paths you’re trying? I did that to help with debugging, but then ripped it out. Mine sped up from 17s to 4s.#2021-12-1521:10Antonio BibianoMhh maybe my implementation is very inefficient, it takes about 1 second on part 1#2021-12-1521:10Antonio BibianoI'll try to clean it up and post it in a bit #2021-12-1521:12thumbnailI used A* (which isn't the best pick for topleft to bottom right, but okay), but it runs in ~1.2S for part1 and doesn't finish for part 2 :')
102ms for part 1 and <4s for part 2. That wraps it up 😬#2021-12-1521:30Callum Oakley@U01HY37QQUA if I had to guess… are you considering positions more than once? If you return to a position you’ve already seen, then you’re necessarily returning to it via a longer path than the first time, so you can ignore it.#2021-12-1521:43thumbnailI sped up my algorithm by a factor of 10 by just using a proper priority map 😅#2021-12-1521:43Antonio Bibianothis is my implementation#2021-12-1521:43Antonio Bibiano#2021-12-1521:44Antonio Bibianomy first guess would be that sorting becomes expensive as tds
becomes bigger and bigger#2021-12-1522:40Antonio Bibianoi changed (first (sort-by val tds))
to (apply min-key val tds)
and got down to 15 s#2021-12-1522:51sarcilavah yeah, that helps, sort is O(n log n) and min is O(n)#2021-12-1523:07Sam AdamsI spent way too long trying to invent an algorithm for this… thanks to @U0124C56J5R for pointing me to Dijkstra’s. Toxic code: https://samadams.dev/2021/12/15/advent-of-code-day-15.html#2021-12-1600:02kevincBrute force, and probably not doing lazy sequences right because I can't fit part 2 in a heapsize under 50MB… 0.2s and 1.0s though! https://github.com/kconner/advent-of-code/blob/master/2021/15a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/15b.clj#2021-12-1601:17kevincNo, I have to take that back. I spaced on checking my second answer after I got the correct answer for the sample input. There are paths I don't consider at all.#2021-12-1604:42kevincGot it: https://github.com/kconner/advent-of-code/blob/master/2021/15a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/15b.clj. 115ms and 2.1s by a weighted flood fill.#2021-12-1703:28lreadBlech! Finally finished day 15 using dijkstra alg. My code is a mess, but I’m not gonna clean this one up anytime soon! Clever fellow that dijkstra!#2022-01-0502:21kingcodeI implemented Dijkstra first the naive way (no priority queue, 41+ secs on real input for part 1, no part2 result); then used clojure.data.priority-map
(370 msecs for part1), then used a Fibonacci Heap (252 msecs for part1, 10+ secs for part2). I kept track of all the paths throughout.#2022-01-0519:59lreadI kept track of paths too so that I could easily print out a visualization.#2022-01-0703:09kingcodeAs an aside, I couldn’t find a Clojure implementation of a Fibonacci Heap, so I fetched a (mutable) Java impl. and hacked a wrapper around it. Does anyone know of a Clojure and/or persistent FibHeap impl?#2021-12-1517:29StuartCan someone who has solved Day 14 help me debug an issue, issue in thread#2021-12-1517:29StuartUsing the test data
"NNCB"
After 10 cycles of reactions, I get
{"CH" 21, "HH" 32, "BH" 81, "BN" 735, "NH" 27, "NB" 796, "HB" 26, "BC" 120, "CN" 102, "CC" 60, "BB" 812, "CB" 115, "HN" 27, "HC" 76, "NC" 42}
Can someone who has solved it tell me what the pair counts are after 10 iterations?#2021-12-1517:30StuartWhen I try to solve, I'm counting the number of character and halving it. BUt I'm off by one on some#2021-12-1517:30R.A. PorterThe last character in the template string.#2021-12-1517:32Stuartoh yeah, its the first and last char that is off by one#2021-12-1517:34Stuartthanks, that helps#2021-12-1517:35R.A. Porter👍#2021-12-1519:26genmeblogYou have to add first and last characters too before dividing by 2.#2021-12-1517:38Sam AdamsSPOILER ALERT — day 15 hint request 🪡🙏#2021-12-1517:39Sam AdamsMaybe just a sanity check: contrary to the examples, the min-risk path CAN include leftward and upward movements, right?#2021-12-1517:40euccastrotheoretically yes, I haven't checked whether they happen in my real input#2021-12-1517:40ACyes. people were posting example grids in the reddit thread that break the assumption that it’s only down and to the right. for example:
<tel:1911191111|1911191111>
<tel:1119111991|1119111991>
<tel:9999999111|9999999111>
<tel:9999911199|9999911199>
<tel:9999119999|9999119999>
<tel:9999199999|9999199999>
<tel:9111199999|9111199999>
<tel:9199999111|9199999111>
<tel:9111911191|9111911191>
<tel:9991119991|9991119991>#2021-12-1517:54Sam AdamsGahh, okay, thanks!#2021-12-1518:45Sam AdamsI’m stumped… were people able to write recursive memoized solutions? Or is a stateful cache necessary…?#2021-12-1519:15ACmy main logic is a loop and a priority-map.
have you gotten any hints/spoilers about what algorithm others are using? (I don’t want to give too many hints unless you want them)#2021-12-1519:19Sam AdamsHave had no hints yet, but I’d appreciate any that come to mind 🙂 (at this point just hoping to avoid punting or reading the solution thread)#2021-12-1519:20Sam Adams“priority-map” confuses me so I suspect my basically brute-force approach (to which I’m trying to add memoization and pruning) is very wrong…#2021-12-1519:24ACmost people are using Dijkstra’s algorithm (or A* though it didn’t help speed mine up at all)#2021-12-1519:30Sam AdamsThat’s a very helpful hint and just what I was after, thanks!#2021-12-1519:34genmeblogmy two hints for dijkstra: you don't need to track a path and you should stop after reaching the end#2021-12-2303:57samedhiWow, finally https://github.com/samedhi/advent-of-code-2021/blob/main/30.clj. Took me a long time to reason that I could use a sorted map as a heapq like thing.#2021-12-2304:00samedhiI would love to see other peoples solution to this day.#2021-12-1519:09StuartDay 14 is annoying me majorly.
It works for the test data, gets the correct answer of 1588 after 10 cycles
Wrong answer for real data.
I re-write with a different approach.
It works for the test data, gets the correct answer of 1588 after 10 cycles.
Exactly the same wrong answer for the real data!
Argh!#2021-12-1519:31genmebloghow do you count character count?#2021-12-1519:32genmeblogmy string has the same character at the beginning and the end and it broke my first attempt#2021-12-1519:33StuartI end up with two chars that have an odd number of counts.
One char is the same as the first char in the string, so I add 1 to that.
Same with the last char in the string.
THen I find the max and min, do max-min, and half that result.#2021-12-1519:35genmeblogwhat is the result after, say 20 cycles?#2021-12-1519:35StuartMy algo is,
I only keep track of the number of each pairs, then on each react cycle I swap out the key with that pair (repeated n times, where n is the original keys value).#2021-12-1519:36genmeblogI remove everything before next cycle. I mean I build counts from the scratch every time.#2021-12-1519:38StuartYeah, that's waht I'm doing too. My react method
(defn react [reactions v]
(reduce (fn [acc [k v]]
(let [freq (frequencies (flatten (repeat v (reactions k))))]
(merge-with + acc freq)))
{}
v))
where reactions is a map of reactions
{"CH" ["CB" "BH"], "HH" ["HN" "NH"], "BH" ["BH" "HH"] ...}
And v is a map of the current pair counts
{"NN" 1
"NC" 1
"CB" 1}
#2021-12-1519:39genmeblogto verify: after 20 cycles my result is: 2264701 and for example [\N \O] is 77113
#2021-12-1519:39Stuartis that for the test data ?#2021-12-1519:39genmeblogyes#2021-12-1519:40Stuartoooh, for the test data I get 1961318 after 20 cycles.#2021-12-1519:40Stuartso there is something that happens after 10 cycles, that doesnt happen in the first 10 cycles for me!#2021-12-1519:40genmeblogyep, sometimes some bug appears later than sooner (was there 🙂 )#2021-12-1519:41Stuartthanks#2021-12-1519:44genmeblogcheck also "NO" count#2021-12-1519:45genmeblogif it's the same it could mean that your final counting is wrong not pair counting#2021-12-1519:47StuartIt's my react function, I guess as I don't end up with any "NO"
key at all after 20#2021-12-1519:47genmeblogit looks valid at the first glance...#2021-12-1519:50genmeblogshit... sorry#2021-12-1519:50StuartAfter 20 my map looks like
{"CH" 10614, "HH" 10002, "BH" 20606, "BN" 965778, "NH" 6775, "NB" 983801, "HB" 13841, "BC" 36044, "CN" 31220, "CC" 18022, "BB" 986886, "CB" 24787, "HN" 6775, "HC" 17379, "NC" 13198}
#2021-12-1519:51genmeblogsorry, I have the same result as you... I used the same var for my data and test data and acciedentally shadow one by another#2021-12-1519:51genmeblogThe result on test data is 1961318#2021-12-1519:52genmeblog{[\C \H] 10614, [\H \C] 17379, [\N \C] 13198, [\N \H] 6775, [\C \N] 31220, [\N \B] 983801, [\B \C] 36044, [\B \B] 986886, [\B \H] 20606, [\C \C] 18022, [\H \N] 6775, [\C \B] 24787, [\H \B] 13841, [\B \N] 965778, [\H \H] 10002}
#2021-12-1519:52genmeblogsorry for confusion, my fault#2021-12-1519:54Stuartso my problem is, something happens in real data that doesnt happen in test data!#2021-12-1519:55genmeblogyou can try on my test data: https://github.com/genmeblog/advent-of-code/blob/master/resources/advent_of_code_2021/day14.txt#2021-12-1519:56genmeblogfor 10 I got 2194#2021-12-1519:56genmeblogfor 40: 2360298895777#2021-12-1519:57Stuartoh, thats helpful, i deffo have a problem as after 10 I'm getting 4151/2
#2021-12-1520:00StuartIs this a valid way of doing 10 cycles
(->> (partial react reactions)
(repeat 10)
(apply comp))
Then just call that with my starting map ?#2021-12-1520:01genmeblogit's better to use iterate#2021-12-1520:02genmeblog(nth (iterate (partial react reactions)) 10)
#2021-12-1520:03genmebloghowever comp
of 10 the same functions should be ok as well#2021-12-1520:48tschadythere is a key difference between real and test data, want a hint?#2021-12-1520:48Stuartyes please#2021-12-1520:49tschadyteh example data only has at most 1 of each pair. real data has multiple.#2021-12-1520:49Stuartis it that you can get duplicate results from the pairs#2021-12-1520:49Stuart😄#2021-12-1520:49Stuartthanks for confirming that#2021-12-1520:50tschadythat one bit a friend#2021-12-1522:14Stuartgot it! Thanks for the help guys 😄#2021-12-1522:29sebastianGeneral question: has anyone tried used Clerk to do some visualizations on their AoC problems? I would like to see some use-cases.#2021-12-1523:27lreadSomeone said it starts to get harder on day 15. Well, I think I see watcha meant there!#2021-12-1523:56Stuarti'm trying to wrangle my existing clojure maze solver into a solution for this, but i dont think i can use it#2021-12-1600:04lreadThis is the first one I will not be able to finish by the end of the day. Perhaps a sign just to take the rest of the challenges at a non-daily pace for me.#2021-12-1604:59Aleks🧵Day 16 answers thread: post your answers here#2021-12-1606:41normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day16/main.clj good enough for aoc.. ship it#2021-12-1607:36ACpart 1 did a good job of hinting what part 2 would want, so I spent most of my time on it and then part 2 took just a few minutes.
I wonder if we are going to see future days expand on this..#2021-12-1609:02nbardiukToday was the most tedious task so far https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day16.clj#2021-12-1609:44Aleks@U076FM90B totally agree, and I spent lots of time to find an annoying bug in my code#2021-12-1611:11genmeblogugh... the same here... one bug ~2h to find if-not
instead of if
😕#2021-12-1611:35jacoelhohttps://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day16.clj#2021-12-1611:43genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day16.clj#2021-12-1614:14normanStrange. I thought it was a fun problem. A parser and an expression evaluator. 95% of my time was on the parser, and that was mostly in trying to find a way to do this with clojure. Immutable parsers are hard. I did a pretty poor job with my attempt, but it was a fun thought process trying to figure out how to do it with those constraints. There was definitely more "reading and understanding" on this problem than others, but at no point was I finding it tedious.#2021-12-1614:15Antonio BibianoI have to say, mutual recursion is thrilling :D#2021-12-1614:28Björn EbbinghausMy solution for part 2 involves generating Clojure Code from this BITS code.
(macroexpand-1 '(BITS "C200B40A82"))
=> (clojure.core/reduce clojure.core/+ [1 2])
#2021-12-1614:28Antonio Bibianowell that's pretty cool#2021-12-1614:35tschadyi hated this problem, such tedious reading#2021-12-1614:40Antonio BibianoYeah took me a long time to wrap my head around it, after that I was afraid I would have to use trampoline
to get the mutual recursion working, luckily it was fine#2021-12-1615:54AleksDidn’t refactor it, I probably won’t
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_16.clj#2021-12-1615:55Alekssecond part just builds a big clojure expression, and evals it#2021-12-1616:47euccastronothing fancy here; I build some kind of AST which is not a clojure expression, then walk it in a different way for each part: https://github.com/euccastro/advent-of-code-2021/blob/main/day16.clj#2021-12-1618:21Antonio Bibianovery clean!#2021-12-1618:34ACI’m not happy with all the “take” and “drop” operations that I have to keep in sync, but I do like using lazy-cat to create a stream of binary digits from the input. Since there’s no need for backtracking, a destructive read from the bit-stream would be cleaner.
I originally did a bunch of bit manipulations to create the bit-stream but then replaced it with a lookup table.
(ns aoc21.day16
(:require [ :as io]))
;; part 1
(defn input-data [filename]
(slurp (io/resource filename)))
(def hex->bin
{\0 [0 0 0 0]
\1 [0 0 0 1]
\2 [0 0 1 0]
\3 [0 0 1 1]
\4 [0 1 0 0]
\5 [0 1 0 1]
\6 [0 1 1 0]
\7 [0 1 1 1]
\8 [1 0 0 0]
\9 [1 0 0 1]
\A [1 0 1 0]
\B [1 0 1 1]
\C [1 1 0 0]
\D [1 1 0 1]
\E [1 1 1 0]
\F [1 1 1 1]})
(defn bit-stream [[hexchar & hexstr]]
(if (nil? hexchar)
nil
(lazy-cat (hex->bin hexchar) (bit-stream hexstr))))
(defn bin->dec [bits]
(reduce #(bit-or (bit-shift-left %1 1) %2) bits))
(defn packet-version [bits]
(bin->dec (take 3 bits)))
(defn packet-type [bits]
(case (bin->dec (take 3 bits))
4 :literal
:operator))
(defn decode-literal [version bits]
(loop [[bit & bits] bits
acc []]
(case bit
1 (recur (drop 4 bits) (concat acc (take 4 bits)))
0 [{:version version
:type :literal
:value (bin->dec (concat acc (take 4 bits)))}
(drop 4 bits)])))
(declare decode-packet)
(defn decode-operator [version bits]
(let [optype (bin->dec (take 3 bits))
ltype (take 1 (drop 3 bits))
bits (drop 4 bits)]
(case (bin->dec ltype)
0 (let [len (bin->dec (take 15 bits))]
(loop [spbits (take len (drop 15 bits))
acc []]
(if (seq spbits)
(let [[packet spbits] (decode-packet spbits)]
(recur spbits (conj acc packet)))
[{:version version
:type :operator
:op optype
:children acc}
(drop (+ len 15) bits)])))
1 (let [cnt (bin->dec (take 11 bits))]
(loop [i cnt
bits (drop 11 bits)
acc []]
(if (> i 0)
(let [[packet bits] (decode-packet bits)]
(recur (dec i) bits (conj acc packet)))
[{:version version
:type :operator
:op optype
:children acc}
bits]))))))
(defn decode-packet [bits]
(let [version (packet-version bits)]
(case (packet-type (drop 3 bits))
:literal (decode-literal version (drop 6 bits))
:operator (decode-operator version (drop 3 bits)))))
(defn sum-version [{version :version type :type children :children}]
(case type
:literal version
(+ version (reduce #(+ %1 (sum-version %2)) 0 children))))
(defn soln-1 [filename]
(sum-version (first (decode-packet (bit-stream (input-data filename))))))
;; part 2
(def optable
{0 +
1 *
2 min
3 max
5 #(if (> %1 %2) 1 0)
6 #(if (< %1 %2) 1 0)
7 #(if (= %1 %2) 1 0)})
(defn solve-tree [{type :type value :value op :op children :children}]
(if (= type :literal)
value
(apply (optable op) (map solve-tree children))))
(defn soln-2 [filename]
(solve-tree (first (decode-packet (bit-stream (input-data filename))))))
#2021-12-1619:26tschadyi don’t like my code. There’s only 2 things I liked, cl-format
and medley.core/take-upto
:
(defn hex->bits [hex]
(cl-format nil "~{~4,'0B~}" (map #(Character/digit % 16) hex)))
(defn slice-literal [stream]
(let [val-part (->> stream
(partition 5)
(take-upto #(= \0 (first %))))
stream (drop (count (flatten val-part)) stream)
value (->> val-part
(map (partial drop 1))
flatten
(s->int 2))]
[value stream]))
#2021-12-1619:29Sam AdamsI find these problems somehow both tedious and satisfying… too much reading for midnight, though. https://samadams.dev/2021/12/16/advent-of-code-day-16.html#2021-12-1619:38ACyeah.. when I saw the wall of text, I debated waiting until the morning. I did waste a fair amount of time because I read “bits at the end are extra due to the hexadecimal representation and should be ignored” as meaning that we had to handle the padding ourselves on every packet. I was throwing out bits that didn’t cause problems until later examples with sub-packets.#2021-12-1619:42tschadyif you liked this problem then we are enemies#2021-12-1619:48Antonio BibianoI dreaded it until I got the main pieces down, then actually running and see the codes get parsed gave me a rush 😄#2021-12-1619:49tschadylike being released from prison#2021-12-1619:50Antonio Bibianoahahhaha right 😄#2021-12-1703:35kevincThis was like a vacation compared to yesterday. I really liked the exercise. https://github.com/kconner/advent-of-code/blob/master/2021/16a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/16b.clj. Now I'm trying to find ways to shorten it; I think the state monad is relevant.#2021-12-1800:16karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day16.clj as most of the people also enjoyed this over the day15, part 2 went rather quickly as I was converting stuff to proper representation as I went through the packets
And when parsing I went probably with easiest solution: always return: [left-to-parse parsed-element]
data structure#2021-12-1616:09genmeblog@sebastian I've started to use it for the other project (for a documentation). What cases you want to see?#2021-12-1618:36sebastianfor example how to visualize some AOC solutions like 2d grids or things like that. what would be a good format to be easily visualized. Things like that.#2021-12-1618:51genmeblogas far as I know, vega light and plotly are supported, that means that you should generate spec for that#2021-12-1618:53genmeblogalso I know that currently support for images (generated or external) are not easily supported as it's in nextjournal. But it's comming.#2021-12-1618:53genmeblogGenerated by quil or clojure2d for example#2021-12-1618:53genmeblogIt can be done via direct html embedding#2021-12-1700:12R.A. PorterIf you don't need more from the grid other than on/off, there's also the brute-force way they use in their own Rule-30 example. I updated my day 13 solution (messily) to use that. The code's so-so, but it does lead to old-school calculator looking output.#2021-12-1714:51genmeblogYou can embed image as described here: https://github.com/nextjournal/clerk/issues/37#2021-12-1622:46ivangalbans🧵 Day 16 - ❓#2021-12-1622:46ivangalbanswhen the length type id is 0, how do you know the number of bits in each packet?
for example here, why not 12 + 15 = 27 ?#2021-12-1622:47ivangalbansthey are always chosen from 11 to 11 and they end up with one that is a power of 2 ?#2021-12-1622:49genmeblogYou don't know the number of bits in each packet and you don't know the number of packets (which is the case for ID 1). You know total number of bits, you know that this number is valid and should contain complete subpacket (which can contain much more subpackets etc).#2021-12-1623:05lreadI found day 16 much easier than day 15. Still not finished day 15!#2021-12-1703:25lreadUgh! Finally finished day 15!#2021-12-1704:56Aleks🧵Day 17 Solutions Thread: post your solution here#2021-12-1705:33Miķelis VindavsClassic AoC where part1 makes you feel like you should find a formula to solve it in constant time, but then part2 says “nope, it’s brute force after all simple_smile”#2021-12-1706:11normanhttps://gitlab.com/maximoburrito/advent2021/-/commit/324a922979d1de288c777789320c56412916f43a#2021-12-1706:14Miķelis Vindavsthe y search space can be reduced to (range (dec y1) (- y1))
#2021-12-1706:14normanI hard coded one my bounds experimentally. I am sure I could figure out a more correct solution, but on AoC when you get the answer, it's time to sleep. #2021-12-1706:15normanThanks. I assumed something like that would be correct, but I wasn't sure.#2021-12-1706:22Charles Comstockhttps://github.com/dgtized/advent-of-code/blob/master/2021/day17/trick_shot.clj#2021-12-1706:31AC@U89SBUQ4T that certainly speeds up my brute-force.#2021-12-1706:37AleksIt is slow, but works 🙃
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_17.clj#2021-12-1709:03nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day17.clj#2021-12-1710:40Miķelis Vindavsvery nice parsing 👍:skin-tone-2:#2021-12-1714:26nbardiukthanks, although today we can avoid parsing, just store numbers in a map#2021-12-1714:36thumbnailI like your part1 😅#2021-12-1715:35euccastroClosed form for part1, brute force for part 2 (but part1 gave me confidence about the bounds in the y direction): https://github.com/euccastro/advent-of-code-2021/blob/main/day17.clj#2021-12-1715:49euccastrothe insight for part 1 (and for narrowing down the y space) is that after reaching as high as it can, the bullet will fall down to exactly zero height, and the next step must be within the target. if we want to reach as high as we can, the next step after reaching zero height will be at the bottom of the target. (this is assuming that the target is below 0, which is kind of implied in the problem description but I didn't assume in my code; I think I could have assumed that x is always positive too)#2021-12-1715:56euccastroI've cleaned up my code with the assumption (again, kind of implied in the description) that the target is in the bottom right quadrant. it's shorter and prettier now#2021-12-1717:46Sam AdamsBrute force: https://samadams.dev/2021/12/17/advent-of-code-day-17.html#2021-12-1720:21Antonio BibianoWas happy to find a solution for part1 but then got super lazy about finishing part 2 :(#2021-12-1721:12genmeblogafter some refactoring I ended up with one function which covers both cases and is short (`reductions` is huge helper here). But it was long process... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day17.clj#2021-12-1721:23genmeblog@U65FN6WL9 seems to work, however there are gaps in initial x velocities when target is missed. For example for x between 195 and 238 (my case) velocities between 81 and 97 miss the target.#2021-12-1721:39tschadyI got a closed form solution (so no boundary checking necessary). 0.1ms, 7ms.
writeup: https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#aoc-2021-d17#2021-12-1721:58karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day17.clj prior to any refactoring. I had a formula to find possible x-velocities but then for y velocities used the dumbest thing that works i.e minimum velocity is the lowest y of target and upper bound is 1000
which is less than ideal. Will try to optimize it later but I must admit solving AoC while having a flu is much harder than without one 😄#2021-12-1804:42kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/17a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/17b.clj. I got way, way too clever on my first try. I'd rather have to improve a slow naive solution than debug a fast, complex, wrong solution.#2021-12-1821:23euccastro@U1EP3BZ3Q what "seems to work" but doesn't? I didn't do anything clever about x velocities; I just try all the ones that could possibly work#2021-12-1821:24euccastroand even some that couldn't, but no big harm in that since my brute force code runs almost instantly#2021-12-1804:55Aleks🧵Day 18 Solutions Thread: post your solution here#2021-12-1806:34erdossolved with zippers 🙂
https://gist.github.com/erdos/797f5a63016b919e43d619fb3a957b49#2021-12-1807:39normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day18/main.clj I also went with zippers, despite the fact that in my 8 or 9 years with Clojure I've never had cause to use them before. I almost gave up to switch to a mutable tree structure, but at the last second I found the problem I was having. #2021-12-1809:50nbardiukflattened tree into vector of pairs of value and path
https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day18.clj#2021-12-1809:53nbardiukzippers look cool :the_horns:#2021-12-1811:37Alekstook this opportunity to understand zippers deeper
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_18.clj#2021-12-1818:14jacoelhoThank you for suggestion on zippers
https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day18.clj
Part 2 takes like 8seconds, is that expected or is an implementation issue?#2021-12-1818:18kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/18a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/18b.clj. 1.2s and 3.3s. I did think this might be the kind of thing a zipper is good for, but i didn't research and use them this time. maybe I'll be inspired next time by having done it the hard way already 🙂#2021-12-1818:43kevincif you treat the index path to the node to be exploded as a four-bit binary number, you can find the leaf to either side by incrementing or decrementing that path number. if you overflow, you're out of the structure. then extend with a fifth bit for depth, and find the leaf on that path.#2021-12-1821:33Callum Oakleyno zippers here, but it looks like it would be a good problem to revisit to give them a try…
only interesting bit is explode
, which walks the tree depth first and returns a triple of “left carry”, “exploded number”, “right carry”. which get carried back up the call stack and applied as appropriate.
21ms/160ms
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/18.clj#2021-12-1823:56euccastroI had the feeling that something like zippers/lenses or other similar things I never learned about would be applicable, but I didn't have the time to look into them now. maybe my solution is somehow equivalent? anyway, it ended up shorter than the zipper-based ones, without any require
s
https://github.com/euccastro/advent-of-code-2021/blob/main/day18.clj
when I read @U076FM90B's description I thought "yes, that's exactly what I did too!", but somehow the actual code seems quite different. my main trick was "make a sequence of the paths to the leaves, then partition that to get the previous and next path for explodes"#2021-12-1903:24Andrew ByalaMine was nothing fancy; I just used a whole lot of get-in
and similar basic vector functions. Still, it all worked out fairly simply.
• https://github.com/abyala/advent-2021-clojure/blob/main/src/advent_2021_clojure/day18.clj
• https://github.com/abyala/advent-2021-clojure/blob/main/docs/day18.md#2021-12-1908:03Antonio Bibiano#2021-12-1908:03Antonio BibianoI went with a flattened list where each number is a pair with value and nesting level#2021-12-1908:04Antonio Bibianoand then used two queues and a buffer to scan the list#2021-12-1908:05Antonio Bibianotook me a lot longer than I anticipated after coming up with the idea 😞#2021-12-1913:33karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day18.clj - this took way longer that I have should probably due to me being sick and not sleeping well 😄 Went with zippers and stick with them but would lie if said I know them well beforehand so had to do a lot of learning while solving it. It is nice that I have purely functional solution that mutates a tree but TBH if I would need to do such task more often I would just use some mutable data structure and be done with it 😄#2022-01-1305:45kingcodeI used zippers, fun stuff. Although slow around 18 seconds for part 2 initially, but brought it under 7 secs using pmap
#2021-12-1813:55AleksIt’s almost dead silent today#2021-12-1814:33karolI am waiting for my kid to go asleep 😄 But took a quick glance at the task in the morning and my gut feeling would to use one inbuilt clojure "library" and the parsing of input looks to be most straightforward of all days (at least in clojure)#2021-12-1904:48Aleks🧵Day 19 Solutions Thread: post your solution here#2021-12-1909:19Miķelis VindavsTurns out finding 6 overlaps is enough. I forgot to change the limit from running the sample input, but still got the right answer#2021-12-1911:44nbardiukruns over a minute but I don't have any more time to optimize https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day19.clj#2021-12-1912:21Aleksfinally solved it 🙃#2021-12-1913:06Antonio Bibianoso strange I can find the overlap on half the example#2021-12-1913:07Antonio Bibianobut not on the other half#2021-12-1914:01nbardiukI had similar symptoms, the problem was in the rotations#2021-12-1914:09Antonio Bibianoyeah I figured is something like that... still haven't found a fix#2021-12-1915:04Callum Oakleyurgh. takes over 10 minutes… 😬 https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/19.clj#2021-12-1916:30Miķelis VindavsFor some reason my solution only runs if I include all 48 transformations (24 + mirroring which according to the text shouldn't be allowed).. were you all able to solve it with 24 rotations?#2021-12-1917:31Antonio BibianoI am also running with 48 transformations, but just because i was too invested in getting the thing to run to fiddle more with coordinate transformations 😄#2021-12-1917:43euccastroMine takes >13 minutes. I'll only try optimizations if I can think of any interesting/fun ones: https://github.com/euccastro/advent-of-code-2021/blob/main/day19.clj#2021-12-1917:44euccastrovery brute force#2021-12-1917:50euccastrobut works with 24 transformations @U89SBUQ4T (I generated a superset of those and filtered by determinant being 1)#2021-12-1920:35Antonio BibianoThis is what I came up with.. some seriously cursed code find-path
and get-one-path
to figure out which chain of coordinate changes to apply to a point once i have the overlaps..#2021-12-1920:52AleksA bit cleaned up my solution
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_19.clj
~7 secs#2021-12-1920:53Aleks@U89SBUQ4T I ended up with 24 orientations#2021-12-1920:55Aleksan example for x axis, y and z follow the same pattern
;; orientations for x axis
;; [+x +y +z]
;; [+x -z +y]
;; [+x -y -z]
;; [+x +z -y]
;; [-x +y -z]
;; [-x +z +y]
;; [-x -y +z]
;; [-x -z -y]
#2021-12-1920:56AleksI was rotating Rubik’s cube to understand it 🤯#2021-12-1921:48Antonio BibianoThese last days I was really just kicking the code into some shape that works and barely any time left to re-think my approach :(#2021-12-1922:44normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day19/main.clj when you keep adding garbage code onto other garbage code until you make it print the number you want. ughhh... I had this mostly done last night, but I was struggling not realizing that what I really needed to do was merge all the points. I'm sure there's actual sane ways to have coded this, but it's really hard to care at this point. #2021-12-1923:32Callum Oakleycherry picking other people’s optimisations… @U067R559Q’s overlap
function and the idea of “fingerprinting” to prune the search space a bit (https://www.reddit.com/r/adventofcode/comments/rjpf7f/comment/hp551kv/?utm_source=share&utm_medium=web2x&context=3https://www.reddit.com/r/adventofcode/comments/rjpf7f/comment/hp551kv/?utm_source=share&utm_medium=web2x&context=3)) …down to sub 300ms 😌
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/19.clj#2021-12-2002:58kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/19a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/19b.clj. Not happy with my running time (6 minutes), and I don't know Clojure concurrency well enough to race several searches for the first successful match.#2021-12-2002:59kevincI did come up with one useful insight: for any vector [a b c], its valid 90 degree rotations are all those with 1. the same cyclic ordering (b c a, c a b…), with an even number of negations (-a -b c, but not -a b c), or 2. the opposite cyclic ordering (c b a, etc.) with an odd number of negations (-c -b -a, -c b a, but not -c -b a).#2021-12-2003:05kevincgreat thinking re: overlap
. I should have known there was excess work being done on my equivalent to that#2022-02-0122:37kingcodewhew…just completed mine. Had to do a lot of gymnastics for this one, including caching, r/fold and trying generally not to do more work than needed - with all my efforts, solution ends up being over 4 mins 😞#2022-02-0221:12kingcodeWow, just switched to the direct point comparison alg. Now, together with caching and || threads, under 4 seconds!#2021-12-1905:08normanWondering if should just some early sleep tonight :)#2021-12-1919:53Filip Strajnaralright so I've already shortened day 1 part 1 code to this long, but I'm trying to find out if there is an even shorter way of writing this
(defn
by-indicies
[lines]
(count (filter #(< (Integer/parseInt (nth lines %)) (Integer/parseInt (nth lines (inc %)))) (range (dec (count lines))))))
#2021-12-1919:56R.A. PorterYou might want to check the pinned thread for day 1 - https://clojurians.slack.com/archives/C0GLTDB2T/p1638336618055100?thread_ts=1638336618.055100&cid=C0GLTDB2T#2021-12-1919:58R.A. Porterpartition
was popular on that day.#2021-12-1919:59Filip Strajnarthanks sooo much, very helpful#2021-12-1919:59Filip StrajnarI'm gonna look up how partition works, seems interesting#2021-12-1919:54Filip Strajnari'm just trying to make really really short solution#2021-12-1919:54Filip Strajnari'm aware it's not the most readable one#2021-12-1919:55Filip Strajnaressentially it gets a range of the array of inputs, each index is put through this anonymous function to check if next number is greater than current, and count the filtered list#2021-12-2004:46Aleks🧵Day 20 Solutions Thread: post your solution here#2021-12-2007:10normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day20/main.clj I'd feel bad about the solution here, but after day 19 I'm just happy to be done#2021-12-2007:15AleksWorks for both demo and real inputs
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_20.clj#2021-12-2007:20Aleks@U0954HGDQ a hint about infinity is a blinking void#2021-12-2007:31normanYeah, I had that but I was deferring to part 2 to figure how I needed to worry about it. I hacked around it and then found out part2 just needed a slightly larger constant in the hack... wheeee#2021-12-2007:32AleksYeah, I read your comments in the code 🙂#2021-12-2011:05Antonio BibianoI was like, now way i need to light up infinitely many pixels..and indeed i needed to 😄#2021-12-2011:08Callum Oakleynice twist. part 2 is pretty slow but I need a break from optimising after yesterday… 😅
200ms/9s
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/20.clj#2021-12-2012:14Antonio Bibianomhhh..went with adding a border that changes each iteration pretty slow for the second part, maybe there is something that I'm doing that is obviously slow?#2021-12-2012:31Aleks@U01HY37QQUA actually you don’t need a border#2021-12-2012:33Antonio Bibianoyeah I could have gone with using a map for my grid, but i didn't want to iterate using indices, but probably that would have turned out better#2021-12-2012:35Callum OakleyI used the set of pixels that are on, or the set of pixels that are off. one of the two is always finite#2021-12-2014:28genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day20.clj#2021-12-2016:10kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/20a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/20b.clj. 75ms and 10s. Instead of computing a number for each group of 9 pixels in an enhancement pass and using that to look up, which I supposed might be a bottleneck, I built the groups into the lookup table and used it as the lookup object. I don't know if that's actually faster in the end.#2021-12-2017:39tschadysame kind of solution as others. 95ms / 5s
https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#aoc2021d20
Only interesting thing I do is :field (cycle [\0 \1])
and (update :field rest)
to oscillate between values at infinity.#2021-12-2020:35karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day20.clj
went for a quick and dirty solution for day20. As in my lookup table first pixel was # and last . I just assumed that infinite board periodically flashes so each turn I alternated between either getting # or . when reaching outside of the board#2021-12-2021:03Sam AdamsEspecially gross code, hacky perimeter-flash logic — hoping to catch up today since I missed the last two days. https://samadams.dev/2021/12/20/advent-of-code-day-20.html#2021-12-2104:55Aleks🧵 Day 21 Solutions Thread: post your solution here#2021-12-2106:47normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day21/main.clj sloppy code as usual, but I think the approach is solid#2021-12-2109:02nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day21.clj#2021-12-2110:34Aleks@U076FM90B Like your approach for switching between two players. I always forget about it#2021-12-2112:49Aleksrefactored my solution with this approach, but basically I got almost the same
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_21.clj#2021-12-2113:09Callum Oakleythat was a fun one. was stuck for a bit because I forgot you had to roll the dice three times, and was confused why I had so many fewer universes than in the example… same approach as everyone else by the looks of it. 2ms/7ms
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/21.clj#2021-12-2115:47Antonio BibianoI think my approach for part 2 is a bit different, i basically count the universes where each player wins or loses after X turns then the number of wins for each turn is the number of universes where the other player does not win in the turn X-1 * the universes where they win in turn X#2021-12-2115:48Antonio Bibiano#2021-12-2115:54Antonio Bibianoturns out slower than @U01HL2S0X71, but maybe it's my code?#2021-12-2117:33AleksLol#2021-12-2117:44Antonio BibianoYeah pretty much every thread on Reddit has this discussion going on#2021-12-2118:24tschadyi don’t loop, just iterate
through whole state space, to track all combos for the visualization I’ll never get around to. 1s part-2.
I do like my fancy mod-1
function to handle base 1 mod, which I went back and applied to some prev problems
(defn mod-1
"Returns the 1-based modulus `base` of `n`"
[n base]
(inc (mod (dec n) base)))
#2021-12-2118:24Callum Oakleynice problem to illustrate the difference between “single recursion” and “multiple recursion” though. I actually like that clojure’s recur
makes the distinction obvious at a glance (though of course automatic tail call optimisation would be cool…)#2021-12-2118:48Aleks@U1Z392WMQ let me stole your lovely mod-1 🙂#2021-12-2118:49tschadythat’s what I’m here for. did you see this one? would clean up a few people’s mixed threading woes.
(defn x-nth
"Returns the `n`th element of sequence `xs`. Works like `clojure.core/nth` but
reverses the order of the arguments so we can use in thread-last pipelines."
[n xs]
(nth xs n))
#2021-12-2118:50Aleksand can you share the link pls, I want to see your solution in clojure. Today I saw one in Python, but it is all about mutating state#2021-12-2118:51tschadykinda gross right now, cleaning up#2021-12-2118:51Aleksyeah, I did, but I prefer (->> coll (drop n …) first)
^_^#2021-12-2119:00tschadymadman#2021-12-2120:56tschady@U067R559Q here’s my immutable solution ~1.2s, no recursion or memoization.
writeup: https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#aoc2021d21
code: https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d21.clj#2021-12-2121:00tschadyso here are the total number of different states at each time tick:
(1 7 49 343 2401 5733 11232 8832 7268 5530 3640 2548 1519 775 375 150 30 3 0)
#2021-12-2121:01Aleks@U1Z392WMQ thanks, I’ll check it tomorrow, need some sleep now
I also tried one, works fast ~300msecs, but looks a bit ugly
(defn qgame [cache [current another :as state]]
(cond
(>= (:score another) 21) [cache [0 1]]
(cache state) [cache (cache state)]
:else
(let [[cache' score']
(reduce (fn [[cache [a b]] [steps freq]]
(let [new-position (move (current :position) steps)
current' (-> (assoc current :position new-position)
(update :score + new-position))
[cache' [a' b']] (qgame cache [another current'])]
[cache' [(+ a (* b' freq)) (+ b (* a' freq))]]))
[cache [0 0]]
[[3 1] [4 3] [5 6] [6 7] [7 6] [8 3] [9 1]])]
[(assoc cache' state score') score'])))
#2021-12-2121:24Sam AdamsSlow and verbose: https://samadams.dev/2021/12/21/advent-of-code-day-21.html
This one was very satisfying — but I also fumbled around for a while forgetting that 3 dice were rolled per turn.#2021-12-2121:45Antonio BibianoI think mine could be adapted to be used with iterate
! Because I generate the possible states at each turn but group them by winning and not winning and just count #2021-12-2121:45Antonio BibianoI'll try that tomorrow :)#2021-12-2203:01kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/21a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/21b.clj, 11ms and 51s.#2021-12-2203:03kevincmy first attempt at part 2 allocated 40GB before I killed it… then I came back to try DFS, which worked better. using pmap
to fork over the first few depths was useful too.#2021-12-2204:48Aleks🧵 Day 22 Solutions Thread: post your solution here#2021-12-2207:44Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_22.clj#2021-12-2207:47normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day22/main.clj#2021-12-2209:02AleksRefactored my solution#2021-12-2213:30Callum Oakleykeeps track of the sequence of disjoint cuboids that are on, so that the result is the sum of the volumes. bit of a mess and pretty slow. will probably revisit to try and clean it up later.
49s
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/22.clj#2021-12-2213:32Callum OakleyI see you’re both doing something totally different! very neat. how long does it take? looks like it’s probably faster…?#2021-12-2216:00Aleksit’s pretty fast#2021-12-2216:01Aleks~156msecs#2021-12-2216:06Aleks@U050UBKAA used a different approach, ~829msecs on my machine
https://github.com/tonsky/advent-of-code/blob/main/src/advent_of_code/year2021/day22.clj#2021-12-2217:15Antonio BibianoTook me a while! after solving it completely wrong the first time..#2021-12-2217:19Antonio BibianoI keep track of the sizes of the input cuboids and the cuboids that result from an overlap with negative size#2021-12-2218:48Antonio BibianoTakes 12 seconds though 😞 i end up with 32191 cuboids in my list..#2021-12-2219:02Callum Oakleyre-wrote my solution based on the same method as @U067R559Q and @U0954HGDQ. thanks both 🙏
23ms/36ms now
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/22.clj
fun function of the day, inspired by haskell’s tails
(probably should be a lazy-seq for serious use)
(defn rests [coll]
(when (seq coll)
(cons coll (rests (rest coll)))))
#2021-12-2220:35Antonio Bibianothe visualization for today are so cool#2021-12-2221:52Callum Oakleyagreed! I chuckled at this:#2021-12-2419:37kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/22a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/22b.clj. In both cases I worked one dimension at a time. And if you process the steps in reverse order, then you only need to think about the space that no prior step has mentioned yet. In graphics terms, this is like the way a Z-buffer can prevent overdraw, but only when you draw front-to-back.
For part 1 I iterated over all x, y, and z values, filtered steps' boxes by whether they intersected that plane, and counted the value from the first match over all three dimensions.
For part 2 I inserted each box in a tree where the root node holds a list of mutually exclusive intervals across x, with child nodes doing the same for the next dimension (unless that interval is empty). Inserting a box involves splitting intervals over new planes, then recursing to insert into the existing child node on the next dimension. There are plenty of ways to improve performance but 4.5s was ok for me. I shudder to think of copying those child nodes without persistent collections!#2021-12-2205:03normanAny time I see 3d-space questions, I dread getting started#2021-12-2222:46lreadSame. I need to visualize my experiments. And that’s hard for me to do in my brain when reading textual x y x coords.
Maybe adding a graphics library to draw the 3d things would help.
Know of any that might work well?#2021-12-2301:07lreadI’m starting to play with quil… haven’t got far yet…#2021-12-2323:37lreadYeah https://github.com/quil/quil seems to be helping me with the 3d puzzles. Had to wrap my brain around how it works, but I understand the basics enough to play a bit!#2021-12-2209:28Alekshttps://twitter.com/algrison/status/1473344262762905612?s=20 made by @a.grison, not me#2021-12-2304:55Aleks🧵 Day 23 Solutions Thread: post your solution here#2021-12-2309:05AleksSolved it by hand LOL, gonna write a code later#2021-12-2309:40normanI have part1, finally. But now I see part 2. Maybe in the morning...#2021-12-2316:07nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day23.clj#2021-12-2318:00Aleks@U076FM90B how many time did you spend?#2021-12-2318:13nbardiukA lot 😅 I had a bug and had to make a big break just to refresh my head. From day 20 I feel tired a bit#2021-12-2318:23AleksHope the last one won’t be so tough#2021-12-2319:35normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day23/main.clj complete rewrite from part1 last night - I really liked this problem even though it was way too much work #2021-12-2320:16AleksAn illustration https://i.imgur.com/h02XUWQ.jpg#2021-12-2320:53normanThe visualization get more and more life-like every year :)#2021-12-2408:08Andrew ByalaOof, I did not enjoy today’s puzzle, but darn it I got the code done! Part 1 with the test data takes a little over a minute to process, but the puzzle data and both inputs to Part 2 take between 6 and 10 minutes to run apiece. Can’t say I’m super proud of this one, but the code works and it’s actually fairly simple to look at, even if it’s inefficient!
• https://github.com/abyala/advent-2021-clojure/blob/main/docs/day23.md
• https://github.com/abyala/advent-2021-clojure/blob/main/src/advent_2021_clojure/day23.clj#2021-12-2409:58Antonio Bibianoi can't figure out a strategy for this one, I wanted to do a dumb bruteforce but I run out of memory, even though top doesn't show more than 80%, is that normal?#2021-12-2411:53Aleks@U01HY37QQUA It might be you have too many possible movements.#2021-12-2411:57Aleksstill haven’t written the code but here is my steps to solve the problem
https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_23.clj#2021-12-2413:26Antonio BibianoYeah I also had a small bug in the calculation of possible states #2021-12-2413:26Antonio BibianoNow it's slowly chugging along :D#2021-12-2413:27Antonio BibianoI also resorted to solving part 1 manually just to see part 2 and boy oh boy i made my code really hard to extend :D#2021-12-2413:33AleksI found https://amphipod.net/ a nice tool to help you solve your input by hand 🙌:skin-tone-2:#2021-12-2421:07Callum Oakleya day behind now because of Christmas commitments… Dijkstra again. by a stroke of luck I barely had to change anything for part 2.
14s/17s
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/23.clj#2021-12-2508:46Antonio BibianoI also finished my brute force today, takes a few minutes on the example, more than 2 hours on part 1 and again a few minutes on part 2 :D#2022-12-3104:24kevinchttps://github.com/kconner/advent-of-code/blob/master/2021/23a.clj, https://github.com/kconner/advent-of-code/blob/master/2021/23b.clj in 18s and 25s#2021-12-2404:45Aleks🧵 Day 24 Solutions Thread: post your solution here#2021-12-2410:47Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_24.clj#2021-12-2416:36nbardiukDecompiled code by hand and run brute force, takes 10 mins each part https://github.com/nbardiuk/adventofcode/blob/master/2021/src/day24.clj#2021-12-2417:06Aleks@U076FM90B you’re a real hacker!#2021-12-2423:39normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day24/main.clj Not an automated solution, but it's the code I used at the repl to figure it out#2022-12-2619:42Antonio BibianoI just wrote some code to run the monad program#2022-12-2619:43Antonio Bibianoto check my calculations but the meat of the problem I solved by hand 🙂#2022-12-2620:48Antonio BibianoWent ahead and wrote a program anyway because it felt good :D#2022-12-2819:21genmeblogI solved it by hand and then based on this created a macro to generate search code https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day24.clj#2022-01-0115:32tschadymedium sized writeup with spoilers: https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#aoc2021d24#2021-12-2407:45normanI'm not getting part1 tonight. I made good progress reverse engineering the code and have, I think, part of my solution. But I'm going to have to come at it fresh tomorrow. sigh... Good luck to anyone still going...#2021-12-2504:54Aleks🧵 Day 25 Solutions Thread: post your solution here#2021-12-2505:42Charles Comstockhttps://github.com/dgtized/advent-of-code/blob/master/2021/day25/sea_cucumber.clj#2021-12-2505:44normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day25/main.clj#2021-12-2506:54Alekshttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_25.clj#2021-12-2507:40Andrew ByalaNothing too tricky here, but I threw in a multi-method mostly to make the code and blog a little more interesting for my non-Clojure coworkers to read.
• https://github.com/abyala/advent-2021-clojure/blob/main/docs/day25.md
• https://github.com/abyala/advent-2021-clojure/blob/main/src/advent_2021_clojure/day25.clj#2022-12-2712:42Antonio BibianoI forgot there was no part 2#2022-12-2712:43Antonio Bibianoso i kept track of the empty spaces too because I figured it would ask to find the biggest empty space or something 😄#2022-12-2712:44Antonio Bibiano#2022-12-2819:10genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day25.clj#2022-12-2822:14tschadydoc: https://github.com/tschady/advent-of-code/blob/main/doc/2021.adoc#aoc2021d25
code: https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d25.clj
Cool bit:
> This is my first use of `as→`. I always thought it obfuscating, but I like it here.
(defn step [dx dy grid]
(as-> grid g
(reduce (partial shift dx dy g) g (filter-vals #{\>} grid))
(reduce (partial shift dx dy g) g (filter-vals #{\v} grid))))
#2021-12-2518:30AleksIt’s too silent today here. Congras everyone who managed to finish Advent of Code 2021. 🎉 And even if you didn’t finish, I believe you got some fun by solving the problems. Maybe one day, you will. 🙌:skin-tone-2:#2021-12-2520:35StuartI ran out of time to solve each day around day 15.
My goal is now to finish this year before next year starts 😆#2021-12-2521:00Miķelis VindavsThanks everyone for sharing your solutions and insights! It was interesting to see the different approaches everyone took#2022-12-2606:16Aleks@U89SBUQ4T that’s one of the aspects of AoC why I like solving it in time. Always learn something new by reading other’s approaches.#2021-12-2520:57spfeifferI am still stuck somewhere in 2016 ¯\(ツ)/¯#2022-12-2606:06Aleksafter AoC 2020 I was solving 2015, 2016 and almost all 2017#2022-12-2610:01MnoThis year I got a pretty decent handle on transducers, so original goal accomplished#2022-12-2611:26Antonio BibianoYeah I learned a ton about clojure! Thanks everybody for posting your solutions!#2022-12-2721:32zxspectrri'm not finished yet but i've learnt a great deal from your answers 😄#2022-12-3014:58zxspectrrhi, i'm a bit late but i'm stuck on day 19, i don't understand why there are up to 24 orientations. four combinations on three axis suggests 12 combinations, rather than 24#2022-12-3015:10tschadyx 2 for direction facing on the axis#2022-12-3015:20zxspectrri wrote some code to take a pos and rotate it 4 times per axis which got me to 12#2022-12-3015:20zxspectrreg rotate-x + rotate-y + rotate-z
#2022-12-3015:21zxspectrri guess it only got me half way. I think i'll move on to 20 and come back to 19 since it seems very complex#2022-12-3015:24zxspectrrit sounds mad but i just took off one of my shoes and moved it around in the air, you're right i'm missing another 12 😄#2022-12-3016:04genmeblogthink about watching a cube. There are 6 sides you can look at. And each side can be seen from four different rotations.#2022-12-3016:16zxspectrrthat helps, ty#2022-12-3023:29lreadThis one drove me a bit coocoo!
I actually took two wooden blocks, one to imagine the sensor and one to image some point in space.
I then rotated the sensor and observed how that affected the sensor’s perception of x y and z.
I also used quil to visualize the cuboids.#2022-12-3023:54lreadI’m still 5 stars away from the finish line!
I’m finding that the puzzles can be a bit… addictive. simple_smile
The nice thing for now is that if I get stumped by one I can move to another.#2022-12-3023:54zxspectrrim slowly getting through them#2022-12-3023:54zxspectrrit's been quite a lot of work for me as i'm a novice in clojure#2022-12-3023:55zxspectrrwasted a lot of time on day 20 by incorrectly copying the test algorithm 😐#2022-12-3023:55lreadYeah, I made some bone-headed moves like that too.#2022-12-3023:56zxspectrrthinking in a non-imperative way is hard for me due to years of java#2022-12-3023:58lreadI’d say I’m maybe (?) approaching intermediate competency in Clojure.
Some of these puzzles hurt my brain because it has had little to no practice in some areas.
Anything 3d was tough for me. And the maze-y ones too.
And I’m still not clear on splitting universes. simple_smile#2022-12-3023:59zxspectrri struggle a bit with some of the algorithms more than the language#2022-12-3100:00zxspectrrbut when i hit a corner i think i can probably get myself unstuck a bit quicker with experience in working with the repl#2022-12-3100:00lreadYup, me too. Good exercise for the old noggin!#2022-12-3100:00zxspectrrfor example on day 20, if i'd just thought to dump the output to file so i could look at it i'dhave found the gotcha about the alternating void#2022-12-3100:00lreadYeah the repl is great for testing ideas quickly.#2022-12-3100:02lreadOh yeah, the trench map, that one was a clever puzzle, I thought. It wasn’t an instant win for me, but I got there!#2022-12-3100:05zxspectrr🙂#2022-12-3100:06lreadI’m trying to avoid studying solutions of others until I’m all done.
But am looking forward to learning from approaches of others to solving these puzzles.#2022-12-3100:25zxspectrri read through other solutions after i finish each one#2022-12-3100:25zxspectrrhelps with the next day#2022-12-3100:34lreadYeah, maybe not a bad idea there!#2022-12-3116:58tschadywoohoo finished 2021 in 2021.#2022-12-3119:10Adam Haberhi, I’m trying to go through aoc but I feel my solutions to all the days that are very “2d-array-oriented” (like day 11 - when a cell flashes and increments everything around it) are awkward#2022-12-3119:11Adam Haberif someone has a solution which they feel is pretty “idiomatic” for these kind of exercises, I’d be very happy to learn from it. Thanks!#2022-12-3119:43Antonio BibianoOne of the thing that I noticed is that by using a map with tuples of coordinates as keys made some solutions quite elegant#2022-01-0609:24Adam HaberHi! Does anyone knows if day 16 (packet decoder) is solvable by something like Kern?
https://github.com/blancas/kern#2022-01-0609:25Adam HaberI thought it could be a good opportunity to learn some interesting parsing techniques (like parser combinators) but I’m not sure if the structure of the program is amenable to such a solution#2022-01-0609:28Adam Haber(https://github.com/Engelberg/instaparse also looks like an interesting parsing library, so same question :-))#2022-01-0615:50tschadyNote: I am not a ParseMaster. I’m more familiar with Instaparse, zero with kern.
I don’t think you can do it with a pure CFG, because there would be ambiguity in level of subgroup, and that matters for part2. You need to recurse to either n
subgroups or m
bit length of subgroups. I think you can get the groupings right, but not the levels. I thought about hardcoding the n
with PEG lookaheads and BNF, like just handling 1-9, but I don’t know a way to handle the m
case. Which means you have to write code, so at that point I just did it with plain old clojure.
Kern’s state tracking is promising though, I hadn’t seen that before. Looks easy to handle n
, and after a quick source browse, you may be able to get m
through get-position
. That seems to be the crux, figuring out how to consider the next m
bits for parsing. I’m very interested if you crack it.#2022-01-0617:59Adam HaberI think I’m making progress, but it’s a bit hacky, I think - would really appreciate your feedback @tws! I am just learning Clojure, so this is probably very non-idiomatic. My idea was to programmatically generate the appropriate parser:
(def base-parser-rules
"packet = literal_packet | op_0_packet | op_1_packet
literal_packet = version lit_val_type lit_val
op_0_packet = version op_type '0' rest15 op_rest
op_1_packet = version op_type '1' rest11 op_rest
version = #'\\d{3}'
rest11 = #'\\d{11}'
rest15 = #'\\d{15}'
lit_val_5 = #'\\d{5}'
lit_val_4 = #'\\d{4}'
lit_val_1 = #'\\d{1}'
lit_val_2 = #'\\d{2}'
lit_val_3 = #'\\d{3}'
lit_val_type = '100'
op_type = '000' | '001' | '010' | '011' | '101' | '110' | '111'
lit_val = lit_val_5+ (lit_val_1 | lit_val_2 | lit_val_3 | lit_val_4)?
op_rest = #'\\d+'")
(def base-parser (insta/parser (str/join " \n " (list "S = packet" base-parser-rules))))
(defn parser-n-packets [n]
(insta/parser
(str/join " \n "
(list
(str/join " = " (list "S" (str/join " " (reverse (conj (repeat n "packet") "op_rest")))))
base-parser-rules))))
#2022-01-0618:00Adam HaberI think it’s starting to do what I want it to do… I’m having a really hard time with the tree structure returned by insta/parser; I’m sure there are nice ways to traverse/process it, I just haven’t found them 🙂#2022-01-0619:02tschadytransform
is the function to use to shape the tree output. I dunno, I think you’ve hit the wall. You’d have analyze rest11
and rest15
outside this grammar AFAICT, which is doable but I need one BNF grammar to make it appealing for me.#2022-01-0619:43Adam HaberGot it. I thought this was doable with parser combinators (eval rest11/rest15 and proceed parsing accordingly), but I guess it’s not (or just significantly harder than I thought)… thanks anyway!#2022-01-0714:10tschadyyou’ve nerd sniped me. going to see what I can do on this over the weekend.#2022-01-0619:51tschadydon’t let my relative ignorance talk you out of it. the extent of my instaparse
knowledge is from past advent of code years#2022-01-0703:17kingcode@adamhaber I just finished day 16 - it was quite straightforward using multi-methods (used parse-body
and eval-packet
mms for part 1 and part 2 resp.). Actually the hardest was hand tracing the examples to understand the requirements.#2022-01-0706:41Adam Haberinteresting! can you share your solution?#2022-01-0713:53kingcodeSure, here it is:
https://github.com/KingCode/advent-of-code/blob/main/src/advent_of_code/_2021/day16/day16.clj#2022-09-0109:35mishatomorrow https://icfpcontest2022.github.io/#2022-09-0112:23tschadyanybody do it last year?#2022-09-0209:26borkdudeWould anyone be interested in testing #clavascript for Advent of Code problems?
It is a dialect of Clojure that looks a lot like CLJS, but is built on mutable JS, it does not come with persistent data structures. {:a 1}
means mutable object and [1 2 3]
is an array.
It's basically "write CLJ syntax, get JS". I think it could be really interesting for AoC.
https://github.com/clavascript/clavascript#2022-09-0209:45borkdudeExpect some rough edges though, but it might be fun to fix those as part of the challenge :)#2022-09-0210:59borkdudeMade a repo here: https://github.com/clavascript/advent-of-code#2022-09-0211:11borkdudeThis is my solution to day 1:
https://github.com/clavascript/advent-of-code/blob/main/2021/day01_borkdude.cljs
You're welcome to contribute yours :)#2022-09-0219:37Ben LiebermanThis looks fun, I will check this out. You can do day 1 part 2 with (nthrest coll 3)
I believe :thinking_face: I did this problem recently and I believe that worked#2022-09-0219:38borkdudeNice! Note that clavascript is a re-implementation of CLJS-ish in JS so not all core functions exist yet, but that is a good chance to post an issue and maybe submit an implementation#2022-09-1218:50borkdudeAdvent of Code helpers written in babashka:
https://github.com/jjcomer/aoc-helper#2022-10-1909:07borkdudeIf you're using babashka for advent of code, please upgrade to the 1.0 release. Babashka has undergone several significant performance improvements in 2022!#2022-11-1418:03Seanthinking about playing around with Advent of Code this year with Clojure - if i’m completely new to clojure/lisp what’s a decent resource to start with to get comfortable?#2022-11-1418:16Ben LiebermanIf I'm not mistaken I've seen some videos of AoC problems being solved with Clojure, if that seems interesting to you.#2022-11-1418:22Seangreat! that’d be a decent starting place i’m sure#2022-11-1418:22Ben LiebermanLet me find them#2022-11-1418:22Seanmuch appreciated#2022-11-1418:23Ben Liebermanhttps://www.youtube.com/playlist?list=PLbPrugU2oQ8VURsQdZ6W_iovXRS24UmZQ#2022-11-1419:47kpav4clojure has some good exercises to get you familiar with various clojure functions -- https://4clojure.oxal.org/#2022-11-1508:53AleksAlso highly recommend this series from Lambda Island https://www.youtube.com/watch?v=9ITiZ88sljA&list=PLhYmIiHOMWoGIMCmCRwMSrWkHJg12vevR&ab_channel=LambdaIsland#2022-11-1512:33ryan echternachtIf you're looking for editor support, I'd recommend Calva on VSCode (unless you're already very comfortable with emacs or vim, at which point there are good plugins for those)#2022-11-1713:39tschadyIf you learn by example, check the pins in this channel, there’s a wide variety of approaches#2022-11-1817:08Rolandas GriškevičiusAlso recommend series from Nikita Prokopov: https://www.youtube.com/playlist?list=PLdSfLyn35ej-UL9AuxUvoFXerHac4RYnH#2022-11-2511:08pwojnowskiBack in 2018 I've written a post for beginners, where I explain step-by-step how to solve AOC problem in Clojure REPL: https://medium.com/virtuslab/advent-of-code-2018-day-2-clojure-repl-e3b288fdedfb (sorry for shameless plug :man-shrugging: ). It may be helpful to see how to approach probelms in Clojure.#2022-11-2016:29Ben SlessAnyone thinking of doing AoC this year with Unison?#2022-11-2407:15Mikko KoskiBlogged: https://www.mikkokoski.com/blog/8-tips-for-advent-of-code-2022/index.html 🎄#2022-11-2414:37borkdudeIf you're looking for something to do AoC puzzles in #CLX41ASCS, this may help https://blog.michielborkent.nl/babashka-test-runner.html#2022-11-2415:21elkenLooks like some stuff from Show me your REPL 👀#2022-11-2415:33borkdudeIt does!#2022-11-2814:23normanIs our leaderboard code still 217019-4a55b8eb
?#2022-11-2816:03Applei think so!#2022-11-2920:34mkvlrI’ve created a https://github.com/nextjournal/advent-of-clerk for folks who want to try doing AoC with Clerk.#2022-11-2922:07tschadyfeature request: static page gen?#2022-11-3006:40mkvlrwe will announce https://clerk.garden at reClojure this week, feel free to give it a try now and report issues in #clerk-garden.#2022-11-3022:39tschady@U5H74UNSF you’ve 0 indexed days (0-24), might be better as (range 1 26)
#2022-12-0112:07mkvlr0 is intentional and meant to be deleted#2022-12-0112:07mkvlris there a day 25 as well?#2022-12-0112:07mkvlrah TIL#2022-12-0112:18mkvlrhttps://github.com/nextjournal/advent-of-clerk/commit/2401fe42669220673f4a8dc6b70682483fae7038#2022-12-0122:15chuckleheadworkflow that will build/deploy to gh pages: https://github.com/casselc/aoc22/blob/main/.github/workflows/gh-pages.yml#2022-11-3013:49borkdudeJust released bb 1.0.167 - the ultimate Advent of Code edition (meaning: the best performance so far). Please use this version if you're going to use bb for solving puzzles :)#2022-11-3015:13delaguardo1.0.167-AoC-2022 ?#2022-11-3015:23borkdude:)#2022-12-0105:00normanDay 1 - have fun!#2022-12-0105:20normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day01/main.clj#2022-12-0105:48karlisHere's mine for today. Nice and easy start for the month 🙂 https://github.com/skazhy/advent/blob/acf852ec2ea2ec527b451c0993456c15fe8e95d5/src/advent/2022/day1.clj#2022-12-0107:52Mikko Koskihttps://github.com/rap1ds/advent-of-code-2022/blob/main/src/day1.clj#2022-12-0108:07nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2022/src/day01.clj#2022-12-0108:57Aleks"\R\R"
❤️#2022-12-0109:52CarnunMPand I thought https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d1.clj was terse! 🙃#2022-12-0110:29StuartDay 1 easy as expected.
(defn parse-input []
(->> (slurp "puzzle-inputs/day1")
(str/split-lines)
(map parse-long)
(partition-by nil?)
(remove #(= '(nil) %))
(map #(apply + %))))
;; part 1
(->> (parse-input)
(apply max))
;; part 2
(->> (parse-input)
(sort >)
(take 3)
(reduce +))
#2022-12-0110:40genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day01.clj#2022-12-0110:47Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/Y2022/calories.clj#2022-12-0111:06tschadyhttps://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d01.clj#2022-12-0111:07tschadytime to update my helpers with parse-long
#2022-12-0112:09Martin Půda(ns aoc2022.day01
(:require [clojure.string :as s])
(:gen-class))
(defn block->calories [block]
(transduce (map parse-long) + (s/split-lines block)))
(def data
(->> (s/split (slurp "resources/input01.txt") #"\n\n")
(map block->calories)))
(defn part1 [data]
(reduce max data))
(defn part2 [data]
(->> data
(sort >)
(take 3)
(reduce +)))
#2022-12-0112:16StuartThat's neat, splitting on "\n\n" to get rid of havintg to partition by nil or "", then remove them#2022-12-0112:18borkdudeMy day01 in babashka and nbb:
https://github.com/borkdude/advent-of-babashka/blob/main/src/aoc22/day01.cljc#2022-12-0112:19mkvlrhere’s my day 1 with #C035GRLJEP8 and #C04ATSH4QNM https://github.clerk.garden/mk/advent-of-clerk/commit/876b9bb61434bd632ef25fe1d39a3550209c073c/src/advent_of_clerk/day_01.html#2022-12-0112:21mkvlroh I see I missed part 2#2022-12-0112:27noogaThis is let-go, not Clojure nor CLJS:
(ns day1)
(defn parse [ls]
(loop [[l & r] ls sum 0 out []]
(cond
(nil? l) out
(empty? l) (recur r 0 (conj out sum))
:else (recur r (+ sum (parse-int l)) out))))
(def data (->> "day1.txt" slurp lines parse (sort >)))
(println "1:" (first data))
(println "2:" (->> data (take 3) (apply +)))
#2022-12-0112:31Stuartwhats let-go ?#2022-12-0112:32noogahttps://github.com/nooga/let-go @U013YN3T4DA#2022-12-0112:32mkvlr@U04V15CAJ thanks TIL about take-nth and sort-by -
is prettier than reverse
#2022-12-0112:35borkdude@UJEK1RGJ0 if I change parse-int
to parse-long
and lines
to clojure.string/split-lines
the code worked in bb too :)#2022-12-0112:36nooga@U04V15CAJ I just literally plopped lines
and parse-int
into my stdlib so I could solve the AoC 😄 will clean that up some day when it's time to get my APIs closer to the real deal#2022-12-0112:38borkdude@UJEK1RGJ0 maybe you can support reader conditionals, would be fun to compare solutions in different clojure dialects#2022-12-0112:44noogacool idea, I'll look into this over the weekend :D#2022-12-0113:16StuartHas filterv
always been in clojure, or is a recent thing ?#2022-12-0113:17borkdudeuser=> (:added (meta #'filterv))
"1.4"
#2022-12-0113:17StuartTIL 🙂 Had no idea there as a v
version#2022-12-0113:17borkdudeThere will also be a partitionv
in 1.12 :)#2022-12-0113:19StuartIs that going to make each bucket a vector too, or more like [(1 2) (3 4)]
?#2022-12-0113:21borkdude@U013YN3T4DA You can try with:
clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.12.0-alpha1"}}}'
and read here:
https://clojure.org/news/2022/06/30/clojure1-12-alpha1#2022-12-0116:21delaguardo(ns aoc2022.day-1
(:require [aoc2022.misc :as misc]))
(defprotocol Top
(-push [this] [this x]))
(defrecord TopOne [x]
Top
(-push [_] x)
(-push [this y]
(if (> y x)
(new TopOne y)
this)))
(defrecord TopThree [x y z]
Top
(-push [_] (+ x y z))
(-push [this a]
(cond
(> a x)
(new TopThree a x y)
(> a y)
(new TopThree x a y)
(> a z)
(new TopThree x y a)
:else
this)))
(defn solve-1 []
(binding [misc/*day* 1]
(misc/read-lines
(fn [xs]
(transduce
(comp (map parse-long)
(partition-by nil?)
(map #(reduce (fnil + 0 0) 0 %)))
-push
(new TopOne 0)
xs)))))
(defn solve-2 []
(binding [misc/*day* 1]
(misc/read-lines
(fn [xs]
(transduce
(comp (map parse-long)
(partition-by nil?)
(map #(reduce (fnil + 0 0) 0 %)))
-push
(new TopThree 0 0 0)
xs)))))
(comment
(time
(dotimes [_ 10000]
(solve-1)))
(time
(dotimes [_ 10000]
(solve-2)))
)
day one without using sort 🙂#2022-12-0118:35nooganeed to wrap my head around implementing transducers, it would be fun to have them at the bottom, gosh I think I really need a let-go channel#2022-12-0201:18peterhI use the “Advent of Clerk” template and really enjoy trying to figure out a nice experimental, notebook-oriented workflow. I try learning from other solutions posted here and document my insights in “TIL” comments. 🙂
https://github.com/formsandlines/aoc2022-clojure/blob/main/src/advent_of_clerk/day_01.cljc#2022-12-0201:22peterhBtw, since I wanted to run tests from Babashka, I needed to exclude the Clerk import via a reader conditional, because otherwise I cannot run the test command due to an error.#2022-12-0202:27ChaseExcited for a new AOC and to learn from all your cool solutions!
https://github.com/Chase-Lambert/aoc-clojure/blob/main/src/aoc/2022/day_01.clj#2022-12-0204:30jaihindhreddySorting is a lot of unnecessary work considering that we only need top 3, especially for large datasets.
Here's something that doesn't do a full-sort, much like @U04V4KLKC did (although his method is even more bespoke):
(defn day1 [fpath]
(let [xs (str/split (slurp fpath) #"\R\R")
q (java.util.PriorityQueue. (count xs) (comparator >))
_ (run! #(->> (re-seq #"\d+" %)
(transduce (map parse-long) +)
(.add q))
xs)
x (.poll q), y (.poll q), z (.poll q)]
[x (+ x y z)]))
I'd appreciate any feedback 😄.#2022-12-0207:23robertfwafter some refactoring I ended up with this as an attempt to do the task in one lazy pass
(ns adventofcode2022.day1
(:require
[ :as io]))
(comment
(with-open [rdr (-> "adventofcode2022/day1.txt" io/resource io/reader)]
(let [calorie-sums
(sequence (comp (partition-by #{""})
(remove #{'("")})
(map #(map parse-long %))
(map #(reduce + %)))
(line-seq rdr))
top-three
(reduce (fn [acc x]
(if (< (first acc) x)
(sort (conj (rest acc) x))
acc))
'(0 0 0)
calorie-sums)]
{:part1 (last top-three)
:part2 (reduce + top-three)}))
;; => {:part1 69310, :part2 206104}
)
#2022-12-0520:26dogenpunkJust realized people are posting these every day. Here’s my day 1: https://github.com/dogenpunk/advent-of-code/blob/main/src/aoc22/day01.cljc#2022-12-0718:20mbjarland(ns day-01
(:require [clojure.string :as str]))
(defn input []
(for [elf (str/split (slurp "../day_01.data") #"\n\n")]
(reduce + (map parse-long (re-seq #"\d+" elf)))))
(defn solution-1 []
(apply max (input)))
(defn solution-2 []
(reduce + (take-last 3 (sort (input)))))
#2022-12-0112:08mkvlrhere’s my day 1 with #C035GRLJEP8 and #C04ATSH4QNM https://github.clerk.garden/mk/advent-of-clerk/commit/876b9bb61434bd632ef25fe1d39a3550209c073c/src/advent_of_clerk/day_01.html#2022-12-0112:20mkvlrsorry, didn’t know & move it there#2022-12-0112:13tschady> A group of a thousand elves on an expedition carrying backpacks filled to the brim --v 4
> By MidJourney
> https://www.reddit.com/r/adventofcode/comments/z9g0i0/ai_imagine_advent_of_code_2022_day_1/
#2022-12-0112:15borkdudeI created a repository to help with doing Advent of Code in #babashka and #nbb!
https://github.com/borkdude/advent-of-babashka-template
Spoiler alert: it contains a solution for day 1.#2022-12-0112:26elkenI did something similar that also pulls the input file too. All you need is to curl the URL and pass the cookie in a header https://github.com/elken/aoc (contains solutions so spoiler alert)#2022-12-0112:27borkdudeoh, we can update this repo to do that#2022-12-0112:27borkdudewith bb new-day --token ....#2022-12-0112:28borkdudePR welcome#2022-12-0112:28elkenNice, yeah I will when I'm off the train 😁#2022-12-0113:58genmeblogJust a reminder: there exists #CLX41ASCS script made by @tws which produces such nice badges:#2022-12-0113:58genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/badges/badges.bb#2022-12-0113:59genmeblogoriginal source: https://github.com/tschady/advent-of-code/blob/main/script/update_badges.clj#2022-12-0114:03borkdudeOh, it would be nice to have a PR with a link to this in the repo I just created...#2022-12-0114:03borkdudeor maybe integrate it in that repo#2022-12-0115:15tschadynow you’re going to force me to clean that up crying-laughing-joy-blood#2022-12-0115:17tschadyI execute with bb badges
{:paths ["resources" "script"]
:tasks {badges {:doc "Updates README badges with latest puzzle completion stats."
:task (shell "bb script/update_badges.clj")}
#2022-12-0115:20borkdudeCool :) You can also do (load-file "script/...")
#2022-12-0115:21genmeblogDon't forget that you have to download session cookie manually to use this script.#2022-12-0115:42tschadyand get the favicon locally#2022-12-0115:43borkdudeMaybe someone can make this a proper library so it can be used in bb.edn#2022-12-0115:44tschadyit’s on my list, along with downloading input: https://github.com/tschady/advent-of-code/blob/main/script/download_input.clj
This was just for my use, i didn’t librify it yet.#2022-12-0115:44tschadybb dl 2022 1
#2022-12-0115:44borkdudeyeah, no obligations of course, just would be nice to have for people :)#2022-12-0206:42Alex AlemiGreat script! Eric has requested that we all put a "User-Agent" field into our requests from scripts. I've modified your script to do that here: https://github.com/alexalemi/advent/blob/main/scripts/badges.clj#L32#2022-12-0206:42Alex AlemiI also have a little input fetching utility: https://github.com/alexalemi/advent/blob/main/scripts/utils.clj#2022-12-0206:43Alex Alemiwhere I try to be nice and ensure that I don't make more than one request by checking to ensure that it is the proper time and not requesting the input once I've already gotten it. In this way shortly before midnight I can just run watch bb fetch
(I set up a bb task) and it'll only make one request to the page and grab the input while I'm reading the problem#2022-12-0115:54Applehow do you make this nicer
(->> x
(map #(map parse-long %))
(map #(reduce + %))
the two maps can you combine them?#2022-12-0115:56Apple(let [x (->> (slurp "src/y2022/input202201")
(re-seq #"\d+|\n\n")
(partition-by #{"\n\n"})
(remove #{["\n\n"]})
(map #(map parse-long %))
(map #(reduce + %))
sort
reverse
(take 3))]
[(first x) (reduce + x)])
my solution for day1#2022-12-0116:00borkdudeyou can use transducers for to speed things up#2022-12-0116:00borkdudebut in this case it's not important, but it is a way to fold those maps#2022-12-0116:00borkdudefwiw, I haven't used it in my solution#2022-12-0116:11elkenI've tried to force myself to use transducers more this year as a learning exercise, but I already failed lol
Edit: found a way https://github.com/elken/aoc/blob/master/src/solutions/2022/day01.clj#2022-12-0116:38Ben LiebermanI was just about to give clojure.walk/walk
a try for this, not sure if it will work. TBD#2022-12-0116:46normanTo me, for
cries out as the most idiomatic way to express this, and for just two operations I might not bother threading:
(for [group x]
(reduce + (map parse-long group)))
#2022-12-0116:47normanOr with the threading
(for [group x]
(->> group
(map parse-long)
(reduce +)))
#2022-12-0118:08Aleks(defn parse-input [input]
(map (fn [xs]
(->> (re-seq #"\d+" xs)
(transduce (map parse-long) +)))
(str/split input #"\R\R")))
#2022-12-0718:27mbjarlandyes, what @U067R559Q said, this was mine:
(ns day-01
(:require [clojure.string :as str]))
(defn input []
(for [elf (str/split (slurp "../day_01.data") #"\n\n")]
(reduce + (map #(Integer/parseInt %) (re-seq #"\d+" elf)))))
(defn solution-1 []
(apply max (input)))
(defn solution-2 []
(reduce + (take-last 3 (sort (input)))))
#2022-12-0202:08pyrmontI'm sure there's a blog explaining this (I've had a look but couldn't find anything quite on point) but is there a 'best way' to reset the environment of an nREPL session? I'm trying Neovim with Conjure to solve AOC problems this year and found that the solution I built up for Day 1 was relying on some bindings that I'd renamed in my source file but which I didn't notice were gone until I later on tried to load the file again. What I have found online is more directed at larger scale systems, I just have two files (the source file for the day's solution and a utilities file with some helper functions).#2022-12-0202:54pithylessYou can remove a certain binding with https://clojuredocs.org/clojure.core/ns-unmap
So, if you want to just remove all the bindings in the current namespace, you could eval something like:
(do-seq [sym (keys (ns-interns *ns*))]
(ns-unmap *ns* sym))
Note: that's usually good enough for re-evaluating a single namespace, but it won't eg. clean up other namespaces that have referred to previous bindings. If you need something that tracks dependencies, etc. you may need to use something more heavy-handed like clojure.tools.namespace.repl
#2022-12-0203:00pyrmontThanks. Yeah, I kind of want something that will just blow away everything (without requiring the REPL to be restarted) and so maybe clojure.tools.namespace.repl
is the place to look. Thanks for the above code, though. If the utilities
library remains stable, maybe that is all I need 🙂#2022-12-0203:46pithylessI think the trick is to learn to eval things often as you make small changes. It should be rare to end up with so much change that you need to blow away everything to get back to a known steady-state.#2022-12-0204:01pyrmontYeah, in this particular case, it was two instances where I'd renamed a binding but forgotten to update the references to it.#2022-12-0204:02pyrmontPerhaps the better solution is something that assists in refactorings like this (although that might be overkill for something like an AOC puzzle).#2022-12-0205:38normanDay 2 - looks like we need a solutions thread#2022-12-0205:38normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day02/main.clj#2022-12-0205:51R.A. Porterhttps://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day02.html#2022-12-0206:07Joseph Dumonthttps://gist.github.com/iwrotesomecode/ea0a28a1e0ad5ac55123805d45d8f35e#2022-12-0206:13R.A. PorterI suspect I'll be one of the few to take the particular strategy I used. I'm frankly just too tired to have done it more elegantly tonight.#2022-12-0206:16Alex Alemihttps://github.com/alexalemi/advent/blob/main/2022/clojure/p02.clj#2022-12-0207:16pwojnowski3 lines of code + data: https://github.com/pwojnowski/advent-of-code/blob/master/src/aoc/aoc2022.clj#2022-12-0207:35Martin Půda(ns aoc2022.day02
(:require [clojure.string :as s])
(:gen-class))
(def data
(->> (s/split-lines (slurp "resources/input02.txt"))
(map #(s/split % #" "))))
(defn round-result [s1 s2]
([3 6 0 3 6]
(+ ({"A" 0 "B" 2 "C" 1} s1)
({"X" 0 "Y" 1 "Z" 2} s2))))
(defn points-for-round [[s1 s2]]
(+ ({"X" 1 "Y" 2 "Z" 3} s2)
(round-result s1 s2)))
(defn my-shape-for-situation [s1 s2]
(["X" "Y" "Z" "X" "Y"]
(+ ({"A" 2 "B" 0 "C" 1} s1)
({"X" 0 "Y" 1 "Z" 2} s2))))
(defn part1 [data]
(transduce (map points-for-round) + data))
(defn part2 [data]
(transduce
(map (fn [[s1 s2]]
(->> (my-shape-for-situation s1 s2)
(vector s1)
points-for-round)))
+ data))
#2022-12-0208:14Mikko Koskihttps://github.com/rap1ds/advent-of-code-2022/blob/main/src/day2.clj#2022-12-0208:52nooga(ns day2)
(def syms {"A" 1 "B" 2 "C" 3 "X" 1 "Y" 2 "Z" 3})
(def domi {1 2 2 3 3 1})
(def losi {2 1 3 2 1 3})
(defn parse [l]
(map syms (split l " ")))
(def data (->> "input/day2.txt" slurp lines (map parse)))
(defn score [[a b]]
(+ (cond
(= a (domi b)) 0
(= a b) 3
:else 6)
b))
(defn strat [[a b]]
[a (case b
1 (losi a)
3 (domi a)
a)])
(println "1:" (->> data (map score) (reduce +)))
(println "2:" (->> data (map (comp score strat)) (reduce +)))
#2022-12-0209:45Benjaminhttps://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/Y2022/day2.clj#2022-12-0210:04Valentin Mourethttps://github.com/ValentinMouret/advent-2022/blob/main/src/day_02.clj's longer, but might be more readable.
Feedback is welcome. 🙂#2022-12-0210:11sebastianI just condensed the information into two lookup tables:
(def data (str "input-" day ".txt"))
(def get-score-1 {'(:A :X) 4
'(:B :Y) 5
'(:C :Z) 6
'(:A :Y) 8
'(:A :Z) 3
'(:B :X) 1
'(:B :Z) 9
'(:C :X) 7
'(:C :Y) 2})
(def get-score-2 {'(:A :X) 3
'(:A :Y) 4
'(:A :Z) 8
'(:B :X) 1
'(:B :Y) 5
'(:B :Z) 9
'(:C :X) 2
'(:C :Y) 6
'(:C :Z) 7})
(defn parse [lines]
(->> lines
(map #(str/split % #" "))
(map #(map keyword %))))
(parse (utils/read-lines data))
(defn part-1 [input]
(->> input
(map #(get-score-1 %))
(apply +)))
(defn part-2 [input]
(->> input
(map #(get-score-2 %))
(apply +)))
(part-1 (parse (utils/read-lines data)))
;; => 10404
(part-2 (parse (utils/read-lines data)))
;; => 10334
#2022-12-0210:40delaguardo(ns aoc2022.day-2
(:require [aoc2022.misc :as misc]))
(defmulti score identity)
(defmacro score-methods [points]
`(do
with dynamic multimethods and macro 🙂#2022-12-0211:02CarnunMPhttps://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d2.clj 🙂#2022-12-0211:14nbardiukmy code today is very verbose https://github.com/nbardiuk/adventofcode/blob/master/2022/src/day02.clj#2022-12-0212:22jaihindhreddyMine looks pretty-ugly:
(let [to-int
(let [A (int \A) X (int \X)]
(fn [a x]
(+ (* 3 (- (int a) A))
(- (int x) X))))
p1 (int-array [4 8 3 1 5 9 7 2 6])
p2 (int-array [3 4 8 1 5 9 2 6 7])]
(defn day2 [^String fs]
(let [n (count fs)]
(loop [i 0 x 0 y 0]
(if (>= i n)
[x y]
(let [z (to-int (.charAt fs i) (.charAt fs (+ i 2)))]
(recur (+ i 4)
(+ x (aget p1 z))
(+ y (aget p2 z)))))))))
Runs decently-quickly:
(let [s (slurp "02.txt")]
(criterium.core/quick-bench (day2 s)))
; Evaluation count : 9996 in 6 samples of 1666 calls.
; Execution time mean : 60.479461 µs
; Execution time std-deviation : 302.265610 ns
; Execution time lower quantile : 60.114543 µs ( 2.5%)
; Execution time upper quantile : 60.909793 µs (97.5%)
#2022-12-0214:00tschadyhttps://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d02.clj#2022-12-0214:10genmeblogMostly static lookups... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day02.clj#2022-12-0214:31StuartDictionary for the lookup of what beats what, invert it to get the hand to play for part 2
https://github.com/stuartstein777/clj-advent-of-code/blob/master/src/stuartstein777/2022/day2.clj#2022-12-0214:32StuartI parsed the file into "rock" "paper" "scissors" because "A", "B", "C", "X", "Y", "Z" was confusing me.#2022-12-0214:33pwojnowskiIsn't this a link to a private repository?#2022-12-0214:34Benjaminit's 404 for us#2022-12-0214:34Stuartyeah, shit was private. I had no idea. SHould be public now 🙂#2022-12-0215:46babardohttps://github.com/v-garcia/aoc_2022/blob/main/day2.clj
with rock paper scissors encoded as 0
1
2
#2022-12-0217:27Luis Santoshttps://github.com/luissantos/aoc/blob/main/src/luissantos/aoc_2022.clj
(defn round-score [round]
(case round
[:rock :paper] (+ 0 1)
[:rock :scissors] (+ 6 1)
[:paper :rock] (+ 6 2)
[:paper :scissors] (+ 0 2)
[:scissors :rock] (+ 0 3)
[:scissors :paper] (+ 6 3)
[:rock :rock] (+ 3 1)
[:paper :paper] (+ 3 2)
[:scissors :scissors] (+ 3 3)))
(defn pick-correct-hand [round]
(case round
[:x :paper] [:rock :paper]
[:x :rock] [:scissors :rock]
[:x :scissors] [:paper :scissors]
[:y :paper] [:paper :paper]
[:y :rock] [:rock :rock]
[:y :scissors] [:scissors :scissors]
[:z :paper] [:scissors :paper]
[:z :rock] [:paper :rock]
[:z :scissors] [:rock :scissors]))
(defn day2-part2 []
(let [hands {\A :rock \B :paper \C :scissors \X :x \Y :y \Z :z}]
(->> (string/split-lines (slurp "input/day-2-input-1.txt"))
(map #(string/replace % " " ""))
(map #(map hands %))
(map reverse)
(map pick-correct-hand)
(map round-score)
(reduce +))))
#2022-12-0520:26dogenpunkDay 2: https://github.com/dogenpunk/advent-of-code/blob/main/src/aoc22/day02.cljc#2022-12-0808:56mbjarland(ns day-02)
;;A-rock, B-paper, C-scissors, X-rock, Y-paper, Z-scissors
(def score-1 {\A {\X 4 \Y 8 \Z 3}
\B {\X 1 \Y 5 \Z 9}
\C {\X 7 \Y 2 \Z 6}})
;;X-loss, Y-draw, Z-win
(def score-2 {\A {\X 3 \Y 4 \Z 8}
\B {\X 1 \Y 5 \Z 9}
\C {\X 2 \Y 6 \Z 7}})
(defn input [score]
(for [[a _ b] (re-seq #".+" (slurp "../day_02.data"))]
((score a) b)))
(defn solution-1 []
(reduce + (input score-1)))
(defn solution-2 []
(reduce + (input score-2)))
#2022-12-0809:00mbjarlandA bit late to the game : / day job intervened, let's see if I can catch up#2022-12-0210:09borkdudeDear Advent of Coders!
The babashka-advent-of-code-template now lets you download input automatically when you set your AOC_SESSION
environment variable:
https://github.com/borkdude/advent-of-babashka-template#downloading-input
Also you can run the code on Github Codespaces now (if you just want to try it out)!
https://github.com/borkdude/advent-of-babashka-template#github-codespaces#2022-12-0220:28arnoutNice idea, this automatic download of the input. I also applied it to my AoC project. #2022-12-0212:30raymcdermottFYI I am doing the challenges using scittle
#2022-12-0212:30raymcdermottI'm improving the visuals as I go along and ideas are welcome#2022-12-0213:16pezWhy not use Joyride for Advent of Code this year around? A first version of a Use repository. It's full of typos and things I haven't thought about. I will improve on it! joyride https://github.com/PEZ/joyride-aoc-2022#2022-12-0214:08StuartWhy is map-invert
in the set
namespace ? :thinking_face:#2022-12-0214:10tschadyCouple of answers follow. https://clojurians.slack.com/archives/C053AK3F9/p1639157027128700#2022-12-0214:25noogaI'll put it in let-go's core I think#2022-12-0215:33Alex AlemiAlso, fun fact: (set/map-invert who-beats-who) = (comp who-beats-who who-beats-who)
#2022-12-0217:02nooga@U02P133R2SZ good one! didn't occur to me#2022-12-0217:02noogait's basically shifting the table#2022-12-0214:09borkdude@qmstuart because maps can be regarded as sets of key-value pairs? it beats me :)#2022-12-0214:26Ben LiebermanAll these beautiful, explicit solutions and I'm just playing code golf 😅#2022-12-0214:27noogaplease share 🙂#2022-12-0214:49Ben Lieberman(def pt-one-points [4 8 3 1 5 9 7 2 6])
(def pt-two-points [3 4 8 1 5 9 2 6 7])
(def outcomes [["A" "X"] ["A" "Y"] ["A" "Z"]
["B" "X"] ["B" "Y"] ["B" "Z"]
["C" "X"] ["C" "Y"] ["C" "Z"]])
(def pt-one-scores (zipmap outcomes pt-one-points))
(def pt-two-scores (zipmap outcomes pt-two-points))
(with-open [rdr (-> "public/puzzle_inputs/day_two.txt"
io/resource
io/reader)]
(->> (line-seq rdr)
(transduce (map (comp #(get pt-one-scores %)
#(string/split % #"\s"))) + 0)))
#2022-12-0215:24raymcdermottnice#2022-12-0215:28Apple;; 202202
(let [rule1 {["A" "Z"] (+ 0 3), ["A" "X"] (+ 3 1), ["A" "Y"] (+ 6 2)
["B" "X"] (+ 0 1), ["B" "Y"] (+ 3 2), ["B" "Z"] (+ 6 3)
["C" "Y"] (+ 0 2), ["C" "Z"] (+ 3 3), ["C" "X"] (+ 6 1)}
rule2 {["A" "X"] (+ 0 3), ["A" "Y"] (+ 3 1), ["A" "Z"] (+ 6 2)
["B" "X"] (+ 0 1), ["B" "Y"] (+ 3 2), ["B" "Z"] (+ 6 3)
["C" "X"] (+ 0 2), ["C" "Y"] (+ 3 3), ["C" "Z"] (+ 6 1)}
d (->> (slurp "src/y2022/input202202")
(re-seq #"\w")
(partition 2))]
(map #(->> d (transduce (map %) +)) [rule1 rule2]))
;; (12772 11618)
#2022-12-0219:37Piotr Kaznowski(Still learning, so probably my solution is not super idiomatic?)
(def rules
[[2 0 1] ;; R = 0 [who-loses who-draws who-wins]
[0 1 2] ;; P = 1
[1 2 0]]) ;; S = 2
(defn parse [line]
(let [[a b] (re-seq #"\w" line)]
[(index-of "ABC" a) (index-of "XYZ" b)]))
(defn result [[a b] part]
(if (= part 1)
(+ (inc b) (* 3 (.indexOf (rules a) b)))
(+ (inc ((rules a) b)) (* 3 b))))
(defn -main [day]
(let [input (map parse (file->lines day))
game (fn [p] (apply + (map #(result % p) input)))]
{:part1 (game 1) :part2 (game 2)}))
#2022-12-0221:39Phil Shapiro@UUAKPEMJ9 that looks good to me. One minor improvement, you can use destructuring to grab the chars from the line and avoid re-seq
:
(defn parse [[a _ b]]
[(index-of "ABC" a) (index-of "XYZ" b)])
#2022-12-0222:39Piotr KaznowskiOf course! Thanks for the hint, @UQL85PT29.#2022-12-0215:20raymcdermottmodest improvements to the UI#2022-12-0221:00zamanskyHey everybody. I'm a CS teacher by day and Clojure hobbyist off hours. I wrote up a piece on days 1 and 2 wearing my teacher hat. The post isn't clojure specific but the embedded videos is a Clojure walkthrough of both days. No claims of being great solutions but wanted to share.
Days 1 and 2 of #AdventOfCode from a teacher's persepctive:
https://cestlaz.github.io/post/advent-2022-day01-01/#2022-12-0714:30Andrew MeinersI actually stumbled on your video on YouTube before I saw this post. Really liked the way you talked through your thought process when finding the solution. Great work!#2022-12-0716:44zamanskyThanks - wish I had time to make more.#2022-12-0221:18pezWe recorded a demo of solving day 1 using Joyride at the office today. It’s in post processing. I think it will be pretty nice content when we’re done with it. Extra bonus is that my colleague made an ”answer” using Rust and an application he has written, that can run Rust code. I think I’ll attach that as an appendix. We’ll see. #2022-12-0221:21Ben LiebermanThe rust version as an appendix would be cool! :face_with_cowboy_hat: but I just thinking about AoC and Joyride on my walk so looking forward either way!#2022-12-0221:37borkdudeawesome :)#2022-12-0222:51noogaman, I like it when I paste a giant fn from clojure.core and it just works#2022-12-0305:23normanDay 3 - solutions#2022-12-0305:23normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day03/main.clj#2022-12-0305:26Alex Alemihttps://github.com/alexalemi/advent/blob/main/2022/clojure/p03.clj#2022-12-0305:29normanOh - intersection can be passed more than two sets - how did I miss that. 🙂#2022-12-0305:35Ben Lieberman(ns slothrop.day-three.rucksacks
(:require [ :as io]
[clojure.string :as string]
[clojure.set :refer [intersection]]))
(def lower (zipmap (map char (range 97 123)) (range 1 27)))
(def upper (zipmap (map char (range 65 91)) (range 27 53)))
(with-open [rdr (-> "public/puzzle_inputs/day_three.txt"
io/resource
io/reader)]
(->> rdr
line-seq
(partition 3) ; pt 2
#_(map #(split-at (/ (count %) 2) %)) ; pt 1
(map (fn [[s1 s2 s3]] (intersection (set s1) (set s2) (set s3))))
(map #(if (Character/isUpperCase (first %))
(get upper (first %))
(get lower (first %))))
(apply +)))
Continuing to phone it in on readability...#2022-12-0306:19R.A. Porterhttps://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day03.html#2022-12-0307:19Mikko Koskihttps://github.com/rap1ds/advent-of-code-2022/blob/main/src/day3.clj#2022-12-0307:28Martin Půda(ns aoc2022.day03
(:require [clojure.string :as s]
[clojure.set :as set])
(:gen-class))
(def data (-> (slurp "resources/input03.txt")
(s/split-lines)))
(defn priority [^Character c]
(- (int c) (if (Character/isLowerCase c) 96 38)))
(defn common-char-with-rating [group]
(->> (map set group)
(apply set/intersection)
first
priority))
(defn line-get-common-char [line]
(let [c (count line)]
(common-char-with-rating (split-at (/ c 2) line))))
(defn part1 [data]
(transduce (map line-get-common-char)
+
data))
(defn part2 [data]
(transduce (map common-char-with-rating)
+
(partition 3 data)))
#2022-12-0307:33jaihindhreddyNothing very interesting.
(ns com.jaihindhreddy.advent22
(:require [clojure.string :as str]
[clojure.set :as set]))
(defn day3 [fs]
(let [priority (fn [c]
(let [x (int c)]
(- x (if (> x 96) 96 38))))
lines (str/split-lines fs)]
[(transduce
(map #(let [n (quot (count %) 2)]
(priority
(first
(set/intersection
(set (subs % 0 n))
(set (subs % n)))))))
+ 0 lines)
(transduce
(comp (partition-all 3)
(map #(priority (first (apply set/intersection (map set %))))))
+ 0 lines)]))
#2022-12-0307:34Andrew ByalaMy https://github.com/abyala/advent-2022-clojure/blob/main/docs/day03.md with linked https://github.com/abyala/advent-2022-clojure/blob/main/src/advent_2022_clojure/day03.clj.#2022-12-0307:42Luis Santos(defn char-range [start end]
(map char (range (int start) (inc (int end)))))
(def priorities
(zipmap
(concat (char-range \a \z) (char-range \A \Z))
(range 1 53)))
(defn parse-rucksack [rs]
(let [rs (seq rs)]
(split-at (/ (count rs) 2) rs)))
(defn item-priority [col]
(->> col
(map set)
(apply clojure.set/intersection)
(first)
(priorities)))
(defn day3-part1 []
(->> (string/split-lines (slurp "input/day-3-input-1.txt"))
(map parse-rucksack)
(map item-priority)
(reduce +)))
(defn day3-part2 []
(->> (string/split-lines (slurp "input/day-3-input-1.txt"))
(partition 3)
(map seq)
(map item-priority)
(reduce +)))
#2022-12-0308:23mchampine;; part1
(defn crr26 [c] (map char (range (int c) (+ (int c) 26))))
(def priorities (zipmap (concat (crr26 \a) (crr26 \A))
(range 1 53)))
(defn solvgrp [grp]
(->> (map set grp)
(apply set/intersection)
first
(get priorities)))
(->> (map #(split-at (/ (count %) 2) %) input)
(map solvgrp)
(apply +)) ;; 7850
;; part 2
(apply + (map solvgrp (partition 3 input))) ;; 2581
#2022-12-0309:26pieterbreedNice solutions all. Haven't seen anybody use str/index-of
for item-type score fn:
(fn [it]
(-> "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
(str/index-of it)
inc))
#2022-12-0310:17Piotr KaznowskiI'm using it (without inc
):
(defn pts [it]
(->> it (map set) (apply intersection) first
(index-of ":abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")))
(defn -main [day]
(let [input (file->lines day)]
{:part1 (transduce (map #(pts (partition (/ (count %) 2) %))) + input)
:part2 (transduce (map pts) + (partition 3 input))}))
#2022-12-0411:40peterhHere is mine, now in the https://github.clerk.garden: https://github.clerk.garden/formsandlines/aoc2022-clojure/commit/1dd601cb5f5d590162e9cb3ab62c68c78e83f3a6/src/advent_of_clerk/day_03.html
Pretty much what everyone did, I guess, using intersection on sets. I converted the type mathematically on the char code, although not as sophisticated as the hack by tschadys coworker. :)#2022-12-0520:27dogenpunkDay 3: https://github.com/dogenpunk/advent-of-code/blob/main/src/aoc22/day03.cljc#2022-12-0809:45mbjarland(ns day-03)
(def priority
(merge (zipmap "abcdefghijklmnopqrstuvwxyz" (range 1 27))
(zipmap "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (range 27 53))))
(def lines (re-seq #".+" (slurp "../day_03.data")))
(defn input-1 []
(for [line lines
:let [c (count line)
h (/ c 2)
[a b] [(subs line 0 h) (subs line h c)]]]
(some (set a) b)))
(defn input-2 []
(for [[a b c] (partition 3 lines)]
(some (set (filter (set a) b)) c)))
(defn solution-1 []
(reduce + (map priority (input-1))))
(defn solution-2 []
(reduce + (map priority (input-2))))
#2022-12-2216:47dumratVery late.
I tend to like these long pipelines of transformations instead of breaking them up. Inscrutable but fun. Everyone seems to have had the same idea though.
(ns aoc2022.day3
(:require [ :refer [resource]]
[clojure.string :as str]
[clojure.set :refer [intersection]]))
(defn data []
(->> (resource "inputs/day3.txt")
(slurp)
(str/split-lines)))
(defn part1 []
(->> (data)
(map #(vector (into #{} (subs % 0 (/ (count %) 2)))
(into #{} (subs % (/ (count %) 2) (count %)))))
(map (partial apply intersection))
(map (comp int first))
(map #(if (> % 96) (- % 96) (- % 38)))
(reduce +)))
(defn part2 []
(->> (data)
(map (partial into #{}))
(partition 3)
(map (partial apply intersection))
(map (comp int first))
(map #(if (> % 96) (- % 96) (- % 38)))
(reduce +)))
#2022-12-0306:00Alex AlemiWild, part 1 was "solved" in 10 seconds: https://twitter.com/ostwilkens/status/1598458146187628544#2022-12-0307:08JDay 3 generated by chatGPT. Many errors in Clojure code:
(defn priority [ch]
(let [offset (if (Character/isLowerCase ch) 96 64)]
(- (char ch) offset)))
(defn solve [input]
(let [counts (frequencies input)]
(first (sort-by (comp second >) counts))))
(def input ["vJrwpWtwJgWrhcsFMMfFFhFp"
"jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL"
"PmmdzqPrVvPwwTWBwg"
"wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn"
"ttgJtRGJQctTZtZT"
"CrZsJsPPZsGzwwsLwLmpwMDw"])
(let [common-item (solve input)]
(println "The common item is" common-item)
(println "Its priority is" (priority common-item))
(println "The sum of the priorities is" (* (count input) (priority common-item))))
#2022-12-0514:06erwinrooijakkers@UHZPYLPU1 what question do you ask to chatGPT?#2022-12-0514:08JThe all aoc day3 state. I only add in Clojure
at the end of the part1 question#2022-12-0311:22tschadyDid I miss the memo about Advent-of-Transduce? 🎅#2022-12-0400:31pezA demo of using Clojure to solve Advent of Code problems in your editor, using VS Code + #joyride. https://www.youtube.com/watch?v=0rJvOtbJDyI#2022-12-0400:35pezAnd the starter template project is a bit updated as well: https://github.com/PEZ/joyride-aoc-2022#2022-12-0405:18normanDay 4 - solutions#2022-12-0405:18normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day04/main.clj#2022-12-0405:19tylerwhttps://github.com/tylerw/advent-of-code-2022/blob/master/src/aoc2022/day04.cljc#2022-12-0405:22Alex Alemihttps://github.com/alexalemi/advent/blob/main/2022/clojure/p04.clj#2022-12-0405:26Apple;; 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)
#2022-12-0406:01Alekshttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_04.clj#2022-12-0406:16chuckleheadhttps://casselc.github.io/aoc22/src/advent_of_code/day_04.html#2022-12-0406:18mchampine(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
#2022-12-0406:31R.A. Porterhttps://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day04.html#2022-12-0407:17Andrew Byalahttps://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!#2022-12-0407:21Mikko Koskihttps://github.com/rap1ds/advent-of-code-2022/blob/main/src/day4.clj#2022-12-0407:26Jan Tore Stolsvikhttps://github.com/jantorestolsvik/advent-of-code-2022/blob/main/src/day04.clj#2022-12-0407:46jaihindhreddyAfter 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))))))))))
#2022-12-0407:52Piotr Kaznowski(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?)}))
#2022-12-0408:09Piotr KaznowskiOh, filter true?
is totally redundant here!#2022-12-0409:49sebastianI 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.#2022-12-0410:13genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day04.clj#2022-12-0410:19Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day4.clj#2022-12-0410:42pwojnowskihttps://github.com/pwojnowski/advent-of-code/blob/master/src/aoc/aoc2022.clj#L77#2022-12-0410:49pwojnowskiI'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.#2022-12-0410:50sebastianOf cause I’m not talking about performance. I was talking about what kind of approach comes more naturally. #2022-12-0411:00CarnunMPhmm, 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!#2022-12-0411:01CarnunMP(ooh, weird how the preview renders <=
and >=
as =
🙃)#2022-12-0411:23Thierryhttps://github.com/LouDnl/advent-of-code-2022/blob/master/src/clj/advent_of_code_2022/days/day_four.clj#2022-12-0411:31tschadysame 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#2022-12-0411:35Luis Santos(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))}))
#2022-12-0412:02ThierryNice, very short and clean#2022-12-0412:04Benjaminseq
instead of not empty
#2022-12-0412:05ThierryOr not-empty
https://clojuredocs.org/clojure.core/not-empty#2022-12-0412:14Luis Santos@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?#2022-12-0412:17ThierryNot at computer atm, what about (filter some? %)#2022-12-0412:18Luis SantosI would have to change my subset? function to return nil. It would be change for change. I don't see an immediate benefit.#2022-12-0412:44ThierryGood point. Doesnt seq yield the same result?
Maybe (some? (not-empty#2022-12-0412:45ThierryMore then one way to reach Rome with Clojure (or any other language for that matter) :rolling_on_the_floor_laughing:#2022-12-0413:27zamanskyhttps://github.com/zamansky/advent2022/blob/main/src/day04.clj#2022-12-0414:08StuartThis 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#2022-12-0414:11StuartI too considered sets, that does feel more natural to me, but then thought it was wasteful to generate all thsoe numbers#2022-12-0414:11Luis SantosThis 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)))
#2022-12-0414:13Thierry@UK00KCK6D Using not=
(defn intersection? [[a b]]
(not= #{} (set/intersection a b)))
#2022-12-0414:14Thierry@U013YN3T4DA I started out with sets aswell but ended up using a for loop on the sets with data/diff#2022-12-0414:16sebastianA lot of good stuff here. #2022-12-0416:26Michael Ducharmhttps://github.com/mducharm/advent_of_code_2022/blob/main/src/advent_of_code/day_04.clj#2022-12-0417:34Andrew ByalaI 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)))
#2022-12-0418:10chuckleheadseems like that would also return true
for partial overlaps, e.g. (overlaps? [1 3 2 4])
?#2022-12-0418:24bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day4/sol.clj#2022-12-0419:07wevremhttps://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_04_cleanup.clj#2022-12-0419:10Caseyhttps://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#2022-12-0420:38robertfwthe 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)))))
#2022-12-0421:25peterhHere 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 😕).#2022-12-0422:31griersonhttps://github.com/grierson/katas/blob/master/advent-of-code/src/aoc2022/04.clj#2022-12-0500:08noogahttps://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?))
#2022-12-0500:22nooga(my >= and =< only take 2 args 😫)#2022-12-0520:27dogenpunkDay 5: https://github.com/dogenpunk/advent-of-code/blob/main/src/aoc22/day04.cljc#2022-12-0810:31mbjarland(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))))
#2022-12-2217:18dumrat(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?))
#2022-12-0405:46AppleThese 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
#2022-12-0405:58jaihindhreddyMine were 5m6s and 6m21s for the two stars resp.
It took me ~2m just to read the question xDD.#2022-12-0410:21pwojnowskiI wonder how it is possible to submit the solution in 16s...#2022-12-0411:24ThierrySeems almost impossible to do this in 16 seconds, it takes longer to read the questions#2022-12-0411:27ThierryToo 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.#2022-12-0411:54Luis SantosThat's not what I'm seeing.#2022-12-0412:08jaihindhreddy@UK00KCK6D thats for both stars. OP is about part 1#2022-12-0412:10ThierryBut still, 16 seconds?#2022-12-0412:13jaihindhreddyAssuming 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.#2022-12-0412:17jaihindhreddyWith 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.#2022-12-0413:25tschadyRuby 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#2022-12-0413:27Luis SantosI checked previous years and there were similar speeds for the 2 rounds.#2022-12-0413:28pez> it doesn't seem too outrageous this way
It seems too outrageous to me still. 😃#2022-12-0413:31jaihindhreddyIndeed @U1Z392WMQ, the leader's GitHub https://github.com/max-sixty/aoc-gpt.#2022-12-0415:40AppleExactly. HN: https://news.ycombinator.com/item?id=33850999#2022-12-0419:22CaseyThere are some nice writeups from past years from folks who placed highly in the leaderboard#2022-12-0419:23Casey• https://gist.github.com/mcpower/87427528b9ba5cac6f0c679370789661
• https://kevinyap.ca/2019/12/going-fast-in-advent-of-code/
• https://blog.vero.site/post/advent-leaderboard#2022-12-0406:58pyrmont@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?#2022-12-0407:22R.A. PorterYep. 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.#2022-12-0407:25R.A. PorterIt'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.#2022-12-0408:00pyrmontThat'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.#2022-12-0409:52sebastianI 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.#2022-12-0413:16raymcdermottday 2#2022-12-0416:40raymcdermottI wanted to make the visual more pronounced per part.#2022-12-0416:45borkdudeDid you manage to upload this to github pages yet?#2022-12-0417:12raymcdermottno, 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.#2022-12-0416:41raymcdermottok, on to day 3 :)#2022-12-0416:42raymcdermottthanks 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:#2022-12-0418:09Luis SantosAsked 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)
#2022-12-0418:24bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day4/sol.clj#2022-12-0418:31bhaumanHey 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))))
#2022-12-0422:02raymcdermottin 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 + %)))
#2022-12-0422:03raymcdermottbut this works perfectly
(->> @data
str/split-lines
(map edn/read-string)
(partition-by nil?)
(keep #(reduce + %)))
#2022-12-0422:03raymcdermottThanks for the tip!!#2022-12-0418:34bhaumanFirst 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]
#2022-12-0418:35russmatneyThis 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#2022-12-0418:36bhaumanYeah I love in general how easy it is to get data in#2022-12-0419:28pezI split the lines and map read-string over them.#2022-12-0418:35bhaumanYou don’t need to parseInt
or any of these thing just use read-string
for just about everything#2022-12-0418:40bhaumanI guess I should just be safe and mention the disclaimer that you shouldn’t use clojure.core/read-string
in production apps …#2022-12-0418:42ThierryI used a macro for the first 3 days
(defmacro adventreader
[resource]
`(let [data# (with-open
[rdr# (io/reader ~resource)]
(doall (line-seq rdr#)))]
data#))
#2022-12-0418:42Thierryand this for today
(string/split-lines
(slurp
(io/input-stream data))
#2022-12-0418:52borkdude@bhauman why not use clojure.edn/read-string
, did you need to parse programs? (I haven't looked at the input)#2022-12-0419:20bhauman@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.#2022-12-0419:21bhauman@thierry572 read-string
parses the input returning integers, lists, vectors etc thus you can skip the parsing step#2022-12-0419:22ThierryI 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.#2022-12-0419:26tschadyI 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#2022-12-0419:26tschadycc @borkdude @U1EP3BZ3Q#2022-12-0419:30borkdudeAwesome, feel free to send a PR to advent-of-babashka under my github name and add the link to "external resources"#2022-12-0422:01Piotr KaznowskiI'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?#2022-12-0422:02borkdude@UUAKPEMJ9 Which OS is this?#2022-12-0422:02borkdudeand what architecture?#2022-12-0422:05Piotr Kaznowski@borkdude Arch Linux, x86_64#2022-12-0422:08borkdudeldd /home/piotr/.local/share/.babashka/pods/repository/retrogradeorbit/bootleg/0.1.9/linux/x86_64/bootleg
?#2022-12-0422:08borkdudecc @U1QQJJK89 - might be good to provide a fully static musl compiled binary for bootleg#2022-12-0422:09Piotr Kaznowski$ 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
#2022-12-0422:10borkdudeaha, so the file doesn't exist at all?#2022-12-0422:10Piotr KaznowskiYes, as I said above:
> Threre's no bootleg
executable at the location, only manifest.edn
file. Before it crashes, it prints:#2022-12-0422:11borkdudethen it's not the issue I suspected it to be#2022-12-0422:12borkdudeThis 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"}
#2022-12-0422:13borkdudeI'll also try on ubuntu...#2022-12-0422:14borkdudecan 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\")"
#2022-12-0422:15Piotr KaznowskiHmm, that worked with /tmp
!#2022-12-0422:15borkdudeOn ubuntu it also worked fine for me. Perhaps you could try to wipe the pods directory and try again#2022-12-0422:17Piotr KaznowskiIt reproduces the erratic behavior.#2022-12-0422:18borkdudecould it be a file system permission thing?#2022-12-0422:19borkdudeyou could try to debug locally with https://github.com/babashka/pods - the load call should also work on the JVM#2022-12-0422:21Piotr KaznowskiOK, will try, thanks.#2022-12-0422:35Piotr Kaznowski(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)#2022-12-0422:36Piotr Kaznowskihttps://github.com/caseneuve/aoc2022#2022-12-0505:44normanDay 5 - Solutions#2022-12-0505:44normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day05/main.clj#2022-12-0505:56mchampine;; Part 1
(def istacks ["VCDRZGBW" "GWFCBSTV" "CBSNW"
"QGMNJVCP" "TSLFDHB" "JVTWMN"
"PFLCSTG" "BDZ" "MNZW"])
(defn move [rfn stks [n from to]]
(let [from (dec from) to (dec to)
lnff (take-last n (get stks from))]
(-> (assoc stks to (apply str (get stks to) (rfn lnff)))
(assoc from (apply str (drop-last n (get stks from)))))))
(defn reducer [rf stk inp]
(->> (reduce (partial move rf) stk inp)
(map last)
(apply str)))
((partial reducer reverse) istacks input) ;; "TBVFVDZPN"
;; Part2
((partial reducer identity) istacks input) ;; "VLCWHTDSZ"
#2022-12-0506:18Apple(ns aoc.y2022
(:require [clojure.string :as cstr]))
;; 202205
(let [[d1 d2] (-> (slurp "resources/202205") (cstr/split #"\n\n"))
procedures (->> d2 (re-seq #"\d+") (map parse-long) (partition 3))
n-stack (count (re-seq #"\d+" d1))
stacks (->> (re-seq #"\w| " d1)
(partition n-stack)
(apply mapv #(cstr/replace (cstr/join %&) " " "")))
f #(->> (reduce (fn [stacks [quantity from to]]
(let [froms (get stacks (dec from))
s (subs froms 0 quantity)
froms' (subs froms quantity)
tos' (str (% s) (get stacks (dec to)))]
(-> stacks
(assoc (dec from) froms')
(assoc (dec to) tos'))))
stacks
procedures)
(map first)
cstr/join)]
(map f [cstr/reverse identity]))
;; ("JDTMRWCQJ" "VHJDDCWRD")
#2022-12-0506:35tylerwhttps://github.com/tylerw/advent-of-code-2022/blob/master/src/aoc2022/day05.cljc#2022-12-0506:35tylerw(Could use some cleanup 😄)#2022-12-0507:09jumarhttps://github.com/jumarko/clojure-experiments/pull/43/files#diff-6859f69e3399c848e3bc1b6b2744ee93fc9cf4b4d49957a2e337f95835804e8cR147-R162#2022-12-0508:27motformLet's see the input get even more strange and specific tomorrow https://github.com/motform/advent-of-clojure/blob/master/src/advent_of_clojure/2022/05.clj#2022-12-0508:57wevremhttps://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_05_cranes.clj#2022-12-0509:20genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day05.clj#2022-12-0509:34genmeblogTIL: re-seq
#2022-12-0510:17nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2022/src/day05.clj#2022-12-0510:18Caseyhttps://github.com/Ramblurr/advent-of-code-2022/blob/main/src/aoc/day05.clj#L10-L77
Parsing the input on this one was pretty fun! I used read-string
like some others have been talking about the past few days.#2022-12-0510:35babardohttps://github.com/v-garcia/aoc_2022/blob/main/day5.clj#2022-12-0511:55tschadyhttps://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d05.clj#2022-12-0511:57Felipehttps://github.com/FelipeCortez/advent-of-code/blob/master/2022/05.clj#2022-12-0513:32Mikko Koskihttps://github.com/rap1ds/advent-of-code-2022
TIL: (list* xs)
is NOT the same as (apply list xs)
. I tried to use list*
to create my stacks with poor results:
;; works
(apply list "ABCD") ;; #=> (\A \B \C \D)
(pop (apply list "ABCD")) ;; #=> (\B \C \D)
(type (apply list "ABCD")) ;; #=> clojure.lang.PersistentList
;; doesn't work
(list* "ABCD") ;; #=> (\A \B \C \D)
(pop (list* "ABCD")) ;; #=> ERROR!
(type (list* "ABCD")) ;; #=> clojure.lang.StringSeq
list*
's https://clojuredocs.org/clojure.core/list* explains it pretty clearly why it's like this#2022-12-0513:43potetmhttps://github.com/potetm/advent-of-code/blob/master/src/advent_2022/day_5.clj#2022-12-0513:52potetmNever would have occurred to me to reverse the inputs and re-run the same engine.#2022-12-0514:12erwinrooijakkers@U076FM90B isn’t (update from #(drop move %))
the same as (update from drop move)
?#2022-12-0514:13potetm@U2PGHFU5U the latter will do (update from #(drop % move))
#2022-12-0514:13erwinrooijakkersah thanks you’re right 🙂#2022-12-0514:15nbardiukyes, unfortunately update
, like thread first
macro, is optimized for single value, not a collection#2022-12-0514:21noogahttps://github.com/nooga/aoc2022/blob/master/day5.lg
(ns day5)
(def data (->> "input/day5.txt" slurp lines (split-with (complement empty?))))
(def stacks (->> data first butlast
(map #(str-replace % #"( |\\[)([A-Z ])(\\]| ) ?" "$2"))
(apply mapv list)
(mapv #(drop-while #{\space} %))))
(def instructions (->> data second rest
(map #(str-replace % #"\\w+ (\\d+)" "$1"))
(map (comp #(mapv parse-long %) #(split % " ")))))
(defn solve [pickup]
(->> instructions
(reduce (fn [a [n f t]]
(let [f (dec f) t (dec t)]
(-> a (update t into (pickup (take n (a f))))
(update f #(drop n %)))))
stacks)
(map first)
(apply str)))
(println "1:" (solve identity))
(println "2:" (solve reverse))
I had a chance to add Regex to let-go core thanks to this ;)#2022-12-0514:22Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day5.clj barely got my stars#2022-12-0515:00StuartOh boy, I am NOT proud of my solution today#2022-12-0515:05StuartI struggled with the parsing. So I filled in the empty spaces with -
, then removed them later after I had made a map of location and boxes. I thought this would make it easy since I could then just split on the boxes...
(apply map vector)
to rotate the rows into columns, then zipmap
with (range)
to get a map of the stack.
https://github.com/stuartstein777/clj-advent-of-code/blob/master/src/stuartstein777/2022/day5.clj
At least part 2 turned out easy, I just had add in a reverse
call.#2022-12-0515:40R.A. PorterI could/should consider rewriting my parsing code. I won't. https://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day05.html#2022-12-0516:56bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day5/sol.clj#2022-12-0519:50Vincent Olesenhttps://github.com/volesen/aoc2022/blob/main/day5/day5.clj#2022-12-0519:54robertfwI am not proud of this code 😅 make it work, make it good, make it fast, right? well, this works...#2022-12-0519:56noogaThat's the spirit! I always code mine with utter disregard for performance and style by putting down first though that I had and sticking to it. Then I go here to appreciate all the thought out solutions. 😆#2022-12-0520:28dogenpunkDay 5: https://github.com/dogenpunk/advent-of-code/blob/main/src/aoc22/day05.cljc#2022-12-0520:45zamanskyHere's my day 5:
https://github.com/zamansky/advent2022/blob/main/src/day05.clj
Was stupid with my regex for a while and also for not paying attention to vectors vs lists 🙂#2022-12-0521:11Luis SantosTook me a while to solve this:
(defn transpose [xs]
(apply map list xs))
(defn build-stacks [i]
(->> (string/split-lines i)
(map #(re-seq #"\[\w\]| |[0-9]" %))
(take-while (complement nil?))
(transpose)
(map reverse)
(map #(remove string/blank? %))
(reduce #(assoc %1 (first %2) (rest %2)) (sorted-map))))
(defn parse-steps [i]
(->> (string/split-lines i)
(map #(re-seq #"move (\d*) from (\d) to (\d)" %))
(filter (complement nil?))
(map (comp rest first))
(map #(cons (parse-long (first %)) (rest %)))))
(defn apply-step [stacks [n a b]]
(let [sa (stacks a)
sb (stacks b)]
(-> stacks
(assoc a (drop-last n sa))
(assoc b (concat sb (take-last n sa))))))
(let [data (slurp "input/day-5-input.txt")
stacks (build-stacks data)]
(->> (parse-steps data)
(reduce apply-step stacks)
(vals)
(map (comp second last))
(reduce str)))
#2022-12-0521:29peterhNot the most elegant solution, but I learned things today! https://github.clerk.garden/formsandlines/aoc2022-clojure/commit/d32c6ea4a4c8b1d7daf8803e2ce5e91e3154f6b3/src/advent_of_clerk/day_05.html#2022-12-0521:43CarnunMPlittle late to the game today, but it https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d5.clj :))
one thing I like about the stacks
parsing here is this line:
(defn parse [input]
(let [{stacks false, steps true} (group-by #(str/starts-with? % "move") input)]
{:stacks (->> (take (- (count stacks) 2) stacks) ; ignore numbers and blank line
(map #(partition 4 4 (repeat \space) %))
(apply (partial map list)) ; <-- HERE
(mapv #(keep (partial some uppercase-letter?) %)))
:steps (map #(let [[move from to] (re-seq #"\d+" %)]
[(parse-long move)
;; 0-based indexing of the stacks vector
(dec (parse-long from))
(dec (parse-long to))]) steps)}))
Effectively turns the (already somewhat parsed) lines sideways! Then just the non-crates need to be removed. :))#2022-12-0522:02Piotr Kaznowski(defn get-stacks [s]
(let [chars (re-seq #"\w| " s)
len (parse-long (last chars))]
(->> chars
(map #(re-matches #"\w" %))
(partition len)
butlast
(apply mapv vector)
(mapv #(remove nil? %)))))
(defn get-movements [m]
(->> m
(re-seq #"\d+")
(map parse-long)
(partition 3)))
(defn parse [s]
(-> s
(split #"\n\n")
((juxt (comp get-stacks first)
(comp get-movements second)))))
(defn reducer [[coll f] [amount from to]]
[(-> coll
(update (dec from) #(drop amount %))
(update (dec to) #(into % (f (take amount (coll (dec from)))))))
f])
(defn -main [day]
(let [[stacks movements] (parse (file->str day))]
(zipmap [:part1 :part2]
(->> [identity reverse]
(map #(reduce reducer [stacks %] movements))
(map #(->> % first (map first) join))))))
#2022-12-0523:23gaboReally struggled with the parsing 😓 and after playing at repl during part 2 I was happy that I noticed reversing or not the stacks when moving them was the only difference in between part 1 and 2
(ns me.galuque.aoc-2022.day-05
(:require [ :as io]
[clojure.string :as str]))
(set! *warn-on-reflection* true)
(set! *unchecked-math* :warn-on-boxed)
(def raw-input (slurp (io/resource "input/day_05.txt")))
(defn transpose
[m]
(apply mapv vector m))
(defn parse-stacks [raw-input]
(-> raw-input
(str/split #"\n\n")
(nth 0)
(str/split #"\n")
(->>
(butlast)
(map #(re-seq #" |[\w+]" %))
(transpose)
(mapv #(remove str/blank? %)))))
(defn parse-instructions [raw-input]
(-> raw-input
(str/split #"\n\n")
(nth 1)
(str/split-lines)
(->>
(map #(re-seq #"\d+" %))
(mapv (fn [[amount from to]]
{:amount (parse-long amount)
:from (dec ^long (parse-long from))
:to (dec ^long (parse-long to))})))))
(defn move [reverse? stacks {:keys [amount from to]}]
(let [reverse-fn (if reverse? reverse identity)
value (->> (nth stacks from)
(take amount)
(reverse-fn))
stack' (-> stacks
(update from (partial drop amount))
(update to (partial apply conj) value))]
stack'))
(defn top-rearrange [reverse? init-stack instructions]
(let [mv (partial move reverse?)]
(->> (reduce mv init-stack instructions)
(map first)
(str/join))))
(defn part-1 [raw-input]
(top-rearrange false
(parse-stacks raw-input)
(parse-instructions raw-input)))
(comment
(part-1 raw-input)
;; => "FRDSQRRCD"
)
(defn part-2 [raw-input]
(top-rearrange true
(parse-stacks raw-input)
(parse-instructions raw-input)))
(comment
(part-2 raw-input)
;; => "HRFTQVWNN"
)
#2022-12-0606:58Anssi Kittilästruggled with parsing the original structure, but after that it was simple#2022-12-0606:58Anssi Kittilähttps://github.com/Triviaali/AoC2022/blob/main/src/aoc2022/day05.clj#2022-12-0608:15pwojnowskiParsing the input became so involved: https://github.com/pwojnowski/advent-of-code/blob/master/src/aoc/aoc2022.clj#L102#2022-12-0611:20jaihindhreddyMine turned out pretty ugly. The parsing is really annoying on this one 😩:
(defn day5 [fs]
(let [[stk steps]
; parsing
(let [[s1 s2] (str/split fs #"\R\R")]
[(->> (pop (str/split-lines s1))
(mapv #(->> (partition-all 4 %)
(mapv (fn [[_ c _]]
(when-not (= c \space) c)))))
(apply mapv vector)
(mapv (comp vec #(take-while some? %) reverse)))
(->> (str/split-lines s2)
(mapv #(let [[n from to] (mapv parse-long (re-seq #"\d+" %))]
[n (dec from) (dec to)])))])
msg (fn [mover]
(->> (reduce mover stk steps)
(mapv peek)
(apply str)))]
[(msg (fn [stk [n from to]]
(-> (iterate #(let [x (peek (nth % from))]
(-> (update % from pop)
(update to conj x))) stk)
(nth n))))
(msg (fn [stk [n from to]]
(let [fr (nth stk from)
[fr' xs] (split-at (- (count fr) n) fr)]
(-> (update stk to into xs)
(assoc from (vec fr'))))))]))
#2022-12-0612:40pwojnowskiI wonder how the people (sic!) from the top of the leaderboard got that parsed that fast, but probably something really straigthforward...#2022-12-0612:41StuartGpt3#2022-12-0612:41pwojnowskiThats's why I wrote "people" 😉#2022-12-0612:42pwojnowskiWith gpt3 the advent became so depressing... 😭#2022-12-0612:43StuartYeah, I think a lot of us are going to have to change careers in next 10 years#2022-12-0612:43pwojnowskiThis is sad, but it appears so.#2022-12-0710:06ThierryFinally had the time to do day 5, I probably used a ridiculous way to solve it and there are probably quicker ways to solve it, but the end result is what matters 😉
https://github.com/LouDnl/advent-of-code-2022/blob/master/src/clj/advent_of_code_2022/days/day_five.clj#2022-12-0814:45mbjarland(ns aoc.day-05
(:require [clojure.string :refer [split join split-lines]]))
(defn initial-state [cs]
(->> (for [line (map vec (butlast (split-lines cs)))]
(map line (range 1 (count line) 4)))
(apply mapv vector)
(mapv #(remove #{\space} %))))
(defn operations [os]
(partition 3 (map parse-long (re-seq #"\d+" os))))
(defn solve [cfn]
(let [[is os] (split (slurp "../day_05.data") #"\n\n")]
(reduce (fn [a [n f t]]
(let [[s r] (split-at n (a (dec f)))]
(-> (assoc a (dec f) r)
(update (dec t) #(concat (cfn s) %)))))
(initial-state is)
(operations os))))
(defn solution-1 []
(join (map first (solve reverse))))
(defn solution-2 []
(join (map first (solve identity))))
#2022-12-0900:55leinfink@U4VDXB2TU That's so pretty! Learned a lot reading that.#2022-12-0909:41mbjarland@U04BA34MCDN thank you! Yes I’ve learnt a lot from other’s solutions here as well (@UP82LQR9N looking at you among others)#2022-12-2219:04dumrat(ns aoc2022.day5
(:require [ :refer [resource]]
[clojure.string :as str]))
(defn data []
(->> (resource "inputs/day5.txt")
(slurp)
(str/split-lines)))
(defn read-crate-line [line]
(->> (partition 4 4 [\space] line)
(map (comp flatten (partial partition-by #{\[ \]})))
(map (partial remove #{\[ \] \space}))))
(defn read-move-line [line]
(->> (re-find (re-matcher #"move (\d+) from (\d+) to (\d+)" line))
(drop 1)
(map parse-long)
(interleave [:amount :from :to])
(partition 2)
(map vec)
(vec)
(into {})))
(defn starting-state []
(let [raw (->> (data)
(partition-by str/blank?)
(remove #(= (count %) 1)))
crate-line-count (dec (count (first raw)))
crates (->> (first raw)
(take crate-line-count)
(map read-crate-line)
(map (partial map (fn [e] (if (empty? e) nil (first e)))))
;Transpose trick
(apply map vector)
(map reverse)
(mapv (partial keep identity))
(mapv vec))
moves (->> (second raw)
(mapv read-move-line))]
{:crates crates
:moves moves}))
(def rearrange-1 reverse)
(def rearrange-2 identity)
(defn move [{:keys [crates moves] :as state} rearrange-strat]
(tap> state)
(if (empty? moves)
state
(let [{:keys [amount to from]} (first moves)
to (dec to)
from (dec from)]
(recur {:crates (-> crates
(update to #(apply conj % (rearrange-strat (take-last amount (get crates from)))))
(update from #(vec (drop-last amount %))))
:moves (drop 1 moves)}
rearrange-strat))))
(defn solution [rearrange-strat]
(let [{crates :crates} (move (starting-state) rearrange-strat)]
(apply str (map last crates))))
(def part1 (partial solution rearrange-1))
(def part2 (partial solution rearrange-2))
#2022-12-2219:04dumratNot cute 😄#2022-12-0513:50potetmI just hopped back in after having been out of the Clojurians slack for a while. Gotta say, it's awesome to see what some of ya'll do in here.#2022-12-0513:51potetmSo many brilliant solutions.#2022-12-0516:48raymcdermottI added an explainer for day 3 (based on a random input of reasonable length) ... not sure if it's going to get too much going forward but wdyt?#2022-12-0516:55borkdudeIt's awesome but you gotta get this up on github pages or else it doesn't count @raymcdermott#2022-12-0517:09raymcdermotthttps://aoc-rmc.github.io/aoc22/#2022-12-0517:11borkdudeawesome!#2022-12-0516:57raymcdermotthaha - I know#2022-12-0516:58mkvlrmaybe try clerk.garden to publish your scittle stuff 🙃#2022-12-0520:17raymcdermottit's a great idea but I might be past that point this time around#2022-12-0520:46mkvlrmaybe next year#2022-12-0516:57bhaumanOK let’s talk parsing again#2022-12-0516:59bhaumanI put the columns into a separate file and then used emacs rectangle commands and a macro to reformat the file.
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day5/input-columns.txt#2022-12-0517:00bhaumanThen I did this:
(def columns
;; file prepared with emacs rectangle commands and a macro
(->> (str "[" (slurp "src/adv2022/day5/input-columns.txt") "]")
read-string
(partition-by integer?)
(remove (comp integer? first))
(mapv #(map first %))))
#2022-12-0517:02bhaumanThat left the commands in another file and I just used read-string
on the whole file again like above and filtered out the integers and partitioned by 3.
(def commands
(->> (str "[" (slurp "src/adv2022/day5/input.txt") "]")
read-string
(filter integer?)
(partition 3)))
#2022-12-0517:02bhaumanjust trying to drive home the super-power that is read-string
#2022-12-0517:15normanread-string
is such a dangerous function, that I don't let my brain even consider it 🙂#2022-12-0517:16bhaumanyeah but if you can’t use it when you’re fun hacking, when can you??😉#2022-12-0517:47bhaumanI love me some dangerous read-string
👹#2022-12-0519:04borkdude😂#2022-12-0519:06borkdudeI know y'all know this, but pretty good what it comes up with :-)#2022-12-0519:18bhaumanYeah you caused me to get a #chatgpt account the other day. It’s pretty insane.#2022-12-0519:19bhaumanAND just quell the controversy I’m going to use clojure.end/read-string even when I’m hacking. 🥲#2022-12-0519:20normananother soul saved!#2022-12-0519:21bhauman(def READ-STRING cloure.edn/read-string)
#2022-12-0519:23borkdudehehe#2022-12-0519:45pezPity. I was waiting for when the file input would be massaged to be code so that read-string proper would spit out the answer.#2022-12-0519:46borkdudeload-string
to the rescue :P#2022-12-0517:07bhaumanAlthough thinking about it I could have used some code to accomplish the same thing as the emacs rectangle macros.#2022-12-0517:14noogaI just did this to parse the first section:
(def data (->> "input/day5.txt" slurp lines (split-with (complement empty?))))
(def stacks (->> data first butlast
(map #(str-replace % #"( |\\[)([A-Z ])(\\]| ) ?" "$2"))
(apply mapv list)
(mapv #(drop-while #{\space} %))))
It gives me a vector of lists representing each stack.
The caveat here is that I'm solving and developing the language at the same time so I had to add regex support to pull this off :d#2022-12-0517:38bhaumanI’ll go look at the orig code to check it out#2022-12-0517:42bhaumanYeah it’s the transpose that seems important here 🙂#2022-12-0517:44bhaumanYeah definitely like your solution here#2022-12-0517:44noogayeah, this is basically:
1. clean up the cruft to get something like
C
DE
ABC
2. split into chars and transpose
[(\space \E \C) (\C \D \B) (\space \space \A)]
3. clean up leading spaces
[(\E \C) (\C \D \B) (\A)]
#2022-12-0517:37bhaumanAnd I offer one more way of parsing the columns without formatting the file:
(def columns-alt
(->> (slurp "src/adv2022/day5/columns-orig.txt")
string/split-lines
;; make rows lists of 4 characters
(mapv #(partition-all 4 (seq %)))
;; transpose - this gets the columns together
(apply map vector)
;; to make the column a string
(map #(string/join (flatten %)))
;; make into clojure data like [[A] [B] 2]
(map #(read-string (str "[" % "]")))
;; remove the last number
(map butlast)
;; to join [[A] [B]] -> [A B]
(map flatten)))
#2022-12-0519:31Ben Liebermanhey, I've been stuck on day five for quite a while, can someone give my code a once over and see if they can find anything stupid and obvious? See in 🧵#2022-12-0519:32Ben Lieberman(ns slothrop.day-five.crates
(:require [ :as io]
[clojure.string :as string]))
(def input (-> "public/puzzle_inputs/day_five.txt"
io/resource
slurp
string/split-lines))
(def crates (take 8 input))
(def instructions (map (comp #(map parse-long %)
#(re-seq #"\d+" %))
(drop 10 input)))
(def full-stacks (atom (->> crates
reverse
(apply map vector)
(filter (fn [[a b c]] (not= a b c)))
(map #(remove #{\space} %))
(map vec)
(into []))))
(defn move-crates [coll params]
(loop [coll coll
[qty from to] params]
(if (<= 0 qty)
(let [from-val (get-in coll [from])
to-val (update-in coll [to] conj (peek from-val))
safe-pop (fn [v] (if (empty? v) v (pop v)))]
(recur (update-in to-val [from] safe-pop) [(dec qty) from to]))
coll)))
(comment
(doseq [ins instructions]
(swap! full-stacks move-crates ins))
@full-stacks
(apply str (map (comp last #(filter some? %)) @full-stacks)))
#2022-12-0519:34jumarI don’t have time to debug this but I suggest getting rid of the atom and trying it on the sample input first#2022-12-0519:44nbardiukOh, I had this bug also! The commands to move crates use 1 based indexes but Clojure collections are 0 based. I don't see any place in your code to decrement from
and to
#2022-12-0519:45Ben LiebermanOh good point @U076FM90B! I accounted for this earlier and then changed my code and forgot to update that part 😅#2022-12-0520:05pithylessI had a bug in today's code (in my defense, AOC comes out at 6am in my timezone... before ☕ ). Since I was using reduce
to go through all the moves one-by-one and update the current stacks, it was really easy to replace reduce
with reductions
and tap>
all of the individual steps to portal (where I could just view them in a table and see where the unexpected behavior happened).
Doesn't answer your question directly, but perhaps it may help give you some ideas for the future (it is related to what @jumar wrote about avoiding doseq
and swap!
if you want an easier time debugging later).#2022-12-0520:10Ben LiebermanThat's a good tip, thanks @U05476190! I didn't even know about reductions
until now.#2022-12-0521:35wevremAnother potential gotcha with the crates: the input lines are not all equal length, so the transpose might cut off some rows/columns.#2022-12-0521:37Ben LiebermanYeah, I was thinking about that initially but using (apply map vector)
in my processing pipeline helped. The problem with my code was the off-by-one issue.#2022-12-0600:27Joseph Dumont@U05476190 Whoa! I like the sound of using tap> to send the steps to portal. I just caught an intro to portal from the ds4clj group but haven't played with it yet. Would you mind sharing how you have it setup? EDIT: I see now from the portal README, (add-tap #'p/submit) ; Add portal as a tap> target
then (tap> x)
#2022-12-0605:33pithyless@U03KMPFU4TH 👍 Some use nrepl middleware to pipe all evals to portal, but I prefer using portal just via tap
. It's also helpful to hook up editor keybindings to run the taps for you, eg:
(tap> *1) ;; last result
(tap> *e) ;; last error
#2022-12-0605:35pithylessI've even got this hack in my emacs config for piping tests to portal (maybe nowadays there is a better way, but it still works for me):
(defun my/cider-portal-test-ns ()
(interactive)
(when-let ((ns (clojure-find-ns)))
(cider-nrepl-sync-request:eval
(concat
"(let [report (atom [])]"
" (tap> ['" ns " report])"
" (with-redefs [clojure.test/report #(swap! report conj %)]"
" (clojure.test/run-tests '" ns " )))"))))
#2022-12-0520:05pithylessI had a bug in today's code (in my defense, AOC comes out at 6am in my timezone... before ☕ ). Since I was using reduce
to go through all the moves one-by-one and update the current stacks, it was really easy to replace reduce
with reductions
and tap>
all of the individual steps to portal (where I could just view them in a table and see where the unexpected behavior happened).
Doesn't answer your question directly, but perhaps it may help give you some ideas for the future (it is related to what @jumar wrote about avoiding doseq
and swap!
if you want an easier time debugging later).#2022-12-0520:32noogahey @borkdude, after your suggestion, I've just added reader conditionals to let-go - will try to update my solutions to run both on lg an bb#2022-12-0520:43borkdudeexciting :)#2022-12-0520:45noogaI'm having a blast 🙂 lg is still extremely barebones but it's surprisingly workable for what it is at the moment#2022-12-0520:47borkdudeI have the same state with #C03QZH5PG6M and #C03U8L2NXNC: it's doable but some things are obviously missing#2022-12-0520:47borkdudedoes lg support interop on go stuff already?#2022-12-0520:50noogait does, as in it can move values from go to lg and back, convert them, call methods on things etc. it even supports moving entire functions and channels between two worlds#2022-12-0520:51noogahowever, the API for this is not entirely fleshed out, I'm still experimenting on how to make it super comfy#2022-12-0520:53noogahere's an example of calling methods on a Go http response https://github.com/nooga/let-go/blob/main/examples/server.lg
here are some lousy mini tests for calling lg from Go https://github.com/nooga/let-go/blob/main/pkg/api/interop_test.go#2022-12-0520:57noogain the first example that fn
is actually passed to some Go function as a callback#2022-12-0521:00noogabtw, I've made a channel: #C04DCFZKPJN 😉#2022-12-0520:45zamanskySince people are sharing how they parsed the input, here's what I did to go from the graphical tower to my map:
(defn make-towers
"Turn the text of the towers into a dictionary
keys are tower names, list of vectors at each entry"
[raw-stacks]
(->> (str/split-lines raw-stacks)
(apply mapv vector) ;; transpose the "matrix"
(mapv reverse) ;; reverse them so that the tower names are left
(filterv (fn [x] (not= (first x) \space))) ;; remove non tower rows
(mapv (fn [x] (filterv #(not= % \space) x))) ;; trim trailing space
;; turn list of lists into a dictionary
(reduce (fn [acc next]
(assoc acc (first next) (into [] (rest next)))) {})))
Solution shared in the solutions thread.#2022-12-0521:15Luis SantosSimilar to mine:
(defn build-stacks [i]
(->> (string/split-lines i)
(map #(re-seq #"\[\w\]| |[0-9]" %))
(take-while (complement nil?))
(transpose)
(map reverse)
(map #(remove string/blank? %))
(reduce #(assoc %1 (first %2) (rest %2)) (sorted-map))))
#2022-12-0521:46CarnunMPI packed things straight into a vector, which is effectively a map from 0-based index to value... and generally simplifies everything downstream. :))
https://clojurians.slack.com/archives/C0GLTDB2T/p1670276617404109?thread_ts=1670219051.953159&cid=C0GLTDB2T#2022-12-0521:49CarnunMPwhat's transpose
@UK00KCK6D?#2022-12-0522:15genmeblogHere is mine. stacks
contains lines of the first part.
(defn parse-stacks-line
[line]
(->> line rest (take-nth 4)))
(defn parse-instructions
[line]
(->> (re-seq #"\d+" line)
(map (comp dec read-string))))
(defn parse
[[stacks instructions]]
{:stacks (->> (butlast stacks) ;; drop stack numbers, bottom line
(map parse-stacks-line) ;; get crates
(apply map list) ;; transpose and keep in the list (stack)
(mapv #(remove #{\space} %))) ;; remove empty spaces
:instructions (map parse-instructions instructions)})
#2022-12-0522:19peterhI somehow always forget that you can map through multiple seqs for transposition, so I used a different approach where I attached the stack index to each letter row by row as a key so that I could merge each row-map to a single map of concatenated items.
(defn parse-stacks [input]
(let [uppercase (set (map char (range (int \A) (inc (int \Z)))))
parse-crate (fn [i xs]
(let [crate-id (filter uppercase xs)]
(when-not (empty? crate-id)
[(inc i) crate-id])))]
(->> input
(map (comp (partial into {}) ;; each row becomes a map: {1 \N, 2 \C}
(partial map-indexed parse-crate) ;; parses the letter along with its position
(partial partition-all 4))) ;; two crates are always 4 chars apart
(apply merge-with concat))))
#2022-12-1212:18Luis Santos@U018D6NKRA4
(defn transpose [xs]
(apply map list xs))
Converts rows into columns.#2022-12-0521:41wevremThis approach doesn’t work on my input, @zamansky, because the input lines are not all the same length (the last stack is shorter than some of those in the middle), and the transpose step truncates to the shortest.#2022-12-0521:42R.A. PorterYou can pad your short stacks first. That should get you over that hump.#2022-12-0521:50wevremAh, but should that padding happen as a manual edit on the input file? I think it should be accounted for in the code. That was my point.#2022-12-0521:51R.A. PorterYeah. In code. You’d need to update that sample code between the first line of the threading macro and the reduce fn.#2022-12-0522:33bhaumanyeah I don’t think my solution above would work either.#2022-12-0523:02wevremI might need to be more careful saving my input files. The original file does have spaces padding out the stack drawing. But saving that in my editor got rid of trailing spaces. Meanwhile, the whole thing prompted me to create a handy transpose
method that will watch for and pad shorter lines.
https://github.com/wevre/advent-of-code/blob/e27c48292592a31619cc70e355e6e10784000be5/src/advent_of_code/common.clj#L24#2022-12-0523:07bhaumanthat makes sense#2022-12-0522:34bhaumanhmmm this makes me want to try a different solution, working it#2022-12-0522:58jurjanpaulAnybody else solving the puzzles in Clojure(Script) entirely on their mobile phone?
I guess not. And I wouldn’t recommend it. 🙂 But I find it’s the only way for me to keep up on busy days, particularly celebrating the great tradition of Sinterklaas in The Netherlands today! (Laptop time is reserved for work and other important stuff, like writing Sinterklaas rhymes, which is great fun actually.)
So I’m pleased that despite some quirks and annoyances (that I really need to dive into someday, mainly with respect to the cursor position jumping out of focus for no good reason), the Scittle based ”‘Away from Preferred Editor’ ClojureScript Playground” (a static HTML page gluing together Scittle, Reagent, CodeMirror, Parinfer and localStorage) at https://jurjanpaul.github.io/ape-cljs-playground allows me to finish this year’s puzzles on the same day they come out (so far, but not much longer I expect, which is fine). Just paste the input into a fresh buffer and go… 🙂
In case anybody knows of a more convenient mobile Clojure experience, I’d be eager to try it though (but suspicious of anything that doesn’t support Parinfer to be honest).#2022-12-1709:56jurjanpaulUltimately I was able to finish the first 15 puzzles on the day they came out, entirely edited and run on my phone with Scittle.
Got stuck on number 16, part 1, with a typical case of not being able to figure out why my obviously correct solution laughcry does not get accepted by the AoC software.
Unfortunately, I have not yet been able to figure out how to fix the editor’s focus issue either; CodeMirror 5 provides a scrollIntoView
method that still manages to scroll the cursor under the iPhone’s keyboard. 🙂 Including a margin helps, but I am still looking for a recipe for figuring out an appropriate value (that would work both for portrait and for landscape phone holding… for any zoom level, on any device anywhere… :thinking_face:).#2022-12-0523:03borkdude@jurjanpaul502 Don't know if it's better since this doesn't have parinfer yet, but it uses nextjournal/clojure-mode directly from npm, in the scittle-spirit of having no build step:
https://babashka.org/scittle/codemirror.html#2022-12-0523:17borkdudeThis editor does support the barfing/slurping stuff: https://nextjournal.github.io/clojure-mode#2022-12-0608:30jurjanpaulThank you @borkdude! That’s a great showcase for Scittle and nextjournal/clojure-mode.
I gave it a try in my phone’s browser, but I don’t find it to be mobile-friendly (or meant to be 🙂).
The slurping and barfing key chords are simply unavailable on a mobile phone’s browser keyboard (or: what am I missing?).
The lack of on-page stdout is fixable of course, as is the lack of explicit storage (the browser remembers the page’s state for a while anyway, until … I make it hang due to an inefficient algorithm. 🙂)
CodeMirror 6 itself probably provides the improvements (over 5) that I am looking for though.
Perhaps it is worth trying to use that (despite the lack of a working Parinfer extension; if only I had enough time to spare to try my hand…) and balance my braces myself after all. 🙂
#2022-12-0609:33borkdudeThe one from npm doesn't support barfing and slurping, but perhaps there can be a pre-made scittle plugin to facilitate this. Then it would be more like this here: https://nextjournal.github.io/clojure-mode/
cc @U5H74UNSF#2022-12-0609:37jurjanpaul'Unavailable' as in: you simply can't enter those key chords in a standard mobile browser keyboard, surely?#2022-12-0609:37borkdudeoh right, also that :)#2022-12-0609:37borkdudeyeah, I can see why parinfer is nice for that#2022-12-0609:38borkdudeape ftw!#2022-12-0609:41jurjanpaul🙂 Well, I would love for someone or some team to do it better.#2022-12-0609:43borkdudeHaving a code editor like ape is certainly one of the things that people would like to do with scittle so perhaps a nextjournal/clojure-code + parinfer thing for mobile kind of plugin could work some day#2022-12-0600:16bhaumanIf you all haven’t seen this, it’s really worth looking at. It demonstrates the interaction with chatGPT to solve advent problems.
https://note89.github.io/the-advent-of-code-ai-edition/
via @cfleming#2022-12-0607:14Mario TrostThanks for sharing! The day 4 prompt is revelatory:
> Write instructions for the following challenge in such a way that a large language model like yourself can take those instructions and produce a program that creates the right output when run. The program needs to read from a file called input.txt
Reminds me of starting to code straight from a business request vs. doing a planning session first and getting requirements straight.#2022-12-0605:13AppleDay 6 - Solutions#2022-12-0605:13Apple;; 202206
(let [d (slurp "resources/202206")
f #(->> (partition % 1 d)
(keep-indexed (fn [i x]
(if (= % (count (set x)))
(+ % i))))
first)]
(map f [4 14]))
;; (1850 2823)
#2022-12-0605:16normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day06/main.clj
worst performance yet#2022-12-0605:24Alekshttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_06.clj#2022-12-0605:27R.A. Porterhttps://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day06.html#2022-12-0605:29mchampine;; Part 1
(defn sop [n s]
(let [cs (partition-all n 1 s)
mk (apply str (first (filter #(= % (distinct %)) cs)))]
(+ n (str/index-of s mk))))
(sop 4 input) ;; 1343
;; Part 2
(sop 14 input) ;; 2193
#2022-12-0605:38Mikko Koskihttps://github.com/rap1ds/advent-of-code-2022/blob/main/src/day6.clj
And happy independence day Finland :flag-fi:!#2022-12-0605:41nbardiukTIL distinct?
https://github.com/nbardiuk/adventofcode/blob/master/2022/src/day06.clj#2022-12-0606:11wevremhttps://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_06_packets.clj#2022-12-0606:58Vincent Olesenhttps://github.com/volesen/aoc2022/blob/main/day6/day6.clj#2022-12-0607:03tylerwhttps://github.com/tylerw/advent-of-code-2022/blob/master/src/aoc2022/day06.cljc#2022-12-0607:03tylerwKeeping with the advent-of-transducers theme#2022-12-0607:06Ben Liebermanthis regrettably only got me the first part but gonna keep working with it
(def input (-> "public/puzzle_inputs/day_six.txt" io/resource slurp))
(defn process-data [n s]
(let [packets (map #(apply str %) (partition n 1 s))
unique-packets (map (comp #(apply str %) distinct) packets)
nums (filter some? (map #(if (= %1 %2) %3 nil)
packets unique-packets (range)))]
(first (drop n nums))))
#2022-12-0607:12tylerwI think changing your last line to (+ (first nums) n)
should do it#2022-12-0607:37motformSeems like I missed out on the take-while
train 😅
https://github.com/motform/advent-of-clojure/blob/master/src/advent_of_clojure/2022/06.clj#2022-12-0608:18J(defn solve [input nb]
(reduce (fn [acc item]
(if (= (count item) nb)
(reduced (+ acc nb))
(inc acc)))
0
(map set (partition nb 1 input))))
(defn part1 [input]
(solve input 4))
(defn part2 [input]
(solve input 14))
#2022-12-0608:45genmeblog(defn marker-id
[data marker-length]
(->> (partition marker-length 1 data)
(map (comp count set))
(map-indexed vector)
(sort-by second >)
(first)
(reduce +)))
#2022-12-0608:47StuartTodays was a LOT easier than yesterday 🙂
https://github.com/stuartstein777/clj-advent-of-code/blob/master/src/stuartstein777/2022/day6.clj#2022-12-0608:51jon.ramoshttps://github.com/jramosg/advent-of-code/blob/master/src/advent_of_code/year_2022/day_06/main.clj#2022-12-0609:07babardohttps://github.com/v-garcia/aoc_2022/blob/main/day6.clj#2022-12-0609:14Piotr Kaznowski(defn solve [it len]
(let [f (fn [ii] ((juxt #(take len %) #(drop 1 %)) ii))]
(loop [[a b] (f it), pos len]
(if (= len (count (set a))) pos
(recur (f b) (inc pos))))))
(defn -main [day]
(let [input (file->str day)
result (partial solve input)]
(zipmap [:part1 :part2] (map result [4 14]))))
#2022-12-0609:49Valentin MouretIt’s so nice to learn about all these functions from your examples (`distinct?`, take-while
, keep-indexed
…).
In https://github.com/ValentinMouret/advent-2022/blob/main/src/day_06.clj, I used reduce
and reduced
and I don’t think I have seen it so far.#2022-12-0610:25Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day6.clj#2022-12-0610:42tschadyVariations on above. This was the first day I used my bb submit
to send in the answers. Next up, submit direct from emacs cider
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d06.clj#2022-12-0610:43BenjaminI am happy that today my solution is almost the same as @U1Z392WMQ#2022-12-0611:01pwojnowskiMaybe I missed something, but why in Clojure there's no queue
function to create a queue?#2022-12-0611:01pwojnowskiMine:
> (defn day-06 [input n]
> (loop [seen (apply conj (clojure.lang.PersistentQueue/EMPTY) (take n input)) i n]
> (if (= (count (set seen)) n)
> i
> (recur (conj (pop seen) (get input i)) (inc i)))))
>
> (defn day-06-1 [input]
> (day-06 input 4))
>
> (defn day-06-2 [input]
> (day-06 input 14))#2022-12-0611:03StuartYou have PersistentQueue#2022-12-0611:04Stuartbut I guess you can mimic simple queues with vectors#2022-12-0611:31jaihindhreddyI couldn't resist not using juxt
😂:
(defn day6 [fs]
((juxt #(% 4) #(% 14))
(fn [k]
(->> (partition k 1 fs)
(keep-indexed
#(when (apply distinct? %2)
(+ % k)))
first))))
#2022-12-0611:36lassemaattaI've been using AoC as an opportunity to finally learn how to use transducers. For example https://github.com/lassemaatta/clj-aoc-2022/blob/master/src/lassemaatta/aoc_2022/day06.clj my solution for day 6.#2022-12-0612:06zamanskyhttps://github.com/zamansky/advent2022/blob/main/src/day06.clj#2022-12-0612:27Michael Ducharmhttps://github.com/mducharm/advent_of_code_2022/blob/main/src/advent_of_code/day_06.clj#2022-12-0613:17Alexis Schad(->> (slurp "day6.txt")
(partition 14 1)
(map (comp count set))
(#(.indexOf % 14))
(+ 14))
#2022-12-0613:25noogahttps://github.com/nooga/aoc2022/blob/master/day6.lg
(ns day6)
(def data (slurp "input/day6.txt"))
(defn solve [n]
(->> data (partition n 1) (map (comp #{n} count set)) (take-while not) count (+ n)))
(println "1:" (solve 4))
(println "2:" (solve 14))
helped me to fix my comp
implementation 🙂#2022-12-0613:38bhaumanDay 6
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day6/sol.clj#2022-12-0614:34CarnunMPhttps://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d6.clj, eh?
the essence of it:
(defn find-marker [n input]
(->> (partition n 1 input)
(keep-indexed #(when (apply distinct? %2) %1))
first
(+ n)))
#2022-12-0614:35StuartI think this just means tomorrow will be brutal :)#2022-12-0614:36CarnunMPindeed...
has felt like the calm before the storm for a while now#2022-12-0614:36noogafirst week is always kinda like this and then it turns into a full time job#2022-12-0614:52normanWhat I spent 5 minutes debugging last night... Zipmap maps aren't ordered.
day06.main> (for [[n] (zipmap (range) "abcdedghijklmn")] n)
(0 7 1 4 13 6 3 12 2 11 9 5 10 8)
day06.main> (for [[n] (map-indexed vector "abcdefghijklmn")] n)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13)
keep-indexed wasn't really in my vocabulary, but now that I see those solutions, I will definitely start using it ore#2022-12-0614:57bhauman@UJEK1RGJ0 yeah the perf of let-go is going to definitely get tested for sure#2022-12-0615:18noogabring it on I say#2022-12-0618:13dogenpunkDay 6: https://github.com/dogenpunk/advent-of-code/blob/main/src/aoc22/day06.cljc#2022-12-0618:16dogenpunkDanggit! I always forget partition
can take a size argument…#2022-12-0618:23Luis Santos(defn sliding-window [seq length]
(loop [result ()
remaining seq]
(let [chunk (take length remaining)]
(if (< (count chunk) length)
(reverse result)
(recur (cons chunk result) (rest remaining))))))
(->> (sliding-window (slurp "input/day-6-input.txt") 14)
(reduce (fn [acc n]
(if (= (count (set n)) 14)
(reduced (+ acc (count n)))
(inc acc )))
0))
I wont forget that partition trick. 😄#2022-12-0618:24Michael DucharmI was looking for an equivalent of rust's windows
function, and learned that partition
could do that. Very handy!#2022-12-0619:25robertfwI went with a queue for this one but loving the succinct partition
answer!
(defn find-marker [stream marker-len]
(reduce-kv (fn [acc k v]
(cond
(< (count acc) marker-len) (conj acc v)
(= marker-len (count (into #{} acc))) (reduced k)
:else (conj (pop acc) v)))
(clojure.lang.PersistentQueue/EMPTY)
(into [] stream)))
#2022-12-0621:05peterh(defn partition-till-detected [n s]
(take-while (complement (partial apply distinct?))
(partition n 1 s)))
(defn count-to-marker [n s]
(+ n (count (partition-till-detected n s))))
(count-to-marker 4 input) ;; part 1
(count-to-marker 14 input) ;; part 2
#2022-12-0711:22ThierryAnd my day 6 solution:
https://github.com/LouDnl/advent-of-code-2022/blob/master/src/clj/advent_of_code_2022/days/day_six.clj#2022-12-2304:28dumrat(ns aoc2022.day6
(:require [ :refer [resource]]
[clojure.string :as str]
[clojure.set :refer [intersection]]))
(defn data []
(->> (resource "inputs/day6.txt")
(slurp)))
(defn solution [s len]
(let [start-3 (into [] (take len s))
except-start-3 (into [] (drop len s))]
(+ len
(reduce (fn [[l idx] e]
(tap> [l idx])
(if (apply distinct? (conj l e))
(reduced idx)
[(conj (subvec l 1) e) (inc idx)]))
[(into [] start-3) 1]
except-start-3))))
(def part1 #(solution % 3))
(def part2 #(solution % 13))
#2022-12-0609:53pezIf someone would like the horrible experience of using JavaScript instead of Clojure... 😃 At least it supports reloading of JavaScripts code. Any ideas of how to integrate ChatGPT in a cool way would be awesome. Please 🧵 . I asked ChatGPT about integrating with its API and it seems pretty straight forward, especially since it gave me the code for it.#2022-12-0610:02Petrus TheronSup Clojurians. Here are my 2022 Advent of Code solutions in Clojure: https://github.com/theronic/advent-of-code/tree/main/src/advent_of_code/year2022#2022-12-0611:42tschadyPSA for those new to some of the core functions people use in these solutions: Study the https://clojure.org/api/cheatsheet . e.g. Have a sequence, and want to get some things from the front? go to “Seq In, Seq Out” -> “Head Items” and checkout the list: take
take-while
butlast
drop-last
for
.#2022-12-0612:38pwojnowskiI totally forgot about distinct?
and really miss basic factory function for queue (sth like (def queue [coll]... (clojure.lang.PersistentQueue ...)
#2022-12-0612:44genmeblogme too! distinct?
and keep-indexed
this time (`re-seq` yesterday)#2022-12-0612:44genmeblogevery day something new 🙂#2022-12-0616:21scottbaleKind of a meta-point: over time I've come up with a bit of https://github.com/scottbale/advent-of-code/blob/main/clojure/resources/template.clj.txt to tackle each day's puzzle, and I like it so much that this year I wrote a little https://github.com/scottbale/advent-of-code/blob/main/clojure/src/user.clj to generate each day's new one. It's not much boilerplate, but it takes care of the little bit of file I/O fiddliness and my experience becomes, I just hop into the REPL and start hacking first using the puzzle's hardcoded sample data, and then more often than not it works on the first try with my personalized input (which I have to copy into the resource file).
So for example day 5 looks like this at the start:
(ns aoc-2022.day5
"docstring"
(:require
[ :as io]))
(defn runner
"runner docstring"
[input]
)
(comment
(runner [" [D]"
"[N] [C]"
"[Z] [M] [P]"
" 1 2 3"
""
"move 1 from 2 to 1"
"move 3 from 1 to 3"
"move 2 from 2 to 1"
"move 1 from 1 to 2"])
(with-open [r (io/reader (io/resource "aoc-2022/day5.txt"))]
(runner (line-seq r)))
)
#2022-12-0617:54elkenI have a bb
script to create a new day from a template with all my clerk boilerplate#2022-12-0617:54elkenhttps://github.com/elken/aoc/blob/master/resources/template.clj#2022-12-0617:55elkenhttps://github.com/elken/aoc/blob/master/bb.edn#2022-12-0618:41pithylessNeat! I started building something that parses the html to markdown and pastes that into clerk, but I might just steal your idea of using hickory and using the clerk/html
viewer. The downside is that the prose is not visible in the editor, but the upside is that the prose is not visible in the editor. :thinking_face:#2022-12-0618:43elkenYeah I did it manually at first but it's tedious to do and wastes space. You can have the notebook in an xwidgets browser frame of Emacs is compiled with it (which is how I work)#2022-12-0618:47pithylessI'm old-fashioned and still use an external browser for my Portal and Clerk. :)
I managed to automate the markdown parsing with this: https://github.com/simon-brooke/html-to-md
But it's just a hacky POC at the moment and I'm not aware of what the sharp edges are (OTOH the AOC html is relatively straightforward so shouldn't be too many issues going forward).
I will play with both approaches when I find some time in the coming days and report back. Thanks for sharing @U043RSZ25HQ!#2022-12-0701:24tschadybb
has Selmer built-in, might want to check that out. (ns aoc.{{year}}.d{{day}}
is convenient.#2022-12-0623:03peterhI’ve seen someone using clojure.lang.PersistentQueue
in todays puzzle, so I wondered if this data structure is something that you use frequently in Clojure and if there are any caveats to be aware of (other than from the general properties of queues).
I already explored how it behaves with conj
, peek
and pop
, which is as expected from a queue (first-in-first-out). I also see that seq
works on queues and so they can be mapped, filtered, etc. and you can use (into clojure.lang.PersistentQueue/EMPTY …)
to get a queue from a seq or vector. They also seem to work with Babashka.#2022-12-0623:59scottbaleFunny you should mention it: earlier this very day, I was mentioning to someone that, although I've been programming Clojure since 2011, until I very recently read chapter 2 of Clojure Applied I did not even know of the existence of clojure.lang.PersistentQueue
. 🤷#2022-12-0701:51wevrem<sample-of-one>I looked through my past AoC solutions and I’ve used it about once a year on average. In a full stack production app I’ve been working on, haven’t used it at all.</sample-of-one>#2022-12-0703:29ACanecdotally (looking through my AoC history), I have used it a couple times for path-finding puzzles but it looks like I switched to clojure.data.priority-map at some point.
I’m not a clojure expert in any way, so I can’t say whether either was the right way to go. (other than they did do the job asked of them)#2022-12-0705:50normanDay 7 - Solutions#2022-12-0705:51normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day07/main.clj
I'm a disappointed at the repeated evaluation for directory sizes. I'm glad this problem didn't punish that.#2022-12-0706:30Alex Alemihttps://github.com/alexalemi/advent/blob/main/2022/clojure/p07.clj#2022-12-0706:32Alex AlemiI had also started by building the fs tree, but then realized that I only needed to keep track of the directory sizes directly.#2022-12-0706:46Apple;; 202207
(let [f (fn [state [_ cmd path filesize filename]]
(if (= "cd" cmd)
(if (= path "..")
(update state :path pop)
(update state :path conj path))
(let [size (parse-long filesize)]
(loop [state state, path (:path state)]
(if (seq path)
(recur (update-in state [:size path] #(+ size (or % 0))) (pop path))
state)))))
m (->> (slurp "resources/202207")
(re-seq #"\$ (cd) (.+)|(\d+) (.+)")
(reduce f {:path []})
:size)
v (vals m)
x (+ (m ["/"]) -70000000 30000000)
q1 (->> v (filter #(>= 100000 %)) (reduce +))
q2 (->> v (filter #(>= % x)) (reduce min))]
[q1 q2])
;; [1667443 8998590]
#2022-12-0709:03J[HINT]: A folder can contains an other folder with the same name 😅#2022-12-0709:21Mikko Koskihttps://github.com/rap1ds/advent-of-code-2022/blob/main/src/day7.clj#2022-12-0710:41Felipehttps://github.com/FelipeCortez/advent-of-code/blob/master/2022/07.clj#2022-12-0710:59motformOver-engineered it a bit by actually building the tree, but got some practice using clojure.walk.
https://github.com/motform/advent-of-clojure/blob/master/src/advent_of_clojure/2022/07.clj#2022-12-0711:09noogabit braindead but I've got a headache today:
(ns day7)
(defn tally [sizes path fsize]
(loop [p path s sizes]
(if-not (empty? p)
(recur (pop p) (update s (apply str p) #(+ (or %1 0) fsize))) s)))
(def sizes (loop [[[f s t] & r] (->> "input/day7.txt" slurp lines (map #(split % " ")))
path []
sizes {}]
(cond
(nil? f) sizes
(and (= f "$") (= s "cd") (= t "..")) (recur r (pop path) sizes)
(and (= f "$") (= s "cd")) (recur r (conj path t) sizes)
(not (#{"dir" "$"} f)) (recur r path (tally sizes path (parse-long f)))
:else (recur r path sizes))))
(def to-free (- (- 70000000 30000000 (sizes "/"))))
(println "1:" (reduce + (filter (partial >= 100000) (vals sizes))))
(println "2:" (apply min (filter (partial <= to-free) (vals sizes))))
https://github.com/nooga/aoc2022/blob/master/day7.lg#2022-12-0711:20noogasporting newly added vals
#2022-12-0711:40CaseyI also used a tree of nested maps for the fs.. parsing the input turned out to be really easy, but calculating the sizes of the nested dirs was a PITA
https://github.com/Ramblurr/advent-of-code-2022/blob/main/src/aoc/day07.clj#2022-12-0712:05nbardiukparsed tree, then flattened into flat list of files, then reduced into folder sizes - too complicated https://github.com/nbardiuk/adventofcode/blob/master/2022/src/day07.clj#2022-12-0713:21CarnunMPnot the most concise (https://clojurians.slack.com/archives/C0GLTDB2T/p1670395567909029?thread_ts=1670392240.040349&cid=C0GLTDB2T@UP82LQR9N! 😅), but seemed a natural fit for zippers (parsing) and postwalk (processing)
https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d7.clj#2022-12-0713:27CarnunMPhttps://clojurians.slack.com/archives/C0GLTDB2T/p1670411367318609?thread_ts=1670392240.040349&cid=C0GLTDB2T too, damn
tiny!#2022-12-0713:31Valentin MouretI am not super satisfied as there are probably more elegant solutions with walk, but I am not quite used to it for now. 🙂
https://github.com/ValentinMouret/advent-2022/blob/main/src/day_07.clj#2022-12-0713:58Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day7.clj#2022-12-0714:31delaguardo(defn partition-with [pred]
(fn [xf]
(let [acc (atom nil)]
(fn
([] (xf))
([result]
(let [result (if-let [r (seq @acc)]
(do (reset! acc nil)
(unreduced (xf result r)))
result)]
(xf result)))
([result input]
(if (pred input)
(let [new-input @acc]
(reset! acc [input])
(if (seq new-input)
(xf result new-input)
result))
(do
(swap! acc conj input)
result)))))))
transducer to split input into partitions where each partition begins with an element for which pred
returns true and the rest - false
.
Similar to split-with but transducer friendly. I used it for day-7 solution to get from input lines blocks like [command & output]
#2022-12-0714:35tschadyFeel like a dropped an atom bomb on this one with zippers and a full-info map. specter helped a bit.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d07.clj#2022-12-0714:58tschadyI just realized my input is in perfect DFS order. Probably a super short solution if you can assume that.#2022-12-0715:06R.A. PorterAs most, over-engineered it a ton in anticipation of a request for more detailed results. Not happy with much of this at all - https://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day07.html#2022-12-0716:18J(defn incr-dir-size [state path size]
(->> (reduce
(fn [acc dir]
(let [d (if-some [p (:parent acc)]
(str p "-" dir)
dir)]
(-> acc
(update-in [:state d] (fnil + 0) size)
(assoc :parent d))))
{:parent nil :state state}
path)
:state))
(defn solve-tree [filename]
(loop [[h & t] (parse-input filename)
current-path []
dir-size {}]
(if (nil? h)
dir-size
(cond
(str/starts-with? h "$ cd")
(let [d (last (str/split h #" "))
current-path (if (= d "..") (pop current-path) (conj current-path d))]
(recur t current-path dir-size))
(not (or (= h "$ ls") (str/starts-with? h "dir")))
(let [[file-size] (str/split h #" ")
dir-size (incr-dir-size dir-size current-path (parse-long file-size))]
(recur t current-path dir-size))
:else
(recur t current-path dir-size)))))
(defn part1 [filename]
(->> (solve-tree filename)
(vals)
(filter #(>= 100000 %))
(reduce +)))
(defn part2 [filename]
(let [sizes (solve-tree filename)
target (+ (sizes "/") -70000000 30000000)]
(->> (vals sizes)
(sort <)
(drop-while #(<= % target))
(first))))
#2022-12-0716:35zamanskyUgly ugly ugly, but it works and now from reading all of your comments above I can go back later and learn about zippers and walk.
https://github.com/zamansky/advent2022/blob/main/src/day07.clj#2022-12-0716:40wevremNot too shabby with zippers.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_07_directories.clj#2022-12-0717:17Vincent OlesenUsed match, which turned out nice. https://github.com/volesen/aoc2022/blob/main/day7/day7.clj#2022-12-0717:29bhaumanLots of postwalk and tree-seq here https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day7/sol.clj#2022-12-0717:51lassemaattaA rather verbose https://github.com/lassemaatta/clj-aoc-2022/blob/master/src/lassemaatta/aoc_2022/day07.clj using a transducer to provide a sequence of file (which wasn't actually necessary) and directory entries#2022-12-0718:52wevremI modified my solution, dropping the step where I added directory sizes to the tree, and instead I just calculate them on the fly with a recursive function.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_07_directories.clj#2022-12-0719:08wevremI liked @U04575QMU2K use of match
, so I incorporated that as well. At what point must I stop tweaking and get on with the real things I’m supposed to be doing today?#2022-12-0719:33genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day07.clj#2022-12-0719:48tschady😆 Second try.
I munged the input string, eval’d it directly into a tree structure.
(defn parse-tree [input]
(let [open (-> input
(str/replace "$ cd .." "]")
(str/replace #"\$ cd (.*?)\n" " [")
(str/replace #"[^\d \[\]]" ""))
missing (- (get (frequencies open) \[)
(get (frequencies open) \]))]
(read-string (str open (apply str (repeat missing "]"))))))
(defn dir-sizes [input]
(->> (parse-tree input)
(tree-seq vector? identity)
(filter vector?)
(map #(sp/select (sp/walker number?) %))
(map (partial reduce +))
sort))
(defn part-1 [input]
(->> (dir-sizes input)
(filter #(>= 100000 %))
(reduce +)))
(defn part-2 [input]
(let [dirs (dir-sizes input)
space-needed (- 30000000 (- 70000000 (last dirs)))]
(->> dirs
(drop-while #(> space-needed %))
first)))
#2022-12-0719:54nbardiukcool! does the trick work because the input is in depth first order?#2022-12-0719:55tschadyyes, I think that’s a requirement. And what do you mean “trick”? Production ready.#2022-12-0720:47noogawhat if I did
cd /
cd a
cd ..
cd a
ls
ls
?#2022-12-0721:04StuartWell, I made a mess today...
I mean, it worked, and I got both stars. But I made a mess in the process.
https://github.com/stuartstein777/clj-advent-of-code/blob/master/src/stuartstein777/2022/day7.clj
My solution creates a map like this (from the test data):
{["/"] {:files #{["c.dat" 8504156] ["b.txt" 14848514]},
:dirs #{"d" "a"},
:sizes 23352670},
["/" "a"] {:files #{["f" 29116] ["g" 2557] ["h.lst" 62596]},
:dirs #{"e"},
:sizes 94269},
["/" "a" "e"] {:files #{["i" 584]},
:dirs #{},
:sizes 584},
["/" "d"] {:files #{["k" 7214296] ["j" 4060174] ["d.log" 8033020] ["d.ext" 5626152]},
:dirs #{},
:sizes 24933642}}
Stupid me thought all that info on files and stuff would be necessary for part 2... sigh
Once I had that I reduce each key over a map of simple directories and sizes (start at 2).
e.g.
["/" "a" "e"] would set map to {["/" "a" "e"] n}
Then increase ["/" "a"]
by the same size, then finally ["/"]
by the same size again.
Which gave me a map of full directory paths and their size.#2022-12-0721:06StuartLike I said, I made a mess. It at least did make part 2 trivial.#2022-12-0722:50bhaumanclojure.walk/postwalk
into a flatten
is a great way to get the dir totals after making the dir structure. Don’t forget about postwalk-demo
which helps get a feel for the execution order#2022-12-0723:13wevremI just finished making some tweaks that do exactly that, @U064J0EFR. Okay, now I’m done. No more fiddling. I’m satisfied.#2022-12-0802:32robertfwI also went full nuclear on this one 😅 I had a feeling it was overkill (especially not knowing what the second part was going to be) but I felt like it was a good opportunity to practice writing a stateful transducer and playing with zippers.
edit: realizing after posting that end-loc
can be refactored using loc-seq
but what's done is done#2022-12-0808:03pwojnowskiI parsed the input into a fs tree {:name name :type :dir/:file :size size :children [for dirs only]}
and then traversed using tree-seq
: https://github.com/pwojnowski/advent-of-code/blob/master/src/aoc/aoc2022.clj#L193#2022-12-0811:21Mark WardleBuilding a tree sounded complicated to me, so I used a different approach and simply built a flattened list of paths and file sizes, and then did filter
by prefix, and reduce
to calculate directory sizes.
(defn parse-line [{:keys [current-path] :as ctx} line]
(m/match (str/split line #"\s")
["dir" _] ctx ;; NOP
["$" "cd" "/"] (assoc ctx :current-path [""])
["$" "cd" ".."] (update ctx :current-path pop)
["$" "cd" dir] (let [path (conj current-path dir)]
(-> ctx
(assoc :current-path path)
(update :dirs conj (str (str/join "/" path) "/"))))
["$" "ls"] ctx ;; NOP
[size filename] (update ctx :files conj [(str/join "/" (conj current-path filename)) (parse-long size)])
:else (update ctx :errors conj {:error "Unknown command: " :line line})))
(defn parse-commands
([lines]
(parse-commands {:current-path []} lines))
([ctx lines]
(if-let [line (first lines)]
(recur (parse-line ctx line) (rest lines))
(dissoc ctx :current-path))))
(defn size
"Given a sequence of files (tuples of path and size), determine total size of the
specified directory."
[files dir]
(reduce (fn [acc [path size]]
(if (str/starts-with? path dir)
(+ acc size)
acc)) 0 files))
#2022-12-0814:08genmeblogRevisited version. Discoveries: you don't need dir
lines at all. Also tree-seq
simplifies the things. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day07.clj#2022-12-0912:19ThierryDay seven part one:
(defn command-walker ; part-one solution
[input]
(let [commands (read-input input)
cd (fn [c] (.contains c "$ cd"))
ls (fn [c] (.contains c "$ ls"))
file (fn [s]
(let [[size name] (string/split s #" ")]
{name (Long/parseLong size)}))
oddsor (fn [tree] ; walks the created map with data to sum the sizes
(walk/postwalk
(fn [node]
(if (map? node)
{:size (reduce +
(concat
(filter number? (vals node))
(keep :size (vals node))))
:children node}
node))
tree))
totalsize (atom 0)
calculate-size (fn [tree] ; calculates the sum of all sizes < 100000
(walk/postwalk
(fn [node]
(let [size? (fn [s] (< s 100000))
size (fn [s] (-> (select-keys s [:size]) :size (#(when (size? %) %))))]
(if (and (map? node) (not-empty (select-keys node [:size])))
(when-let [total (size node)]
(swap! totalsize + total))
node)))
(oddsor tree)))
foldercontent (atom {})
folders (atom {})
foldertree (atom [])
previousfolder (atom nil)
currentfolder (atom nil)
_inputwalker (doall ; converts the input to a map with data
(for [c commands
:let [cdto (first (when (cd c) (take-last 1 (re-seq #"[a-zA-Z0-9/[..]]+" c))))]]
(if cdto
(do
(reset! previousfolder @currentfolder)
(if (= ".." cdto)
(reset! foldertree (into [] (take (dec (count @foldertree)) @foldertree)))
(swap! foldertree conj cdto))
(reset! currentfolder (last @foldertree))
(reset! foldercontent {}))
(when-not (ls c)
(when-not (.contains c "dir ")
(swap! foldercontent conj (file c)))
(swap! folders assoc-in @foldertree @foldercontent)))))]
(calculate-size @folders) ; calculate the size
@totalsize)) ; return the size
#2022-12-0912:56ThierryDay seven part two
https://github.com/LouDnl/advent-of-code-2022/blob/09be4f6e8d6340ca38861b88fb963449927d6f37/src/clj/advent_of_code_2022/days/day_seven.clj#L140-L194#2022-12-1016:53peterhFinally got back to AoC. Didn’t want to build the tree, so I made a graph-like thing and recursively resolved the absolute paths as references while walking from "/"
. Not the most elegant solution, but somehow I believed it’d be more flexible and easier to reason about: https://github.clerk.garden/formsandlines/aoc2022-clojure/commit/50c1e9931d26b276f0521296954ab90f3334f8ee/src/advent_of_clerk/day_07.html
TIL from Apple’s approach that you don’t even need to consider subdirectories in ls
output, because the cd
commands contain all the information when you just recursively add the file sizes to all parent directories!#2022-12-0712:04noogaI just had a thought that one could implement a file system, insert all the files from the problem into it and then shell out to du
to find out the sizes 😂#2022-12-0712:09noogaor better yet, regexp the problem into a shell script for creating all those files on disk i.e.
dir foo -> mkdir foo
123 bar -> dd if=/dev/zero of=bar count=123 bs=1
$ cd <x> -> cd <x>
and then du
#2022-12-0712:28Felipealmost got it... du is tricky#2022-12-0712:46noogadirs probably weight something in posix#2022-12-0713:00Felipeyeah, that was the whole problem#2022-12-0713:01Felipewe can sum just the files in a subshell#2022-12-0713:01Felipe{:tag :a, :attrs {:href "/cdn-cgi/l/email-protection", :class "__cf_email__", :data-cfemail "5d3b3831342d383e322f2938271d34273c3e"}, :content ("[email protected]")}
#2022-12-0713:02Felipepiping find to find? yeah sure#2022-12-0713:06Felipeworks on the real input too!#2022-12-0713:33noogawoot#2022-12-0713:33nooga@UA2U3KW0L this is epic#2022-12-0714:19Benjaminlol#2022-12-0712:28pithylessOr... now bear with me... write a generator of random nested directory/files and repeat until tree
matches the original input problem, and then just du
😂#2022-12-0712:29pithylessIs there something like "code golf" for AOC, where the purpose is to find the most ridiculous way to solve the problem? This should be a separate leaderboard.#2022-12-0712:47nooga"code rube goldberg"#2022-12-0712:50noogareminds me of http://tom7.org/harder/#2022-12-0713:21motformThere is some on that over on the reddit with the tag Upping The Ante: https://www.reddit.com/r/adventofcode/?f=flair_name:%22Upping%20the%20Ante%22#2022-12-0715:37Cal HerriesThere’s a separate competition for die-hard code golfers over on stack exchange. Not the same problems though https://codegolf.meta.stackexchange.com/questions/25251/announcing-code-golf-advent-calendar-2022-event-challenge-sandbox#2022-12-0716:55noogameh, they have home-made languages for golfing#2022-12-0717:00noogaand it seems like they don't have to parse the input#2022-12-0717:33bhaumanpostwalk
and tree-seq
come in very handy here.#2022-12-0717:36ThierrySpent the good afternoon on day 7 part one. At the moment I have a ds thats a map and contains each folder and its size in files. Now im stuck because i need to add the size of a subfolder to the parent folder. I have yet to figure out how :rolling_on_the_floor_laughing:
{:/ {:a {:e {:files [{:name "i", :size 584}],
:folders [],
:foldersize 0,
:totalfilesize 584},
:files [{:name "f", :size 29116} {:name "g", :size 2557}
{:name "h.lst", :size 62596}],
:folders [:e],
:foldersize 0,
:totalfilesize 94269},
:d {:files [{:name "j", :size 4060174} {:name "d.log", :size 8033020}
{:name "d.ext", :size 5626152} {:name "k", :size 7214296}],
:folders [],
:foldersize 0,
:totalfilesize 24933642},
:files [{:name "b.txt", :size 14848514} {:name "c.dat", :size 8504156}],
:folders [:a :d],
:foldersize 0,
:totalfilesize 23352670}}
*edit, was some info missing#2022-12-0812:13oddsorMaybe you already figured it out, but I solved this by using postwalk.
I rebuild the hierarchy to contain an easily available size-parameter, which is used to add the folder’s size to the parent folders.
Note that my data structure looks like this so you’d need to modify the code a bit:
{"b.txt" 14848514,
"c.dat" 8504156,
"a" {"f" 29116, "g" 2557, "h.lst" 62596, "e" {"i" 584}},
"d" {"j" 4060174, "d.log" 8033020, "d.ext" 5626152, "k" 7214296}}
(defn assign-size-to-directories [tree]
(walk/postwalk (fn [node]
(if (map? node)
{:size (reduce + (concat
(filter number? (vals node))
(keep :size (vals node))))
:children node}
node))
tree))
#2022-12-0812:14Thierrythanks! ill have another look tomorrow when i have a day off#2022-12-0812:14oddsorResult:
{:size 48381165,
:children
{"b.txt" 14848514,
"c.dat" 8504156,
"a" {:size 94853, :children {"f" 29116, "g" 2557, "h.lst" 62596, "e" {:size 584, :children {"i" 584}}}},
"d" {:size 24933642, :children {"j" 4060174, "d.log" 8033020, "d.ext" 5626152, "k" 7214296}}}}
#2022-12-0912:19ThierryWith your tip I was able to finish day seven part one, thanks!#2022-12-0912:19ThierryI name the fn in my solution oddsor 😉#2022-12-0718:31noogaI refuse to adopt transducers, zippers and all those other quirky post-modern solutions... Simply because I don't have them in the language 😂#2022-12-0718:37borkdude@UJEK1RGJ0 what happens if you just copy/paste the source of map, etc in your language?#2022-12-0718:38noogait usually works but I need to cleaan up stuff relating to chunked & lazy seqs for now, also some clojure RT stuff has to be replaced if present#2022-12-0718:38noogabut some of the core fns just work#2022-12-0718:38noogaI've omitted the transducer arities though#2022-12-0718:39borkdudedo you re-implement core functions or execute them from source?#2022-12-0718:39noogawrote transduce
and mapt
, filtert
etc and it works#2022-12-0718:40noogawell 😅 I usually paste them over and remove 2/3 of the code and adjust the rest - I have no way to execute full core source atm#2022-12-0718:41borkdudewhat I mean, do you compile the source or have them built in go#2022-12-0718:41noogaaah, some of them are written in go, but many are already written in let-go#2022-12-0718:41borkdudeand does it pre-compile the stuff into the binary or are these functions compiled on the fly at startup?#2022-12-0718:42noogahttps://github.com/nooga/let-go/blob/main/pkg/rt/core/core.lg#2022-12-0718:42noogaeverything is compiled at startup atm, although it will not stay that way#2022-12-0718:43noogawhat I want to do is compile built-in NSes and take an image of the bytecode, then ship the interpreter with that image so it doesn't compile anything at boot#2022-12-0718:43borkduderight. image is just a byte array or so?#2022-12-0718:44borkdudemaybe there will be a .lgc or so with bytecode?#2022-12-0718:44noogayeah, that's the plan#2022-12-0718:45noogai.e. let-go -c foo -o foo.lgc
and then let-go foo.lgc
, or even (dump-image "foo.lgc")
from a REPL#2022-12-0718:45borkdudecool#2022-12-0718:46noogawhy you ask?#2022-12-0718:46borkdudeno reason, just wondering how you are doing things#2022-12-0718:47noogaI might actually look into this over the weekend#2022-12-0805:43normanDay 8 - Solutions#2022-12-0805:46normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day08/main.clj
Dumb mistake on part 1 where I tested if all trees in the direction were visible, not just if the one tree was visible. I had to go back to the sample input and write the map visual to catch the mistake. Lots of time lost. Wheee#2022-12-0806:43Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/08.clj
breaking out the grid helper functions from previous years 😌#2022-12-0806:44Andrew ByalaA little parsing, a couple of transducers... all normal stuff here.
• https://github.com/abyala/advent-2022-clojure/blob/main/docs/day08.md
• https://github.com/abyala/advent-2022-clojure/blob/main/src/advent_2022_clojure/day08.clj#2022-12-0808:44motformA bit verbose as always. This felt like an ur-aoc-problem, the kind of thing an AI would generate on prompt (not in a bad way, mind you).
https://github.com/motform/advent-of-clojure/blob/master/src/advent_of_clojure/2022/08.clj#2022-12-0809:10tylerwUsing clojure.core.matrix: https://github.com/tylerw/advent-of-code-2022/blob/master/src/aoc2022/day08.cljc#2022-12-0810:28genmeblogwith split-at
and split-with
today. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day08.clj#2022-12-0811:06babardohttps://github.com/v-garcia/aoc_2022/blob/main/day8.clj#2022-12-0811:32nbardiukI've over engineered again https://github.com/nbardiuk/adventofcode/blob/master/2022/src/day08.clj#2022-12-0811:52Felipehttps://github.com/FelipeCortez/advent-of-code/blob/master/2022/08.clj#2022-12-0812:36jon.ramoshttps://github.com/jramosg/advent-of-code/blob/master/src/advent_of_code/year_2022/day_08/main.clj#2022-12-0813:02Alekseduction
https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_08.clj#2022-12-0813:38R.A. PorterUgly as sin, and I realize this is not the first year that I've used meta
to track information like this in a grid: https://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day08.html#2022-12-0813:58Mark WardleOooo using clerk is nice @U01GXCWSRMW very pretty. Here is my effort, which seems overlong compared to the problem at hand. https://github.com/wardle/aoc2022/blob/main/src/day08.clj#2022-12-0814:49CaseyI used a map with [x y] as keys.. and then just a bunch of threading (like most of this month has been so far)
https://github.com/Ramblurr/advent-of-code-2022/blob/2bee95d7f45a4fb1572004882fb17d11b0aa82e7/src/aoc/day08.clj#L25-L59
got to pull out medley's take-upto
which I find I use surprisingly often.. I wonder why it's not in clojure.core#2022-12-0814:49Michael Ducharmcouldn't get yesterday's, so glad I was able to get today's. Starting to think that maybe it wasn't a good idea to pick AoC as my first introduction to clojure haha
https://github.com/mducharm/advent_of_code_2022/blob/main/src/advent_of_code/day_08.clj#2022-12-0815:23dogenpunkDay 8: https://github.com/dogenpunk/advent-of-code/blob/main/src/aoc22/day08.cljc#2022-12-0815:27bhaumanDay 8
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day8/sol.clj#2022-12-0900:12CarnunMPdefinitely late to the game today... with a rather ugly entry: https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d8.clj
now to read your solutions and realise what trick I missed! 😁#2022-12-0900:31CarnunMPOkay, for one: Every now and then I'm reminded how in problems like this it's much nicer and neater to move unit distances from some position, rather than keep track of long lists of positions to check. And I think, "That's really nice and neat!"
Then some time later it just leaks out of my ears, apparently. 🙃#2022-12-0900:33CarnunMPnice https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/grid.clj @U01HL2S0X71!#2022-12-0900:44CarnunMPanother TI(re-)L: range
can take a 'step'!
ty @UA2U3KW0L :))#2022-12-0912:25Felipe@U018D6NKRA4 np! I still feel weird when I have to inc/dec the end
#2022-12-0913:03Stuarthttps://github.com/stuartstein777/clj-advent-of-code/blob/master/src/stuartstein777/2022/day8.clj
Finally.
So, last night around 9pm. I started on part 2.
I was sure what I had was right and would work, and then was debugging it till just past 1am... I just couldn't find what I had wrong. I re-read the question and realised I had skipped the paragraph.
To measure the viewing distance from a given tree, look up, down, left, and right from that tree; stop if you reach an edge or at the first tree that is the same height or taller than the tree under consideration. (If a tree is right on the edge, at least one of its viewing distances will be zero.)
The Elves don't care about distant trees taller than those found by the rules above;
sigh
Anyway, I solved it by creating a grid like this of height and co-ordinate.
[[[3 [0 0]] [0 [0 1]] [3 [0 2]] [7 [0 3]] [3 [0 4]]]
[[2 [1 0]] [5 [1 1]] [5 [1 2]] [1 [1 3]] [2 [1 4]]]
[[6 [2 0]] [5 [2 1]] [3 [2 2]] [3 [2 3]] [2 [2 4]]]
[[3 [3 0]] [3 [3 1]] [5 [3 2]] [4 [3 3]] [9 [3 4]]]
[[3 [4 0]] [5 [4 1]] [3 [4 2]] [9 [4 3]] [0 [4 4]]]]
Then I could just deal with each row left -> right, because even after rotating the grid and reversing rows, I still had the original cell co-ordinates.#2022-12-0915:09mbjarland(ns aoc.day-08
(:require [clojure.string :refer [split]]))
(let [nd (mapv #(mapv (comp parse-long str) %) (split (slurp "../day_08.data") #"\n"))
td (apply mapv vector nd)
[my mx] [(dec (count nd)) (dec (count td))]
views (fn [y x] [(reverse (take x (nd y))) (drop (inc x) (nd y))
(reverse (take y (td x))) (drop (inc y) (td x))])
yxvs (for [y (range 1 my) x (range 1 mx)] [y x ((nd y) x)])
fn1 (fn [a [y x v]]
(if (some #(every? (partial > v) %) (views y x))
(inc a) a))
fn2 (fn [a [y x v]]
(let [dist #(if (< %2 v) (inc %) (reduced (inc %)))]
(max a (->> (views y x)
(map #(reduce dist 0 %))
(reduce *)))))]
(prn {:one (reduce fn1 (+ (* 2 my) (* 2 mx)) yxvs)
:two (reduce fn2 0 yxvs)}))
;{:one 1785, :two 345168}
#2022-12-1008:46pieterbreedLate to the party; here's the meat of the solution:
(defn d8-part-2-distance-can-see-in-direction
[direction]
(let [[this-h & rst] (direction)]
(->> rst
(take-until (fn [h] (>= h this-h)))
(count))))
(defn d8-viewing-distances [tree-map x y]
(let [{:heights/keys [north
south
west
east]}
(d8-heights-fns tree-map x y)]
(* (d8-part-2-distance-can-see-in-direction north)
(d8-part-2-distance-can-see-in-direction south)
(d8-part-2-distance-can-see-in-direction west)
(d8-part-2-distance-can-see-in-direction east))))
(defn d8-part-2-solve
[input]
(let [tree-map
(d8-parse-input input)
{:keys [height width]}
(d8-dimensions tree-map)]
(->> (for [x (range 1 (dec width))
y (range 1 (dec height))]
(d8-viewing-distances tree-map x y))
(sort)
(reverse)
(first))))
#2022-12-1021:59leinfinkhttps://github.com/leinfink/aoc-2022-clj/blob/main/src/aoc22/day8.clj#2022-12-1423:05peterhTrying to catch up, here is mine: https://github.clerk.garden/formsandlines/aoc2022-clojure/commit/73f80fe4c2b12eed7e92ba5d3863f27a180c1fef/src/advent_of_clerk/day_08.html
My approach was basically to loop over a grid, consisting of the input sequence in rows and a copy transposed to columns each mapped to coordinate-indices for easier lookups. The rows and columns are reversed to consume the grid from left, right, top and bottom at the same time in each iteration, while accumulating the visible trees (part 1) or the scenic scores for each tree (part 2) in a map.
I’ll have to check what others have done, there are certainly much simpler and more performant solutions.#2022-12-0821:02Apple(four-way or seen)
doesn't work#2022-12-0900:01noogaI just went with scanning each row and column both ways while obtaining the columns by transposition, then reducing the 2d result, it's dumb but it works 😄#2022-12-0900:02Appleit works and it's short. i love it.#2022-12-0901:37Apple(defn four-way [comb f]
(let [sides (fn [ts] (map comb (f ts) (reverse (f (reverse ts)))))]
(mapcat (partial map comb)
(map sides data)
(apply map list (map sides (apply mapv vector data))))))
(println "1:" (->> (four-way #(or % %2) seen) (filter true?) count))
(println "2:" (->> (four-way * scenic) (reduce max)))
save a few bytes.#2022-12-0902:10Apple(let [d (->> (slurp "resources/202208")
(re-seq #"[^\n]+")
(map #(->> (re-seq #"\d" %) (map parse-long))))
seen (fn [row]
(loop [[h & t] row, top -1, r []]
(if h
(recur t (max top h) (conj r (> h top)))
r)))
scenic (fn [row]
(loop [[h & t] row, r []]
(if h
(recur t
(let [l (count (take-while #(< % h) t))]
(conj r (if (= l (count t)) l (inc l)))))
r)))
four-way (fn [comb f]
(let [rowfn (fn [row] (map comb (f row) (reverse (f (reverse row)))))]
(mapcat (partial map comb)
(map rowfn d)
(apply map list (map rowfn (apply map list d))))))]
[(->> (four-way #(or % %2) seen) (filter true?) count)
(->> (four-way * scenic) (reduce max))])
minor improvement. count forward in scenic.#2022-12-0902:30AppleYour solution is not dumb at all. Efficient and elegant!#2022-12-0908:49noogathank you! 😊#2022-12-0915:25mbjarlandI went with reducing using coordinates, ugly but still manages to stay fairly concise (and below the 26 line limit : ):
(ns aoc.day-08
(:require [clojure.string :refer [split]]))
(let [nd (mapv #(mapv (comp parse-long str) %) (split (slurp "../day_08.data") #"\n"))
td (apply mapv vector nd)
[my mx] [(dec (count nd)) (dec (count td))]
views (fn [y x] [(reverse (take x (nd y))) (drop (inc x) (nd y))
(reverse (take y (td x))) (drop (inc y) (td x))])
yxvs (for [y (range 1 my) x (range 1 mx)] [y x ((nd y) x)])
fn1 (fn [a [y x v]]
(if (some #(every? (partial > v) %) (views y x))
(inc a) a))
fn2 (fn [a [y x v]]
(let [dist #(if (< %2 v) (inc %) (reduced (inc %)))]
(max a (->> (views y x)
(map #(reduce dist 0 %))
(reduce *)))))]
(prn {:one (reduce fn1 (+ (* 2 my) (* 2 mx)) yxvs)
:two (reduce fn2 0 yxvs)}))
;{:one 1785, :two 345168}
#2022-12-0915:27mbjarlandperformant it is not#2022-12-0915:30mbjarlandI feel like I get schooled every day by your solutions @UP82LQR9N#2022-12-0915:33mbjarlandchallenging myself and trying to find ways to cut a few bytes off your solutions @UP82LQR9N - a possible alternative to the reducing function for day 7 using fnil
and reductions
:
(defn parser [state [_ cmd path filesize]]
(if (= "cd" cmd)
(if (= path "..")
(update state :path pop)
(update state :path conj path))
(let [size (parse-long filesize)]
(reduce #(update-in %1 [:size %2] (fnil + 0) size)
state
(rest (reductions conj [] (:path state)))))))
#2022-12-0915:34mbjarlandalways wanted to use reductions
for something : )#2022-12-0915:35noogahey hey, this time I schooled @UP82LQR9N, not the other way round, then they schooled me on my solution though ;D#2022-12-0915:38mbjarlandah that was your solution @UJEK1RGJ0 ? well pardonne moi - I stand corrected, I get schooled by both of you : )#2022-12-0915:42Applelol#2022-12-0919:32nooga@U4VDXB2TU I see you like concise solutions. After day 2 I decided not to go above 26 lines as a challenge to myself. Maybe you'll be interested in my AoC repo: https://github.com/nooga/aoc2022#2022-12-0920:02Applehttps://github.com/nooga/let-go this is soooooooooooo cool!#2022-12-0920:04noogathanks! but use at your own risk 😅 I wouldn't call it remotely mature and the similarity to Clojure is superficial at the moment 😉#2022-12-1012:49mbjarlandThanks for the repo @UJEK1RGJ0!#2022-12-1014:05mbjarlandwow chatgpt is freaky#2022-12-0905:01Joseph DumontI'm learning so much from all your solutions! Thanks for posting everyone. A quick question from a day8 function I saw:
(defn visible?
[[tree & other-trees]]
(every? #(< % tree) other-trees))
This captures edges too without needing a single arity version, e.g. (visible? [3]) ;;=> true
but it's unclear to me what is happening with every? and the comparison when there's no other value to compare with. It's clearly not equivalent to (< (rest [3]) 3)
.#2022-12-0907:11pezother-trees
will be nil
when there are no args to destruct there. A way to investigate things like this is to use ”inline def”.
(defn visible?
[[tree & other-trees]]
(def tree tree)
(def other-trees other-trees)
(every? #(< % tree) other-trees))
Then call the function:
(visible? [3])
Then evaluate other-trees
in the REPL.#2022-12-0908:17Joseph DumontThanks for the response. I understand other-trees will be nil, but I don't understand how it doesn't reduce to the comparison (< nil 3)
and a NullPointerException, and what every? does with it.#2022-12-0908:19pezCheck out https://clojuredocs.org/clojure.core/every_q. In fact, I added a think about nil
there just a few days ago, because it surprised me too.#2022-12-0908:21Joseph DumontAha! "vacuous truth"#2022-12-0908:23pezYeah, ChatGPT warns about it too 😃#2022-12-0908:33pezChatGPT's mix of things that makes sense and pure bullshit is interesting!#2022-12-0917:09erwinrooijakkers#2022-12-0906:55pezThe hypocrisy of i using eval
by other names, such as read-string
, is going on to this day, though.#2022-12-0907:51jumarQuite good except the slow performance of Java land#2022-12-0910:47noogahehe, I don't even have eval in my implementation#2022-12-0910:47nooganot because it's hard to make, it's actually trivial, I just don't want to include it#2022-12-0910:52pezNo free will in your kingdom, @UJEK1RGJ0? 😃#2022-12-0910:53noogait's an edn#2022-12-0911:04pezDidn't see that one coming!#2022-12-0914:59nooga> toiling in obscurity
is what you do in Java land apparently 😂#2022-12-0907:19Andrew ByalaDay 9 - Solutions#2022-12-0907:20Andrew ByalaAm I the only fool staying up late to code this and document it? Oh well, so be it! Fun puzzle today. 🙂
• https://github.com/abyala/advent-2022-clojure/blob/main/docs/day09.md
• https://github.com/abyala/advent-2022-clojure/blob/main/src/advent_2022_clojure/day09.clj#2022-12-0907:33Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/09.clj
early rather than late for me! agreed this was a fun one. getting more interesting now#2022-12-0907:39normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day09/main.clj
No - I stayed up too. I completely misunderstood the tail following head algorithm, but what I did worked for all sample inputs and the full input on part1 but not on part 2. After re-reading for the 47th time I finally figured out what I was doing wrong. uggghh.... I applies zero cleanup here, so it's a total mess#2022-12-0908:09nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2022/src/day09.clj#2022-12-0910:18macNow contains both parts.
https://gist.github.com/maacl/992c94a6000ae1ae206a926eccd34294#file-clj#2022-12-0910:29Eugene Huang👋 new clojurian here. after a rough day 8, am decently pleased with my solution today. happy for any notes!
https://github.com/elh/advent-2022/blob/main/src/advent_2022/day_09.clj#2022-12-0910:55tschadyI reused my grid/moves->path
function which takes the input and returns all coords visited, made this trivial. Each subsequent knot treats the earlier knot like the head, so iterate
works nicely. Refactored with core.matrix, thanks @U02CV2P4J6S
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d09.clj#2022-12-0911:16CaseyMore verbose than I would like.. but I'm not golfing after all. https://github.com/Ramblurr/advent-of-code-2022/blob/main/src/aoc/day09.clj#2022-12-0911:40Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day9.clj (formatted it) feeling ultra clever today#2022-12-0911:45tschady@U02CV2P4J6S nice idea, I’m going to replace some of my vector helpers with core.matrix/{+,-}
now.#2022-12-0912:21Felipehad a total brain freeze for some 10 minutes trying to come up with the generalized step fn reduction
https://github.com/FelipeCortez/advent-of-code/blob/master/2022/09.clj#2022-12-0912:30Felipe@U01HL2S0X71 shouldn't make much of a difference here but last
is linear, peek
is constant https://github.com/callum-oakley/advent-of-code/blob/b562459233253a8de222e96cc17de2af6e3a040d/src/aoc/2022/09.clj#L28e#2022-12-0912:46Callum Oakley@UA2U3KW0L good catch, thanks! cuts the time almost in half 😁 (from 200ms to 100ms)#2022-12-0912:52Felipeooo, nice!#2022-12-0915:21Andrew ByalaI like your move-rope
implementation, @U076FM90B, since I was reducing over the indexes of my knot vector and calling update
for the values in place. I think your reduce
with conj
of a new vector is a much cleaner solution. Once I update my blog, I think I'll be following suit!#2022-12-0915:36Alex Alemihttps://github.com/alexalemi/advent/blob/main/2022/clojure/p09.clj#2022-12-0915:38Alex AlemiI took a shortcut for part 1 that slowed me down for part 2. In part one since the head only moves up down left or right, the tail, if it moves always takes the old head position. This doesn't work for part two though as intermediate knots might move diagonally.#2022-12-0916:30Alekshere we go
https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_09.clj#2022-12-0916:56Aleks@U076FM90B as usual like your solution especially when it comes to moving something ^_^
btw, just checked that clojure.math
has signum
.#2022-12-0916:58nbardiuk@U067R559Q cool! I've never seen it TIL
. Will try to integrate into next solutions#2022-12-0918:06Mark WardleYikes. Wasn't sure I liked this today. Bizarrely, my solution to the second part is simpler and more general purpose (configurable numbers of knots) than my solution to the second part! One of those times knowing the second part would have helped! https://github.com/wardle/aoc2022/blob/main/src/day09.clj#2022-12-0918:15Mark WardleThink I need to learn 'iterate' given the posted solutions above!#2022-12-0918:17Piotr KaznowskiDidn't know the clojure.core.matrix
so had to reinvent some wheels, it's not super readable though:
(defn -mapf [fc ac] (mapv #(%1 %2) fc ac))
(defn follow [H T]
(let [diff (map - H T)]
(if (> (apply max (map abs diff)) 1)
(let [fx (map #(cond (> % 0) inc (< % 0) dec :else *) diff)] (-mapf fx T))
T)))
(defn solve [input len]
(-> (reduce
(fn [{p :pos :as g} [m s]]
(let [go (partial -mapf ((zipmap ["R" "L" "U" "D"] [[inc *] [dec *] [* inc] [* dec]]) m))]
(loop [p p, n (parse-long s), g g]
(if (zero? n) (assoc g :pos p)
(let [np (reduce #(conj %1 (follow (last %1) %2)) [(go (first p))] (rest p))]
(recur np (dec n) (update g :vis #(conj % (last np)))))))))
{:pos (repeat len [0 0]), :vis #{[0 0]}} input)
:vis count))
(defn -main [day]
(let [solution (->> (file->str day) (re-seq #"\w+") (partition 2) (partial solve))]
{:part1 (solution 2) :part2 (solution 10)}))
#2022-12-0918:21bhaumanDay 9
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day9/sol.clj#2022-12-0918:22noogawhew, slightly ugly but here it goes:
(ns day9)
(def dirs {"U" [0 -1] "D" [0 1] "R" [1 0] "L" [-1 0]})
(def data (->> "input/day9.txt" slurp lines
(mapcat #(let [[d n] (split % " ")] (repeat (parse-long n) (dirs d))))
(reductions #(mapv + %1 %2) [0 0])))
(defn next-pos [[tx ty] [hx hy]]
(let [sign (fn [x] (cond (zero? x) x (< x 0) -1 :else 1))]
(if (or (-> tx (- hx) abs (> 1)) (-> ty (- hy) abs (> 1)))
[(+ tx (sign (- hx tx))) (+ ty (sign (- hy ty)))]
[tx ty])))
(let [paths (iterate (partial reductions next-pos) data)]
(println "1:" (->> paths second (map str) set count))
(println "2:" (->> (nth paths 9) (map str) set count)))
nailing next-pos
took me ages cause I've made a dumb assumption#2022-12-0918:23Piotr KaznowskiDefinitely need to learn how reductions
work...#2022-12-0918:24Mark WardleMe too! Great to see other people's solutions for ideas!#2022-12-0918:24noogaalso, my sets don't like vectors so I had to (map str)
, it wouldn't be needed in Clojure#2022-12-0918:25bhaumanreductions is like reduce but it returns each step#2022-12-0918:25bhaumanso in the case of the snake of positions you only have to keep the last position in the accumulator#2022-12-0918:25Mark WardleYes I see - I went through contortions to track each step in my 'reduce' which would have been unnecessary!#2022-12-0918:26Piotr KaznowskiYup, that would make my solution much simpler#2022-12-0918:26bhaumanyeah I get it, it took me a minute to see the mapping to reductions#2022-12-0918:28Mark WardleI feel I would be cheating now to change it, but will keep in mind for coming days. That said, I am not sure I can look at my day 9 code and not change it... ! 😂#2022-12-0918:32bhaumanHey if it’s in git, everyone can see the history….. so change away. That’s what I do anyway. It’s not that often that you can have this much fun coding, so I say maximize the fun and experimenting.#2022-12-0918:32noogayou know what helps? implementing the core functions as you solve#2022-12-0918:32bhaumanLOL#2022-12-0918:32noogayou learn a ton this way#2022-12-0918:33bhaumanyeah I bet#2022-12-0918:35wevremI came up with my own solution this morning, but looking over others I like some of the simpler approaches (i.e. reductions instead of loop/recur). Maybe I’ll go back and re-factor, but good enough for now.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_09_rope_snake.clj#2022-12-0919:45tschadyAn advantage to iterate/reductions is you have all this step-wise data for the visualizations that you’ll never make#2022-12-0920:00Mark WardleRight... this is very much simpler - TIL reductions
is a super power. Updated code, still can be improved but good enough. https://github.com/wardle/aoc2022/blob/main/src/day09.clj#2022-12-0920:07leinfinkHaha, I had just discovered reductions
today also!
https://github.com/leinfink/aoc-2022-clj/blob/main/src/aoc22/day9.clj#2022-12-0920:09leinfinkNearly got crazy until I realised it had \d
instead of \d+
in my regex so the latter parts of the input failed to parse correctly...#2022-12-0920:12leinfinkReading through here, I wonder why it didn't occur to me to use reductions for the tail itself, and not just for the intermediate knots, as I did? :face_with_raised_eyebrow: Oh well, happy with my result 😇#2022-12-0922:18R.A. PorterBlergh. What an ugly solution I’ve written today.
https://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day09.html#2022-12-0922:21Applecheck if they are touching/overlap/neighbor
neighbor? (fn [xy1 xy2] (every? #{-1, 0, 1} (map - xy1 xy2)))
catch up to previous knot
(->> (map - prev curr)
(map #({2 1, -2 -1} % 0))
(map - prev))
#2022-12-0922:47CarnunMPHappy Friday yous lot :))
I had fun taking https://github.com/mikera/core.matrix for a spin, for the first time!
https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d9.clj#2022-12-0923:30noogahttps://clojurians.slack.com/archives/C0GLTDB2T/p1670624488987059?thread_ts=1670570395.443139&cid=C0GLTDB2T oh that could clean up my next-pos
nicely, thanks Apple#2022-12-1007:13Aleks@UP82LQR9N what a nice and neat solution#2022-12-1014:37MaxI thought this ended up being rather pretty#2022-12-1118:19genmeblogEventually made it https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day09.clj#2022-12-1118:20genmeblogAlso visualized how to knots travel. First knot and ninth knot (blues are knots from 1-8)#2022-12-1118:50genmeblogjust for fun, rope with 100 knots 🙂#2022-12-1119:42nbardiukthis visualization reminds me that people come up with part 3: what's the smallest number of knots such that the tail knot doesn't move
https://www.reddit.com/r/adventofcode/comments/zgre9m/2022_day_9_bonus_mini_problem_only_try_after_part/#2022-12-1119:59genmeblog426 in my case...#2022-12-1610:11mbjarlandvery late to the game but finally got around to finishing day 09:
(ns aoc.day-09)
(let [ds {\L [0 -1] \R [0 1] \U [-1 0] \D [1 0]}
parse (fn [a [d n]] (concat a (repeat (parse-long n) (ds (first d)))))
data (reduce parse [] (partition 2 (re-seq #"\w+" (slurp "data/2022_09"))))
head (reductions #(mapv + %1 %2) [0 0] data)
rope (fn [[y x :as t] h]
(let [[dy dx] (map - h t)
tx {0 0 2 1 -2 -1}]
[(+ y (tx dy ({2 dy} (abs dx) 0))) (+ x (tx dx ({2 dx} (abs dy) 0)))]))
tail #(reductions rope [0 0] %)]
(prn {:one (count (distinct (tail head)))
:two (count (distinct (nth (iterate #(tail %) head) 9)))}))
#2022-12-1701:48peterhSame here. I also made a visualization, mainly to verify my solution and because I want to get used to writing SVG. However, ran into stack overflow with the actual data, so I guess canvas would have been a better choice here. 🙂
https://github.clerk.garden/formsandlines/aoc2022-clojure/commit/a068cdff5c85be281f7bf550313d5e9a2b05d573/src/advent_of_clerk/day_09.html#2022-12-1719:35peterhOmg, reductions
would have made my life so much easier (it seems like I am not the only one, looking at this thread). Also, I really like the approach of using map
for simple vector math that I have seen in some solutions. I also have to remember to make more clever use of default values in collection getters.#2022-12-0914:41CaseyAnyone know if there's an easy way to pair clerk and quil for simple web based visualizations?#2022-12-0915:13nbardiukmaybe people in #C035GRLJEP8 can help. I guess there should be a way to assign custom visualiser for data based on its metadata, but I haven't looked into it.#2022-12-0922:12Sam RitchieI think Quil has been lagging way behind on jvm versions… it only works on jdk8 etc as far as I know#2022-12-0922:12Sam Ritchiebut if you are interested in Mathbox I can get you set up with Clerk and mathbox! https://mathbox.mentat.org/#2022-12-0922:13Sam Ritchiemathbox examples: https://mathbox.org/#2022-12-1416:17Casey> I think Quil has been lagging way behind on jvm versions… it only works on jdk8 etc as far as I know
Oh that's sad.. I haven't used it in quite a few years. But I thought it might be fun to use with this years AOC since there are some cool animated visualizations one can do. And since I've been using Clerk notebooks for AoC I thought it would be cool to pair them. I've also never used Quil in a web browser context, so not sure how that would work#2022-12-1417:02Sam RitchieActually!! That might be totally fine since the cljs side uses p5.js which is up to date #2022-12-0921:01noogawut#2022-12-0921:11genmeblogIs this your code? Now you know the truth...#2022-12-0921:13noogayes, this is my code from day 2#2022-12-0921:16AppleChatGPT likes you! I ask it what's the date today and all I get is 'no data', 'trained till 2021'#2022-12-0921:28kenjI wonder if changing "day2" to something else would be enough to throw it off#2022-12-0921:50Marcelo FernandesI pasted the solution for my day 5 and asked for it to explain in human terms what it was doing. Not only did it figure out that it was an Advent of Code Day 5 solution (good namespace?) but also explained what the code was doing using words such as warehouse that weren't present in the solution.
https://github.com/marceloschreiber/advent-of-code-clojure/tree/main/src/aoc/2022/day_05 (kind of hard to read)#2022-12-0923:28noogaall that while it stopped learning in 2021#2022-12-0923:28noogaI fear for my job in 5 years#2022-12-0923:28nooganot now, but 5 years is enough, maybe we should all jump on the AI train 😂#2022-12-1014:12mbjarlandI asked chatgpt to opimtize some clojure core functions…came back with some interesting reasoning#2022-12-1005:37normanDay 10 - Solutions#2022-12-1005:38normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day10main.clj#2022-12-1005:57Apple;; 202210
(let [pos [20 60 100 140 180 220]
d (->> (slurp "resources/202210") (re-seq #"(addx) (-?\d+)|(noop)")
(reduce (fn [r [_ addx val noop]]
(let [v (peek r)]
(if addx
(conj r v (+ v (parse-long val)))
(conj r v))))
[1]))
f (fn [i v] (if (<= -1 (- v (mod i 40)) 1) "▓" "░"))]
(->> (map-indexed f d)
(partition 40)
(mapv (comp println str/join)))
(->> (map (comp d dec) pos) (map * pos) (reduce +)))
;; ▓▓▓░░▓▓▓▓░░▓▓░░▓▓▓░░▓░░▓░▓▓▓░░▓▓▓▓░▓▓▓░░
;; ▓░░▓░░░░▓░▓░░▓░▓░░▓░▓░▓░░▓░░▓░▓░░░░▓░░▓░
;; ▓░░▓░░░▓░░▓░░░░▓░░▓░▓▓░░░▓░░▓░▓▓▓░░▓▓▓░░
;; ▓▓▓░░░▓░░░▓░▓▓░▓▓▓░░▓░▓░░▓▓▓░░▓░░░░▓░░▓░
;; ▓░░░░▓░░░░▓░░▓░▓░░░░▓░▓░░▓░░░░▓░░░░▓░░▓░
;; ▓░░░░▓▓▓▓░░▓▓▓░▓░░░░▓░░▓░▓░░░░▓▓▓▓░▓▓▓░░
;; 13680
#2022-12-1006:53Alekshttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_10.clj#2022-12-1007:05Aleks6) 3360 ********** Nazarii Bardiuk
7) 3360 ********** Aleksandr Zhuravlёv
😁#2022-12-1007:30nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2022/src/day10.clj#2022-12-1007:47Joseph DumontI learned reduction
from yesterday and got to use it, but unfortunately I used flatten
so I'll probably have to rework it to avoid the curse. https://gist.github.com/iwrotesomecode/64da2ce8702d62d5557f030ce1752131#2022-12-1007:51nbardiuk@U03KMPFU4TH you can replace map
+ flatten
with mapcat
which concatenates sequences produced by map
into single sequence#2022-12-1007:52Joseph DumontAh yes! Thank you for saving me from dismay, @U076FM90B#2022-12-1008:11tylerwhttps://github.com/tylerw/advent-of-code-2022/blob/master/src/aoc2022/day10.cljc#2022-12-1008:12tylerwProbably would've done things differently had I known what part 2 was.#2022-12-1008:22tschadyMunge the string, eval, reductions:
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d10.clj#2022-12-1009:54Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day10.clj
thought I had a cool solution, after seeing @UP82LQR9N and @U1Z392WMQ I feel humbled and educated.#2022-12-1012:18nooga(ns day10)
(def data (->> "input/day10.txt" slurp lines
(mapcat #(if (= % "noop") [0] [0 (-> % (split " ") second parse-long)]))
(reductions + 1)))
(println "1:" (reduce + (map #(* % (nth data (dec %))) (range 20 260 40))))
(doseq [l (->> data (map-indexed #(if (-> %2 (- (mod %1 40)) abs (<= 1)) "#" ".")) (partition 40))]
(println "2:" (apply str l)))
#2022-12-1012:28zamanskyMissed the last two days - too much work but this one was fun.
https://github.com/zamansky/advent2022/blob/main/src/day10.clj#2022-12-1013:19babardohttps://github.com/v-garcia/aoc_2022/blob/main/day10.clj#2022-12-1013:32Aleks@U1Z392WMQ made your parsing function a little bit less dangerous 😅
(defn parse-input [input]
(->> (str/replace input #"noop|addx" "0")
(str "1 ") ; add init state
(aoc/parse-longs)
(reductions +)))
#2022-12-1013:33tschadyweakness!#2022-12-1013:35Vincent OlesenUsed match
which turned out nice. Tried out using reductions, but simply reducing over the instructions and adding two register States for addx
seemed simpler, as my goal was to collect register states for every cycle. https://github.com/volesen/aoc2022/blob/main/day10/day10.clj#2022-12-1013:58tschadyfine, less dangerous, less fun, more readable:
(defn reg-series [input]
(let [deltas (-> input (str/replace #"noop|addx" "0") s/ints)]
(reductions + 1 deltas)))
(defn part-1 [input]
(->> [20 60 100 140 180 220]
(map #(* % (nth (reg-series input) (dec %))))
(reduce +)))
(defn draw-pixel [cursor cycle]
(let [dist (abs (- (mod cursor 40) cycle))]
(if (<= dist 1) \# \.)))
(defn part-2 [input]
(->> (reg-series input)
(map-indexed draw-pixel)
(partition 40)
(map (partial apply str))))
#2022-12-1013:59tschady:til: abs
is in Clojure 1.11#2022-12-1014:53Felipehttps://github.com/FelipeCortez/advent-of-code/blob/master/2022/10.clj#2022-12-1014:55FelipeI wonder if I have an off-by-one error somewhere or this just looks hard to read#2022-12-1014:57nbardiuktry changing (<= (dec x) (mod cycle 40) (+ x 2))
to (<= (dec x) (mod cycle 40) (+ x 1))
the size of sprite is 3 and x
is in the middle#2022-12-1014:58Felipe@U076FM90B ahhhh yeah, now it looks perfect#2022-12-1014:58Felipethanks!#2022-12-1015:37mac@U1Z392WMQ (str/replace #"(noop|addx)" "0"))
- that's clever.#2022-12-1015:53leinfinkhttps://github.com/leinfink/aoc-2022-clj/blob/main/src/aoc22/day10.clj#2022-12-1016:35leinfinkI kinda assumed that part2 would involve different commands and command-durations...#2022-12-1016:45bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day10/sol.clj#2022-12-1016:56bhauman@U1Z392WMQ has my favorite solution. So a big thumbs up there!#2022-12-1016:58noogayep, i took similar approach but theirs is less cryptic ➕#2022-12-1016:59bhaumanwell you could add some newlines… help a reader out!#2022-12-1017:02nooga(ns day10)
(def data (->> "input/day10.txt" slurp lines
(mapcat #(if (= % "noop")
[0]
[0 (-> % (split " ") second parse-long)]))
(reductions + 1)))
(println "1:" (reduce + (map #(* % (nth data (dec %)))
(range 20 260 40))))
(doseq [l (->> data
(map-indexed #(if (-> %2 (- (mod %1 40)) abs (<= 1))
"#"
"."))
(partition 40))]
(println "2:" (apply str l)))
#2022-12-1017:02tschadyI just did a bad thing, new elfscript
library :coral:
(defn part-2 [input]
(->> (reg-series input)
(map-indexed draw-pixel)
(partition 40)
(map (partial apply str))
(elfscript/ocr)))
#_(part-2 input); "FCJAPJRE"
#2022-12-1017:02bhauman@UJEK1RGJ0 oh yeah it is the same#2022-12-1017:03nooga@U1Z392WMQ had a better idea about parsing the input though#2022-12-1017:03bhaumanSo you just piped it to chatgpt eh?#2022-12-1017:03bhaumanfor the OCR 😉#2022-12-1017:05bhauman(->> (edn/read-string (str "[" (slurp "src/adv2022/day10/input.txt") "]"))
(map #(if (symbol? %1) 0 %1))
(reductions + 1))
;; this is a take on the solution by @tschady
#2022-12-1017:06noogawell, I don't have read-string and anything like that so I need to parse "by hand"#2022-12-1017:07bhaumanoh I get it, I’m iterating on the idea#2022-12-1017:09bhaumanhmmmm seems like you already have a reader in there. oh but is it a compiled lexer or something?#2022-12-1017:29noogayou mean in let-go? well I have a full clojure reader written in Go, but it's not callable from the language itself#2022-12-1017:58wevremI’m happy with my solution. The one trick I like from @U1Z392WMQ is replacing 'addx
and 'noop
with 0.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_10_signals.clj#2022-12-1018:00Aleks(cycle (range 40))
— makes it even more functionalish#2022-12-1018:29wevremOkay, I was happy with my solution, for, like, 3 seconds. But I pushed the “replace instruction with 0” trick from @U1Z392WMQ a little further and did some refactoring for something even simpler. I remembered I had written a common/parse-longs
method from prior years, which lets me drop edn/read-string
and I also did less math, meaning I don’t rely as much on mod
and abs
and more on mapping indices (-1, 0, 1) to characters. That was a trick I saw you geniuses using for the rope problem from yesterday and I think it is a good fit for these problems that are simple integer x- and y-coordinates.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_10_signals.clj#2022-12-1018:31bhaumanThat’s very readable#2022-12-1018:33Mark WardleForgot to post. Like someone else in this thread, I thought part 2 might have lots of additional commands, so overengineered using multi methods. Using advice from prior days, reductions remains a superpower. https://github.com/wardle/aoc2022/blob/main/src/day10.clj#2022-12-1018:35Mark WardleCan’t imagine the mess I’d create if using Java to solve these, and the need to refactor entirely when part 2 isn’t what you expect. #2022-12-1018:38Alex AlemiNot nearly as concise as the other ones here: https://github.clerk.garden/alexalemi/clerktudes/commit/85191e17481bf7a2dc7d441d14df5cfa4977d858/notebooks/advent-2022-10.html I built a lazy-seq
of the cycles of the machine, simple transducer for part 1, some threading for part 2.#2022-12-1019:01chuckleheadmight not be the most time I've spent on a captcha, but it has to be close#2022-12-1019:45Apple"▓" "░" looks nicer give it a try#2022-12-1020:52potetmhttps://github.com/potetm/advent-of-code/blob/master/src/advent_2022/day_10.clj#2022-12-1020:53CarnunMPfun day! https://github.com/CarnunMP/Advent-of-Code/blob/master/src/y2022/d10.clj#2022-12-1101:44bhaumanIt might be interesting to distill the lessons all of the years of AOC contests into a combinator style DSL for solving these problems. Oh wait we already have that …#2022-12-1115:13Felipe@bhauman yeah, this crazy one is 12k lines long! https://github.com/betaveros/noulith/blob/main/src/lib.rs#2022-12-1120:42genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day10.clj#2022-12-1221:00StuartMy day 10
https://github.com/stuartstein777/clj-advent-of-code/blob/master/src/stuartstein777/2022/day10.clj#2022-12-1015:07Felipe(updated the year)#2022-12-1017:04tschadyNote: this is not open source software. I want $5000 USD for a 1 year license.
(elfscript/ocr)
https://github.com/tschady/advent-of-code/blob/main/src/aoc/elfscript.clj#2022-12-1017:07bhaumanwell that’s pretty crappy deal, but if you had all the letters then we’re talking …#2022-12-1017:14tschadyOK, $10k for @bhauman, $5k for everybody else#2022-12-1017:15bhaumanman once a software developer gets a little power ….#2022-12-1017:15tschadyI actually think this is the full set, I pulled a few years input from a handful of people#2022-12-1017:18bhaumanyeah the missing ones aren’t drawable in these constraints perhaps, too bad about the license though 😉#2022-12-1017:21bhaumanThe Elfscript license: This software is only free if used between the days of Dec 1 to 25th EST. Beyond that its $1000 per render. (There is an online API renderer, that’s only $5 a month)#2022-12-1017:24Alekslovely visualization https://www.reddit.com/r/adventofcode/comments/zhmsg2/2022_day_10_sprites_and_not_the_elf_kind/#2022-12-1101:44bhauman#2022-12-1106:10ryan echternachtAnyone have thoughts on the handling the massive numbers generated by day 11?#2022-12-1106:10ryan echternachtthis is definitely where I'm weakest for AOC#2022-12-1106:19Andrew ByalaI really dislike these puzzles. About to search the Googles for someone who cares more about finding the trick than I. 🙂#2022-12-1106:21Andrew ByalaIt has something to do with the fact that all of the "divisible by" tests are with prime numbers.#2022-12-1106:30Andrew ByalaGot it. It's related to the Chinese Remainder Theorem. I don't remember exactly how it works, but this is what I did:
When reducing your worry, for part 1, do what you did.
For part 2, take the remainder of your item worry amount by the product of all of the test divisors across all monkeys.#2022-12-1106:50Applethx for the tip. problem solved!#2022-12-1106:51Andrew ByalaWoot!#2022-12-1107:49robertfwThanks for the tip!#2022-12-1108:29wevremI don’t think this is related to Chinese Remainder Theorem. At least, you don’t apply the Chinese Remainder Theorem in order to solve it. The trick is we can reduce the large numbers modulo the LCM of all the monkey’s divisors, without invalidating any of the monkey’s division checks. The monkey’s divisors don’t need to be prime for this modulo LCM approach to work. But since they are all prime, the LCM is simply the product.
The CRT, btw, is about finding a number that satisfies a set of remainder constraints, whereas this problem is about divisibility constraints.#2022-12-1109:23Callum Oakleyimagine instead that there was only one check: “is the worry divisible by 12?” then it’s fairly clear that there’s no reason to store worry greater than 12, you can apply mod 12 after every step since it doesn’t change the result of the test.
we can do something similar with multiple tests, but we have to find a mod to apply which won’t change the results of any of the tests. this needs to be a number that is divisible by all the tests, the smallest of which is the LCM (but any common multiple will do)#2022-12-1110:41AleksI wonder is there some other way to solve it within reasonable time?#2022-12-1112:23Callum OakleyI’d imagine not. napkin justification:
I assume all the inputs have the new = old * old
operation. say an item hits that operation every 10 rounds, then in 10000 rounds you square an items worry 1000 times, which if an item starts with worry 2 lands you with worries of
2^2^1000
which is an absurdly astronomical number (about 3x10^300 digits)#2022-12-1115:06marcofisetI genuinely enjoyed today's problem, I think it may be my favorite this year so far... except for part 2 😄#2022-12-1116:31FelipeI thought I had understood how the modulo thing works, but I still can't explain why ((big-x mod y) * (big-x mod y)) divisible by z
is equivalent to (big-x * big-x) mod y divisible by z
#2022-12-1116:46Felipeok got it https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/modular-multiplication#2022-12-1107:10normanDay 11 - Solutions#2022-12-1107:15normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day11/main.clj
I really don't enjoy the aoc problems that have a math trick in them. Thankfully this was a somewhat obvious one, but still...#2022-12-1107:28wevremRan fast enough with memoization.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_11_monkeys.clj
[Edit] — had to go back and make sure sample puzzles (with only 4 monkeys instead of 8) also worked.#2022-12-1107:58Andrew ByalaWrite-up complete. May this be the only "you'll never get it if you don't know the gimmick" problem of the season!
• https://github.com/abyala/advent-2022-clojure/blob/main/docs/day11.md
• https://github.com/abyala/advent-2022-clojure/blob/main/src/advent_2022_clojure/day11.clj#2022-12-1109:13Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/11.clj
I’ll take maths tricks over “reverse engineer this pseudo assembly” any day 😅#2022-12-1110:55Alekshttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_11.clj#2022-12-1110:56Aleks@U01HHBJ56J1 my code is pretty the same as yours this time 🙂#2022-12-1110:57Alekshate the problems which require modulo arithmetic knowledge#2022-12-1112:58tschadyVery similar to some above, I think we’re influencing each other?
I don’t like my parse-op
yet.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d11.clj#2022-12-1113:49tschadyAOC rule #7: if the numbers get too big, there’s a mod with primes#2022-12-1114:02CaseyHad to learn the trick from the other thread 😞 Not a big fan of the math trick ones. Not my best today.
https://github.com/Ramblurr/advent-of-code/blob/main/src/aoc/2022/day11.clj#2022-12-1114:04Alekspracticed in writing a better op
fn, dnk how to make it better
(defn make-op-fn [s]
(let [[_ _ x op y] (->> s (re-seq #"\w+|\+|\*") (map symbol))]
(-> (list 'fn [x] (list op x (cond-> y (not= x y) (-> name parse-long))))
(eval))))
((make-op-fn "Operation: new = old * 3") 5) ; => 15
((make-op-fn "Operation: new = old + 5") 5) ; => 10
((make-op-fn "Operation: new = old + old") 21) ; => 42
#2022-12-1115:07Felipetook me ~2 hours to finally get the trick after I realized all the div checks were for primes. first idea was to store the factorization of the number, but that wouldn't work with sums. turns out it was much simpler than that https://github.com/FelipeCortez/advent-of-code/blob/master/2022/11.clj#2022-12-1115:23Vincent OlesenWas happy with the parsing, but I think round
could need a cleanup. https://github.com/volesen/aoc2022/blob/main/day11/day11.clj#2022-12-1116:07Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day11-part2.clj messy, part 2 in a separate file.#2022-12-1117:54Callum Oakley@U067R559Q rather than parsing everything to symbols and then re-parsing the numbers as longs, you could read-string
from the start? I’d never touch it in production code, so it’s easy to forget that it exists, but I find it really useful for AoC. this is what I ended up with:
(let [[a op b] (map read-string (re-seq #"old|\+|\*|\d+" line))]
(eval (list 'fn ['old] (list op a b))))
#2022-12-1118:04zamanskyAdd me to the didn't love today club. My solution like a lot of others here -
Solved part 1 just using straightforward simulation as others have.
Wrote and tested part 2 using mod on he product of the test divisors (also as others have done).
Started it running and waited.
And waited
Started to try to figure out how to improve things when I got an answer and entered it.
On a lark, I decided to run the code through Babashka for a lark. The part 2 solution that took minutes and minutes completed in half a second 🙂#2022-12-1120:11Joseph Dumont@U04575QMU2K I like your simple and self-documenting parsing strategy.#2022-12-1122:45Alex AlemiSome confessions for today. Originally I skipped writing a parser and just wrote some edn for my input (though I've gone back and written a parser), and second instead of generalizing my solution and piping through the worry-manager
, I just made it a var and used a binding
to set it to mod appropriately for part-2. Not sure how guilty I should feel about that second one. https://github.com/alexalemi/advent/blob/main/2022/clojure/p11.clj#2022-12-1201:13bhaumanGeez that sucked
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day11/sol.clj#2022-12-1203:33bhaumanyeah, its tough moving one mental model of AOC from pure data structure manipulation to this type of solution, anyone else implement these?
(defn modulo* [a b m]
(mod (* (mod a m) (mod b m)) m))
(defn modulo+ [a b m]
(mod (+ (mod a m) (mod b m)) m)
#2022-12-1203:33bhaumanhad to look them up#2022-12-1204:25wevrem@U064J0EFR well maybe it sucked, but hey you had occasion to write a function called monkey-around
😆 #2022-12-1210:30genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day11.clj#2022-12-1610:13mbjarland(ns aoc.day-11
(:require [clojure.string :refer [join split]]))
(defn parser [acc [_ & r]]
(let [is (drop-last 4 r)
[[o _ & a] d t f] (take-last 4 r)
a (when (not= (first a) \o) (parse-long (join a)))]
(conj acc {:is (vec is) ;; items
:ac 0 ;; activation count
:dv d ;; divisor
:op #(({\+ + \* *} o) % (or a %)) ;; operation
:tx #(if (zero? (mod % d)) t f)}))) ;; transfer
(let [data (->> (split (slurp "data/2022_11") #"\n\n")
(map #(re-seq #"[*+] ?(?:\d+|old)|[\d]+" %))
(map (fn [c] (map #(or (parse-long %) %) c)))
(reduce parser []))
ixs (range (count data))
mod* (reduce * (map :dv data)) ;; limit int sizes, mod with * of dv
turn (fn [d ms mi]
(let [{:keys [op tx is]} (nth ms mi)
throw (fn [a i]
(let [i (mod (quot (op i) d) mod*)
di (tx i)]
(-> (update-in a [mi :is] (comp vec rest))
(update-in [mi :ac] inc)
(update-in [di :is] conj i))))]
(reduce throw ms is)))
res (fn [d] (iterate #(reduce (partial turn d) % ixs) data))]
(prn {:one (->> (nth (res 3) 20) (map :ac) (sort >) (take 2) (reduce *))
:two (->> (nth (res 1) 10000) (map :ac) (sort >) (take 2) (reduce *))}))
;; {:one 100345, :two 28537348205}
#2022-12-1111:57noogauh I don't like today's problem at all 😛#2022-12-1111:57noogaI can write compilers and golf, don't ask me to do modulo arithmetic#2022-12-1112:02Alekstotally agree#2022-12-1114:28Sam Ritchiehttps://github.com/sicmutils/sicmutils/blob/main/src/sicmutils/modint.cljc#2022-12-1114:29Sam Ritchieif you want to push some work into a type, given ModInt
a try!#2022-12-1114:29Sam Ritchiehttps://github.com/sicmutils/sicmutils/blob/main/test/sicmutils/modint_test.cljc#L61#2022-12-1117:27wevremI may be in the minority, but I actually liked today’s problem. It’s not a bad thing to have some knowledge of modular arithmetic in your bag of tricks, and it’s at least as important as code golf.#2022-12-1118:03solfI would like if people keep talks specifics about a day inside the daily thread, some people (like me) is behind on the daily puzzles#2022-12-1118:04zamanskySorry - I meant to put it under the thread- I goofed.#2022-12-1118:05solfThanks 👍#2022-12-1119:04Mark WardleYes sorry I thought this was todays thread - deleted. #2022-12-1205:51normanDay 12 - Solutions#2022-12-1205:52normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day12/main.clj
Finally a nice fun search...#2022-12-1205:58wevremhttps://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_12_elevations.clj
Used a Dijkstra datatype I put in place for prior years.#2022-12-1207:18wevremHad one of those “aha!” thoughts as I was just about to head to bed, and totally revamped my approach for part II. Okay, maybe not so much “aha!” as “duh!”#2022-12-1207:28Aleks@UTFAPNRPT like your comments (thoughts) in the code#2022-12-1208:32Aleksold good bfs without any tricks
https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_12.clj#2022-12-1209:13Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/12.clj
always happy to have an opportunity to use my search functions. used the same trick as @UTFAPNRPT. searching in reverse 😌#2022-12-1210:02mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2022/day12.clj#2022-12-1210:20CaseyToday was fun! I leaned on loom
rather than come up with my own bfs alg. https://github.com/Ramblurr/advent-of-code/blob/main/src/aoc/2022/day12.clj#2022-12-1210:21AleksOk, I refactored it and use the same trick for part 2. Thanks @UTFAPNRPT
https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_12.clj#2022-12-1210:23Aleks@U01HL2S0X71 how does it work for part 2 if you don’t change the climbing condition?#2022-12-1210:24Callum OakleyI’m doing part 1 in reverse as well 🙂#2022-12-1210:25AleksOhh, I missed that 🙃#2022-12-1212:59AleksFound out that my lowest destination on the way is just -2 from the current. Seems like nobody would break their legs.#2022-12-1213:53tschadyRe-used my grid library, leveraged ubergraph algorithm, Terra Incognita has infinite height.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d12.clj#2022-12-1215:06leinfinkI didn't keep track of particular paths, just spread out from the starting point with a counter for each step, using sets to avoid double checks. This worked flawlessly for multiple starting points (and goals also, I guess), so I think this was my luckiest part 2 so far.
https://github.com/leinfink/aoc-2022-clj/blob/main/src/aoc22/day12.clj#2022-12-1215:49Miķelis Vindavshttps://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/y2022/day12.clj#2022-12-1217:26bhaumanI’m high I’m low and I’m high again. Fun stuff!#2022-12-1217:29bhaumanone of my problems is I’m using the graph library loom b/c I be darned if I implement dikstras, but now I don’t have insight into why its choosing a least optimal path, other than I’m creating the graph wrong.#2022-12-1218:07bhaumanLGTM#2022-12-1218:49bhaumanyeah I guess there is an off by one error somewhere but looking at the output it really seems like the minimal path so I’m going to let it go for now, and come back to it this evening#2022-12-1218:51CaseyConsider that in the example explanation for Day12 they are counting steps, not the number of nodes visited#2022-12-1218:51CaseyThat could be causing an off by 1#2022-12-1218:52Casey(I also used loom 😊)#2022-12-1218:52bhaumanThanks! That’s good advice. But … that’s already been accounted for as I dec
the result.#2022-12-1218:52bhaumanawesome, loom users unite!#2022-12-1218:57Aleks@U064J0EFR Could you miss out this statement “This also means that the elevation of the destination square can be much lower than the elevation of your current square”?#2022-12-1218:58bhaumanthanks, yeah thats in there to and my path has to allow for that as it goes [ab … nopnopqr …]#2022-12-1219:32Vincent Olesenhttps://github.com/volesen/aoc2022/blob/main/day12/day12.clj#2022-12-1220:49Felipeugly as hell dijkstra code, but it gets the job done https://github.com/FelipeCortez/advent-of-code/blob/master/2022/12.clj#2022-12-1222:57genmeblogWhen your paths end nowhere, read this sentence after a couple of hours of debugging :/
> (This also means that the elevation of the destination square can be much lower than the elevation of your current square.)#2022-12-1223:59chuckleheadCame here to say basically the same thing #2022-12-1300:00chuckleheadCouldn’t figure out why my bfs worked on the sample but not the full#2022-12-1301:55Andrew ByalaRunning, jumping, climbing trees...
• https://github.com/abyala/advent-2022-clojure/blob/main/docs/day12.md
• https://github.com/abyala/advent-2022-clojure/blob/main/src/advent_2022_clojure/day12.clj#2022-12-1305:50bhaumanI did figure out my problem from earlier, I was setting start to 0 and end to 27 thinking that I was being clever. Still not sure why that added 4 steps to the result but … I’ll look into it more tomorrow#2022-12-1306:36Appley25 cannot get to E27#2022-12-1312:00genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day12.clj#2022-12-1315:06leinfinkrefactored a bit https://github.com/leinfink/aoc-2022-clj/blob/main/src/aoc22/day12.clj#2022-12-1315:41bhauman@UP82LQR9N my coding was 1-26 and I was using 0 for start and 27 for end. I was a real puzzler for me…#2022-12-1315:50Apple1 for start and 26 for end then#2022-12-1315:51Applei use 0 and 25 for the 0-25 range#2022-12-1315:52Appledoesn't matter really as long as the start and end falls in the range#2022-12-1317:11bhaumanBut the interesting question is why would [start = 0, a = 1 … z=26, end = 27]
provide a different result ing edge length of 444
in this case (both in loom and my custom bfs), and when I changed the mapping to [start = 1, a = 1 … z=26, end = 26]
I got the correct solution of 440
. The traversal rules work the same for both? hmmmm ….#2022-12-1317:12leinfinkYou can go from Y (25) to Z (26), but not to 27#2022-12-1317:13leinfinkI think?#2022-12-1317:13Appley25 cannot get to E27#2022-12-1317:13bhaumanyeah thats right#2022-12-1317:13bhaumanso you can skip the last z#2022-12-1317:14bhaumanI just didn’t think that was correct#2022-12-1317:15bhaumanIn fact you can skip all of the last z’s theoretically I just didn’t think the problem implied that at all#2022-12-1317:17bhaumanI’m rereading the problem for the qoute I missed now#2022-12-1317:17bhaumanAlso included on the heightmap are marks for your current position (S) and the location that should get the best signal (E). Your current position (S) has elevation a, and the location that should get the best signal (E) has elevation z.
#2022-12-1317:17bhaumanpretty straightforward …#2022-12-1317:17bhaumanugh#2022-12-1317:18leinfinkif you got lucky and had my input instead, i think your mistake wouldn't have mattered and your day would have been much more relaxing haha#2022-12-1317:18bhaumanOMG#2022-12-1317:19bhauman#2022-12-1317:20bhauman#2022-12-1317:21bhaumanyep there are the extra steps#2022-12-1317:22leinfinkah I had that start too, so it still would have mattered#2022-12-1409:00Miķelis Vindavs@U04BA34MCDN apparently your algo has a name: https://en.wikipedia.org/wiki/Lee_algorithm#2022-12-1409:11leinfink@U89SBUQ4T oh, interesting. I wonder if the fact that I didn't need to do the backtrace part mitigates some of that slowness / memory usage? but i guess thats negligible#2022-12-1409:15leinfinkohh and i like the idea of propagating waves from source and target at the same time#2022-12-1412:45leinfinkwelp, tried it, didn't give any noticeable performance benefit tho#2022-12-1215:09Benjamintips for day 12?#2022-12-1215:10BenjaminI have a function that finds all possible paths but the time complexity doesn't work for the input#2022-12-1215:43Aleksbreadth-first search#2022-12-1215:46Miķelis Vindavsyou could google Dijkstra’s algorithm#2022-12-1215:49Miķelis Vindavsalso, clojure has a somewhat hidden datastructure called PersistentQueue
It is fast to add to the back and remove from the end
Create an empty one with clojure.lang.PersistentQueue/EMPTY
(no parens needed)
Add to the end (right) with conj
Look at the first element (left) with peek
Return a new queue without the first element with pop
#2022-12-1215:49Callum Oakleyhard to say without seeing what you’ve already got, but given you say you already have a function to find all possible paths I have a hunch you’ll already be doing BFS (or something equivalent) and the time complexity issue will be because of double counting. make sure you’re not finding multiple paths to the same place! (you only care about the shortest one)#2022-12-1215:51Aleksa handy helper for PersistentQueue
(defn queue [& args]
(into PersistentQueue/EMPTY args))
#2022-12-1215:55Miķelis VindavsThat’s exactly the one I have in my support namespace as well 😄#2022-12-1215:58Callum Oakleywhile we’re sharing convenient type wrappers for search, here’s my https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/search.clj#L8-L13 based on clojure.data.priority-map (useful for Dijkstra)#2022-12-1215:59JI have used PriorityQueue
#2022-12-1216:05Miķelis Vindavsoh nice i didn’t know clojure.data.priority-map
existed#2022-12-1216:05Miķelis Vindavsi guess you could also build it using a sorted-map#2022-12-1216:08Miķelis Vindavs@U01HL2S0X71 that’s a very nice support lib!#2022-12-1220:26StuartI'm a ways behind, just catchup up with day 10 now.
I have a question about part 2. Question in thread to avoid spoilers.#2022-12-1220:29StuartI'm not sure what's asking me to do.
I dont see the relevance of what I did in part 1.
I have all the values for x at each cycle (240 of them).
So essentially in pseudo code is it asking
for n = 1 to 240:
if x-values[n] is within +/- 1 of n (mod 40):
draw dark pixel
draw light pixel
Is that right?#2022-12-1220:42StuartArgh, I had (<= 1 ,,, )
, where I should have had (<= ,,, 1)
Solved now#2022-12-1305:40Alex AlemiDay 13 - Solutions#2022-12-1305:40Alex Alemihttps://github.com/alexalemi/advent/blob/main/2022/clojure/p13.clj#2022-12-1305:40Alex Aleminot the most elegant comparison function, but I tried for speed today#2022-12-1305:45Alex Alemiit was also nice having an input file that was valid clojure#2022-12-1305:49wevremVery crude solution which I will proceed to refine.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_13_distress_packets.clj#2022-12-1306:46normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day13/main.clj
Some days I feel like I have no reading comprehension skill....#2022-12-1307:24nbardiukparsing is easy if we wrap everything into a vector and read edn. Comparator is the meat of the task. I've made a detour trying to normalize packets to the same shape in order to use standard compare
, but figured that writing comparator is easier. https://github.com/nbardiuk/adventofcode/blob/master/2022/src/day13.clj#2022-12-1307:39Andrew ByalaI got mine to work, also using edn/read-string
, and I've done my usual write-up.
• https://github.com/abyala/advent-2022-clojure/blob/main/docs/day13.md
• https://github.com/abyala/advent-2022-clojure/blob/main/src/advent_2022_clojure/day13.clj#2022-12-1308:10wevremOkay, refining is done. Off to bed.#2022-12-1308:40CaseyPretty gross comparator.. I basically wrote it while reading the puzzle text top-down. Was pleasently surprised to find that in part-2, I could slot it into clojure.core/sort
without any changes.
https://github.com/Ramblurr/advent-of-code/blob/main/src/aoc/2022/day13.clj#2022-12-1309:12Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/13.clj
no surprises today#2022-12-1310:27Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day13.clj#2022-12-1310:36Benjamin(edn/read-string (str "[" input "]"))
doens't this somehow feel like some win condition for lisp?#2022-12-1310:46CaseyMaybe.. in JavaScript you could so the same with JSON.parse#2022-12-1311:39Mark WardleI don't think I've done anything very differently to anyone else here. Feels like this problem designed to be solved with a lisp.... Wonder if my comparator is a bit verbose... https://github.com/wardle/aoc2022/blob/main/src/day13.clj#2022-12-1311:50Mark WardleJust read @UTFAPNRPT’s solution and his use of keep-indexed which is much nicer than my map-indexed and then filter contortions! This is great for learning.#2022-12-1312:10Felipehttps://github.com/FelipeCortez/advent-of-code/blob/master/2022/13.clj
and TIL
> Java comparators are all 3-way, meaning they return a negative, 0, or positive integer depending upon whether the first argument should be considered less than, equal to, or greater than the second argument.
>
> In Clojure, you may also use boolean comparators that return true
if the first argument should come before the second argument, or false
otherwise (i.e. should come after, or it is equal). The function <
is a perfect example, as long as you only need to compare numbers. >
works for sorting numbers in decreasing order. Behind the scenes, when such a Clojure function bool-cmp-fn
is "called as a comparator", Clojure runs code that works like this to return an int instead:
> (if (bool-cmp-fn x y)
> -1 ; x < y
> (if (bool-cmp-fn y x) ; note the reversed argument order
> 1 ; x > y
> 0)) ; x = y
#2022-12-1312:11CaseyRecommended reading on clojure comparators: https://clojure.org/guides/comparators#2022-12-1314:23misha[2,3,4] vs 4 are in the right order
because 2<4 makes a decision before right runs out of elements.
so [2 3 4] [4] is ok
and [2 3 4] [2] is not because 2=2 (no decision), and only after that right runs out of elements
and [2] [2 3 4] is ok, because 2=2 (no decision), and left runs out, and thats ok
and as a result (every? true? (map correct? left right))
is incorrect#2022-12-1315:05genmeblogMuch much easier than yesterday... It was great decision to write comparator for part1. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day13.clj#2022-12-1315:42bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day13/sol.clj#2022-12-1315:45bhaumanThe interesting bit
(defn comparer [a b]
(cond
(every? integer? [a b])
(compare a b)
(every? sequential? [a b])
(if-let [res (->> (map comparer a b) (filter #(not (zero? %))) first)]
res
(comparer (count a) (count b)))
:else ;; one is a list and one is an integer
(apply comparer (map #(cond-> % (integer? %) vector) [a b]))))
#2022-12-1315:45tschadyLists, first, next.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d13.clj#2022-12-1315:52Vincent Olesenhttps://github.com/volesen/aoc2022/blob/main/day13/day13.clj#2022-12-1316:09tschadyLooking at the source for =
led me to next
instead of rest
, which I always forget about. next
especially helps because (compare nil 2 ) (compare 3 nil) (compare nil nil)
all do the right thing.#2022-12-1316:27wevremThat’s a good thing to remember, @U1Z392WMQ.#2022-12-1316:34AleksImpressed by @UTFAPNRPT’s code of comparator. It’s really concise.#2022-12-1316:35AleksMine is a bit wordy
https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_13.clj#2022-12-1317:11wevremI thought a lot about it (too much!) and made two attempts to normalize and flatten the packets and do a simple element-wise compare, but I kept running into exceptions. I got as close as having only 3 cases that I couldn’t resolve (with my input). Ah well. It’s like the false promise of alchemy.#2022-12-1317:21nbardiukmade an animation how the packets would look like if normalized to the common shape. Although it is only animation, the compare
doesn't work on it#2022-12-1400:43wevremNil is less than everything. And ##-Inf is less than everything else. #2022-12-1400:48tschadynot everything trollface
user=> (compare ##-Inf ##NaN)
0
#2022-12-1415:22wevremnil
is less than everything, ##-Inf
is less than everything else, and ##NaN
is less than nothing.#2022-12-1415:23Aleksnil is endless void ^_^#2022-12-1307:27AleksDay 13 part 1: I get the right answer for the sample, but it’s wrong for my input. Any tips?#2022-12-1307:31Aleksdouble checked everything, but can’t see a mistake#2022-12-1307:35Alekscompared visually the output for every example, it seems correct#2022-12-1307:35wevremThe input has empty vectors in strange places that messed me up when I tried to get too tricky.#2022-12-1307:41AleksI use edn/read-string
to parse it, should work fine I guess#2022-12-1309:28BenjaminCame here for the exact same question#2022-12-1309:31Benjamin(read-string (str "[" input "]"))
(partition 2)
works fine for the example and the real input also seems correct. Am I wrong?#2022-12-1309:43Aleksshould be fine, I found a problem with a logic for comparison#2022-12-1309:43AleksI’m using a zipper in a wrong way#2022-12-1309:53BenjaminFor me I realized my logic is wrong for this case:
[[4, 5], 6]
[[4, 5], 3]
#2022-12-1312:53Aleks(cmp [[[] 6 2]] [[[]] [10]])
a good example to check against, should return false
#2022-12-1312:59AleksMy mistake is I was trying to use zippers.#2022-12-1307:40Andrew ByalaPosting out here to see if someone with clojure-core-match
skills can answer a specific question on my solution to day 13.#2022-12-1307:42Andrew ByalaIn the bottom of https://github.com/abyala/advent-2022-clojure/blob/main/docs/day13.md, I mention trying to use match
to check the types of the two values at a given level of the vector, checking if they're nil
, scalar, or vectors. I was able to work with matching on [(type v)]
just fine, but once I brought in two types, with [(type v1) (type v2)]
, I couldn't get it to work. I had to resort to :guard
clauses, which just look messy.
Does anyone know how to get the matcher to work when using the types of 2 or more values in the input vector?#2022-12-1309:12elkenI started on the same approach! I just went with condp
in the end which does the same thing in this trivial case#2022-12-1312:37tschadyI had the same idea, but when I saw this in the wiki, I gave up on match as more complex.
> Unlike pattern matching found in most functional programming languages core.match
does not promote matching on concrete types. Instead core.match
matches on abstract interfaces / protocols -`IPersistentVector`, ILookup
, Sequential
and so on.#2022-12-1315:44Andrew ByalaI found a way to make it work, but I still think it's messy. Instead of working with actual types, I had to map the types to keywords. Note the mapv
under the m/match
call. Surely this isn't the intention?
(defn correct-order?
([left right] (correct-order? left right [0]))
([left right address]
(let [[v1 v2 :as values] (map #(get-in % address) [left right])]
(m/match (mapv #(cond (number? %) :num, (vector? %) :vec, :else nil) values)
[nil nil] (recur left right (-> address move-up move-right))
[nil _] true
[_ nil] false
[:num :num] (case (u/signum (- v1 v2))
-1 true
1 false
(recur left right (move-right address)))
[:vec :vec] (recur left right (move-down address))
[:vec :num] (recur left (vectorize right address) address)
[:num :vec] (recur (vectorize left address) right address)))))
#2022-12-1316:50Alexis Schadwhy not use guards for types?#2022-12-1317:14Andrew Byala@U01V2D5ALKX - I did the first time through, but I had to repeat the guards multiple times to get all of the conditions to work. Thought it looked a little ugly, unless you know a better way.
(defn correct-order?
([left right] (correct-order? left right [0]))
([left right address]
(let [[v1 v2] (map #(get-in % address) [left right])]
(m/match [v1 v2]
[nil nil] (recur left right (-> address move-up move-right))
[nil _] true
[_ nil] false
[(_ :guard number?) (_ :guard number?)] (case (u/signum (- v1 v2))
-1 true
1 false
(recur left right (move-right address)))
[(_ :guard vector?) (_ :guard vector?)] (recur left right (move-down address))
[(_ :guard vector?) _] (recur left (vectorize right address) address)
[_ (_ :guard vector?)] (recur (vectorize left address) right address)))))
#2022-12-1317:31Alexis SchadIt's not that ugly for me, at least you know what's going on#2022-12-1405:55wevremDay 14 - Solutions#2022-12-1405:57wevremThis is so sloppy and fast because I want to get to bed so I can go snowboarding tomorrow. Yay!
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_14_sand.clj#2022-12-1406:01normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day14/main.clj#2022-12-1409:05CaseyMy solution is coming along. Got the parsing, ASCII visualization and sand falling.. trying to sort out how to detect the termination condition#2022-12-1409:07CaseyOne could easily cheese it by hard coding based on your specific input.. but a general solution would be nice#2022-12-1409:44Callum Oakleyadapted my solution to 2018 day 17, so I don’t know if this is necessarily the most natural algorithm. doesn’t drop a unit of sand at a time, instead keeps track of areas of flowing sand and settled sand. in 2018 the “drop at a time” approach was too slow so I’d be curious to know how long it takes today. this one is ~200ms for part 2 (could certainly speed it up by drawing whole triangles at a time when there are no obstacles!)
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/14.clj#2022-12-1409:45nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2022/src/day14.clj#2022-12-1410:26CaseyGot it! This one was very fun. https://github.com/Ramblurr/advent-of-code/blob/main/src/aoc/2022/day14.clj
@U01HL2S0X71 For part 2 my input and algo takes ~4.5 seconds on my computer.#2022-12-1411:02Aleks@U01HL2S0X71 “Elapsed time: 7734.680185 msecs”#2022-12-1411:12Felipefelt easier than the last few days 🎉
https://github.com/FelipeCortez/advent-of-code/blob/master/2022/14.clj#2022-12-1411:15Felipedid a-step-at-a-time, got 3 seconds for both parts here (on a m1 mac, which is quite fast)#2022-12-1412:01genmeblogwhat a cave!#2022-12-1413:06Felipe@U1EP3BZ3Q looks nice! I also remember seeing some very cool visualizations of the mountain climbing one on reddit#2022-12-1413:12Mark WardleI didn't use a grid, but just used sets representing the blocks and so looped adding sand along the way and naively faking an infinite floor. https://github.com/wardle/aoc2022/blob/main/src/day14.clj#2022-12-1413:17Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day14.clj#2022-12-1413:23Alex Alemihttps://github.clerk.garden/alexalemi/clerktudes/commit/a2b49d062e7e01bb0c62b055c15727ec8ef275d0/notebooks/advent-2022-14.html#2022-12-1413:23Alex AlemiMy part 1:#2022-12-1413:24Alex AlemiPart 2:#2022-12-1413:42zamanskyPretty straightforward but you can always make your life more difficult by writing this:
(apply max (first (keys world))
to find the maximum x coord in the world instead of this
(apply max (map first (keys world)
D'oh!!!!
https://github.com/zamansky/advent2022/blob/main/src/day14.clj#2022-12-1414:55wevremI got up and thought I might feel compelled (shamed?) to do major overhaul, but upon review I think my original approach holds up well, and part 2 only takes about 3s. I got rid of the debug stuff scattered throughout and cleaned up some function signatures and I’m happy with it.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_14_sand.clj#2022-12-1415:03wevremThat picture for part 2, @U02P133R2SZ, makes me wonder if it could be solved by subtracting triangles, instead of simulating grains of sand, like what @U01HL2S0X71 was saying. I haven’t done Year 2018 yet, but I seem to recall some puzzle that required adding/subtracting/combining rectangular regions. Hmmm.#2022-12-1415:07Aleks@UTFAPNRPT triangles are not a problem I guess, but what about these shapes?#2022-12-1415:19wevremThat’s what makes it so interesting. Is there is a way to determine from the vertical and horizontal barriers which triangles (and maybe half triangles) to add and subtract? I’m not saying I’m going to spend the brain power to go figure it out, but it seems like there might be a solution there. (Of course, that is what I thought about normalizing distress signal packets from yesterday, and that turned out to be a fool’s errand. 🙃)#2022-12-1417:13Vincent Olesenhttps://github.com/volesen/aoc2022/blob/main/day14/day14.clj#2022-12-1417:14Alexis SchadYou could remove the "white" triangle below horizontal lines, but then you have to manage some edge cases where sands can’t reach some areas due to vertical lines.#2022-12-1421:08bhauman#2022-12-1421:24bhaumanDay 14 https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day14/sol.clj#2022-12-1422:52tschadyNothing special. Exact floor width needed (plus one for aesthetics). I did like this:
(defn simulate-add-sand [cave]
(let [box (grid/bounds cave)]
(loop [sand source]
(cond
(grid/ob? box sand) :infinite
(nil? (get cave (m/add sand [0 1]))) (recur (m/add sand [0 1]))
(nil? (get cave (m/add sand [-1 1]))) (recur (m/add sand [-1 1]))
(nil? (get cave (m/add sand [1 1]))) (recur (m/add sand [1 1]))
(= sand source) :blocked
:else (conj cave {sand \o})))))
(defn sim-p2-frames [input]
(->> (parse-cave input)
(add-floor)
(iterate simulate-add-sand)
(take-while #(not= :blocked %))))
Lots of optimizations to pursue, but I’d rather work on the Clojure2D viz.
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d14.clj#2022-12-1510:07genmeblogFinally... Used java.util.TreeSet
for gathering blocking sand/rock from given column. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day14.clj Clojure2d viz part at the end.#2022-12-1413:07Applehttps://github.com/betaveros/noulith (https://github.com/betaveros)
https://news.ycombinator.com/item?id=33975556#2022-12-1413:31Miķelis VindavsIt’s great. The core idea is very similar to threading (`->>`) in clojure, but with partial application as the default#2022-12-1413:32Miķelis Vindavs(his solutions for this year are in https://github.com/betaveros/advent-of-code-2022 )#2022-12-1413:44Appleculi 8 hours ago | next [–]
I just checked the 2nd place[^0] person and they... also have their own programming language...[^1]
What's going on here? Are they just extra motivated to show off their languages? Is making your own programming language more common than I realized?
EDIT: same with the 4th place person[^2]
EDIT2: same with the 7th place[^3]. Btw this is the 4th person that's clickable so actually 3/4 leaders with their GHs linked have their own programming languages
EDIT3: jonahx pointed out I made a mistake and the 2nd place person didn't actually create Vyxal, just used (and contributed) to it
[^0]:
[^1]:
[^2]:
[^3]:
#2022-12-1415:26russmatneythese langs (and code-golf, i.e. going for smallest program byte-size) are mind-blowing! i'd never understood it until this year (i'd always associated the term with vim-golf)#2022-12-1415:27russmatneyhttps://codegolf.meta.stackexchange.com/questions/25251/announcing-code-golf-advent-calendar-2022-event-challenge-sandbox#2022-12-1415:32AppleAlso this solving AoC with jq! https://github.com/odnoletkov/advent-of-code-jq
Discussion https://news.ycombinator.com/item?id=33963383#2022-12-1506:55wevremDay 15 - Solutions#2022-12-1507:12wevremIt took something like 10 minutes for my Part 2 to run. Yikes!#2022-12-1507:20AppleIf a position is occupied by B then that position doesn't count for part1, correct? How about the position of S?#2022-12-1507:22wevremI think just the B’s have to be removed.#2022-12-1507:29wevremI used pmap and got my part 2 runtime down to about 2.5 minutes. Still seems slow.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_15_beacons.clj#2022-12-1507:41normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day15/main.clj
Not proud in any way of this code. Sad to say I spend OVER 30 minutes debugging part1 only to realize I was checking y=10 from the sample input and not the y for the real input... UGGH...
I had to write a couple version of part2 before I got it right. I didn't reuse much code between part1 and part2.
"Elapsed time: 31199.856226 msecs"#2022-12-1511:25nbardiukoptimizing this problem is hard, I've reordered points and suddenly it solves in 4 seconds - just because my answer is close to edge and with the new order it needs to brute force through less data#2022-12-1511:28nbardiuk#2022-12-1513:44Felipepart 2 takes some 30 seconds but hey, it works! my previous record was completing day 14 so I'm happy that's as far as I ever got 🎉
https://github.com/FelipeCortez/advent-of-code/blob/master/2022/15.clj#2022-12-1513:57Alexis Schad(defn merge-intervals [intervals]
(get
(reduce (fn [[nb-open last retval] [x dir]]
(if (= -1 dir)
[(inc nb-open) (if (zero? nb-open) x last) retval]
[(dec nb-open) last (if (= 1 nb-open) (conj retval [last x]) retval)]))
[0 nil []]
(->>
(concat (map #(list (first %) -1) intervals)
(map #(list (second %) 1) intervals))
(sort-by second)
(sort-by first))) 2))
(defn part1 [rowy inputs]
(let [intervals (keep (fn [[x1 y1 x2 y2]]
(let [dist (+ (abs (- x2 x1)) (abs (- y2 y1)))
dist-at-row (- dist (abs (- rowy y1)))]
(when (>= dist-at-row 0)
[(- x1 dist-at-row) (+ x1 dist-at-row)])))
inputs)]
(merge-intervals intervals)))
(defn part2 [inputs]
(doall
(for [y (range 4000000)]
(let [intervals (part1 y inputs)]
(when (> (count intervals) 1)
(println y intervals)))))
nil)
(->> (slurp "day15.txt")
(str/split-lines)
(map (fn [line]
(map parse-long (str/split line #" "))))
(part1 2000000))
(->> (slurp "day15.txt")
(str/split-lines)
(map (fn [line]
(map parse-long (str/split line #" "))))
(part2))
#2022-12-1514:01mishafinding slopes, their intersections, and the only one outside all sensors - 10ms#2022-12-1514:04Felipe(spoilers) of course https://www.reddit.com/r/adventofcode/comments/zmfwg1/2022_day_15_part_2_seekin_for_the_beacon/. how did I not think of that#2022-12-1519:42bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day15/sol.clj#2022-12-1520:45genmeblogWrong parsing killed me today... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day15.clj#2022-12-1522:25wevremI tried out my idea that I was pondering last night, and Part 2 runs in 41 msecs. Yahoo!#2022-12-1522:26wevremReading above, it looks like my approach must be similar to @U051HUZLD ’s#2022-12-1522:41rjrayI'm just flailing on this day, for some reason. My first submission for part 1 was too low. Every change/adjustment I've made to the code since then keeps returning the exact same answer.#2022-12-1522:50genmeblogIt was my case too... I had a bug in parsing, there are negative numbers.#2022-12-1522:51genmeblogWhat happens on example data?#2022-12-1522:51rjrayExample data runs fine. And I am accounting for negative numbers, yeah.#2022-12-1522:52rjrayWhat is weirding me, is that every change yields the same answer. If there were something wrong with the algorithm I would expect SOME variation...#2022-12-1522:54genmeblogToday's case is really hard to debug imho. I was reading squares manually to be sure I'm right (or wrong).#2022-12-1522:55genmeblogYou can take a look at my input and compare results.#2022-12-1522:56genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/resources/advent_of_code_2022/day15.txt#2022-12-1522:56genmeblogyields 4737443
#2022-12-1522:58rjrayWhich value for y?#2022-12-1523:05genmeblog2000000#2022-12-1523:07tschady@UEF091BP0 not sure what you’re using, but sometimes when I get crazy results like that, it’s because I have some old function compile in my cache. restarting emacs cider takes care of it.#2022-12-1523:09bhauman@UEF091BP0 how are you handling becons in the row?#2022-12-1523:10rjraySadly, when I run for the actual answer I use a lein run
process to make sure it's a clean VM.#2022-12-1523:10rjrayAnd I got the right answer for genme's input. Yay.#2022-12-1523:11rjrayI don't count beacons in the row... should I be? The example specifically doesn't count the one beacon in its row.#2022-12-1523:12bhaumanyeah that’s the way, just checking#2022-12-1523:12rjrayHey, even I'm not sure at this point 😛.#2022-12-1523:14bhaumanhmmm and your are incrementing the difference between the start and end locations?#2022-12-1523:14rjrayNot sure what you mean?#2022-12-1523:15genmeblogI had exactly the same, other imput was correct, mine not. Maybe verify parsing again?#2022-12-1523:16rjrayHmmm... can't hurt. Let me check.#2022-12-1523:16bhaumanSo the abs difference between -2 and 24 is 26. But its inclusive so its actually 27 entries minus the beacon.#2022-12-1523:16genmeblog^^^ exactly#2022-12-1523:19bhaumanAlso, I think I’ve mentioned before about how edn/read-string
is a great way to parse …. :face_with_hand_over_mouth:#2022-12-1523:20bhaumanyeah that was obnoxious#2022-12-1523:24rjrayParsing checks out. What I am doing is running along the given y from (min-x, max-x). For each (x,y) pair, I look to see if it isn't a beacon, and if it is in range of at least one sensor.
This gave me the correct answer for the other input data, just not for mine.#2022-12-1523:28bhaumanthen I’d suspect the bounds maybe min-x and max-x are wrong#2022-12-1523:29rjrayPossible. They are calculated by finding the min-X from the sensors, then subtracting it's beacon distance from it. Do the same with max-X and +.#2022-12-1523:31bhaumanI can tell you a number that your max shouldn’t be below if you want. It’s something you learn in from the second part.#2022-12-1523:32bhaumanbut that sounds like a great way to get the min and max#2022-12-1523:33bhauman@UEF091BP0 hmmm actually your bounds algorithm sounds wrong#2022-12-1523:33Appleanyone got more than one beacon on the same row?#2022-12-1523:34bhauman@UEF091BP0 because the (min-x sensor + beacon dist) might not be the the absolute min-x#2022-12-1523:34rjrayOh $^!%. I think it might actually be freakin' typo. Just found something sus when verifying my bounds code.#2022-12-1523:35bhauman@UEF091BP0 did you see my messages above?#2022-12-1523:36rjrayYes, I did. It's (min-x sensor minus beacon dist), then (max-x sensor plus beacon dist).#2022-12-1523:36bhaumanyeah that’s the problem, I had a typo#2022-12-1523:37bhauman@UEF091BP0 (min-x sensor minus beacon dist) isn’t nessearily the min-x#2022-12-1523:38bhauman@UEF091BP0 because the middle-x sensor may have a huge beacon dist#2022-12-1523:38rjrayArgh. And I must have just been lucky on genme's input, then.#2022-12-1523:50rjrayWhee. Part 1 done. How hard can part 2 be? Right?#2022-12-1600:01bhaumangood luck!#2022-12-1600:01rjrayYeah, that was sarcasm 🙂. Even before reading part 2, I knew the gist of it. Not even sure where to start...#2022-12-1600:07wevremFinished writing a lot of notes to explain my approach. I’m quite pleased with it.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_15_beacons.clj
I need to go back and adapt part 1 to use it, I think I have a way to do it.#2022-12-1600:27robertfwa pretty naive approach, checking each row for spans covered and merging those. pt2 runs in ~36 seconds
edit: a bit of hacking away with some threads to use all my cores and I can get pt2 down to about 6.5s#2022-12-1613:12CaseyHad no time yesterday.. playing catch up now. I came upon the same insight that was linked earlier on reddit.. checking one space beyond the perimeter of each range diamond. It's dog slow.. even using pmap
. I also used the
for some geometry functions.
https://github.com/Ramblurr/advent-of-code/blob/main/src/aoc/2022/day15.clj
My part 2 solution has a bug somewhere, because it returns multiple points for the sample.. but I lucked out I guess with my input because after 11 minutes running it spat out a single (correct) answer#2022-12-1613:15CaseyI'm not really sure why it is so slow.. if anyone is interested, I'd be curious to get some tips on why it's slow.#2022-12-1616:45wevrem@U70QFSCG2 you don’t need to check every point outside a diamond (I think that is what you are doing) you can limit your search to intersections. In other words, expand the lines that make up each diamond by one point outward, then search the intersections of all those lines.#2022-12-1519:42genmeblogI need some more correct examples for Day 15 part 1 can anyone share some part of his input with a result? My code works for given example but for my input not. All of ideas for debugging failed. Any hints?#2022-12-1519:43genmeblogJust to be precise I need a couple of sensors with the result for any y
#2022-12-1519:44bhaumanAll of my input is in github#2022-12-1519:45genmeblogok, I'll try this, thanks#2022-12-1519:45bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day15/input.txt#2022-12-1519:45bhaumanand my results are in my code#2022-12-1519:45bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day15/sol.clj#L78#2022-12-1519:46bhaumanhttps://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day15/sol.clj#L117#2022-12-1519:48genmeblogThanks! Funny (or not), the result from my code is the same... :/#2022-12-1519:49bhaumanbeen there for sure#2022-12-1519:49genmebloggeez... the bug is in parsing...#2022-12-1519:51genmeblogI missed the negative -
sign... which caused the error with my data.#2022-12-1519:52genmeblogBut not with yours.#2022-12-1519:52genmeblogAnyway, thanks for assisting me 🙂#2022-12-1522:16bhaumanIt was nothing! Glad you got it sorted. 🙂#2022-12-1606:15robertfw#2022-12-1608:10genmeblogExpecting the worst for part 2...#2022-12-1607:22normanDay 16 - Solutions#2022-12-1607:25normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day16/main.clj
So ugly. I really struggled for a good representation. I was surprised that part1 worked at a reasonable speed, but it did. For part 2 I brute force extended the solution, but it was too slow. Because it's getting late, I capped the number of positions i consider one the search frontier got large. I got the right answer, but I really need to revisit this tomorrow and use a smarter strategy...
Ideas to improve
• can I actually filter out paths that can't possibly exceed the best solution? It's easy to compute the minimum score at the end for the best node and to compute the maximum score for the other nodes
• can I filter out the zero nodes and simplify the graph before starting?
• can part one be re-used, maybe computing everything you can reach in 26 minutes and intelligently combining them?#2022-12-1607:26normanApparently this is stumping lots of people.... This was the first time I got in the top 1000.#2022-12-1610:32Miķelis VindavsSince only a fraction of the valves have flow, you can precompute the distance between each pair and only consider those when branching #2022-12-1610:37Miķelis VindavsAnd another easy way to prune the space in part2 is - when both you and the elephant can go to the same 2 valves, only checks the cheapest option
e.g. if at some moment you can go to valve A with cost 3 and B with cost 5
And the elephant can go to A with cost 4 and B with cost 2
then only you->A, elephant->B should considered as the total cost is 3+2 as opposed to 5+4 for the inverse.
And the end states are equivalent, one player on each of the valves#2022-12-1613:56AleksA humble visualization. It helped me to solve the problem. (made with graphviz).#2022-12-1615:31tschady@U067R559Q I did the same, (though I learned about :circo
from you). Here’s the before/after graph of my cave after “shrinking”#2022-12-1617:35nbardiuktoday was hard for me, ended up with some sort of A* on working valves https://github.com/nbardiuk/adventofcode/blob/master/2022/src/day16.clj#2022-12-1618:13mishap2 sample and input times
"Elapsed time: 19.593426 msecs"
"Elapsed time: 25420.249547 msecs"
but spent way too long on it,
constantly getting 1705 instead of 1707 due to insufficiently unique cache keys
https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2022/day16.clj#L83-L119#2022-12-1618:45Miķelis Vindavs@U051HUZLD are you me? 😄 I had the exact same 1705 instead of 1707. In my case I had a typo that was causing the last move to fail.#2022-12-1701:44bhaumanStarting on the second part now, and feeling lucky I abstracted the search mechanism into a small higher order function… but I’m not done yet …#2022-12-1703:12bhaumanSo as far as I could tell this is a traveling salesman problem preceded by a bfs shortest path problem.#2022-12-1703:14bhaumanStill waiting to find the optimal solution …. for the real data in part 2#2022-12-1710:32Felipefinally got part 1!
https://github.com/FelipeCortez/advent-of-code/blob/master/2022/16.clj#2022-12-1714:01bhaumanIt’s a toughie!
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day16/sol.clj#2022-12-1714:02bhaumanpart 2 “Elapsed time: 163016.040392 msecs”#2022-12-1716:10Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/16.clj
I'm a day behind now but I really enjoyed this one. got to https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/search.clj#L50-L65
part 2 takes <2s#2022-12-1719:59genmeblogEventually figured it out. Part 2 is so slow... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day16.clj#2022-12-1720:32Alex AlemiOh man, part 2 kicked my butt, first time since 2020 that I didn't get it within the 24 hours of release. Eventually got it but took ~25 seconds for part-2 https://github.com/alexalemi/advent/blob/main/2022/clojure/p16.clj#2022-12-1804:36rjrayUgh. I caved after >24 hours and went with a Python solution. Now I'm trying to convert it to Clojure and I'm getting a StackOverflowError. Probably going to give up and prep for day 18.#2022-12-1814:14Vincent OlesenI am really happy with the solution, using dynamic programming and considering Part 2 in a special way: https://github.com/volesen/aoc2022/blob/main/day16/day16.clj#2022-12-1707:43normanDay 17 - Solutions#2022-12-1707:53normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day17/main.clj
Part 1 was very fun, though it took much longer than I thought. Part 2 was really tough, but we've had cycle detection problems before so it seemed relatively clear what generally needed to be done.
Part2 here is kind of ugly. I dumped my height differences into emacs and played with the buffer a bit to confirm there were cycles and what size they were to write a more targeted solution. It's not my finest clojure, but it works...#2022-12-1712:25nbardiukI also hard coded boundaries for cycle in part 2 https://github.com/nbardiuk/adventofcode/blob/master/2022/src/day17.clj#2022-12-1712:39mishasemia-utomatic search of cycle segment
https://github.com/akovantsev/adventofcode/blob/43cb2bcc0fda8719135af9333c3a7dd003a497cb/src/adventofcode/y2022/day17.clj#L119-L143#2022-12-1716:46Miķelis Vindavs@U076FM90B what a beautiful solution — very readable & expressive! I like the use of reductions
and cycle
, and the reusing of dh
in part 2#2022-12-1716:47Miķelis VindavsI wasn’t able to get my clj solution for today to run faster than 3 or so seconds. Whereas my simpler python solution runs in 70ms 😕#2022-12-1716:50Miķelis Vindavsthen again in py i used a bitmask to represent each line of the stack#2022-12-1716:53nbardiukyes, my solution is slow. Also I track which point belongs to which original shape for colorful rendering#2022-12-1716:55Miķelis Vindavsmy comment about the slowness wasn’t directed at you, it was about my own clojure solution 😅 sorry if it sounded that way
yes, i noticed that you assoc the keyword for each shape into the map.
What are you using to generate that image?#2022-12-1716:57nbardiukI didn't took it personally, I meant my code is ALSO slow 🙂 I use clojure2d, the file with sketch is not that readable https://github.com/nbardiuk/adventofcode/blob/master/2022/sketch/day17_sketch.clj#2022-12-1716:57Miķelis Vindavsnice, i didn’t know about clojure2d#2022-12-1716:59nbardiukit's great - runs on latest jvm (while quil doesn't) and has documentation site with examples https://clojure2d.github.io/clojure2d/docs/codox/index.html#2022-12-1717:00Miķelis Vindavsi also find it surprising that you can find the cycle just by looking at the height differences, that’s so much simpler than what i did — make a “fingerprint” of the last 10 rows, basically the relative max height of each x coordinate#2022-12-1717:01Miķelis Vindavsi don’t think either solution would work correctly for all possible inputs though
e.g. mine definitely wouldn’t work if there were “caves” under an overhang#2022-12-1717:03Miķelis Vindavsor a super tall empty gap on one side which then later gets filled by dropping an I
shape down more than 10 rows#2022-12-1717:03nbardiukyes, last 10 rows are not stable because peaces can fall between cracks. Also heights can repeat while the shape does not.#2022-12-1717:11Aleks@U89SBUQ4T “to run faster than 3 or so seconds”
Is it for part 1 or part 2?#2022-12-1717:11Miķelis Vindavsfor part 2#2022-12-1717:14Miķelis VindavsI store the occupied slots as a set of x,y tuples
This means that collision tests, but especially fingerprinting (which has to do at least 1 linear search over the entire set to find the max Y coordinate), get slower as the stack gets filled up.
What’s interesting is that i tried pruning down the set of coordinates every once in a while, but that only made the whole thing even slower#2022-12-1717:16AleksInteresting, pruning down the set was my first thought when I saw part 2 question.#2022-12-1717:17Miķelis Vindavsthe cycle occurs pretty fast so it doesn’t get that huge- it always stays below 10k elements#2022-12-1717:25Miķelis Vindavsi just realized i can pass in the “max y” from outside, now it all takes 100ms#2022-12-1717:26Miķelis Vindavsthat’s kind of funny#2022-12-1717:27AleksI ended with this, works relatively fast
(defn reify-rock [state]
(let [{:keys [rock chamber position height]} state
[cx cy] position
[chamber' height'] (reduce (fn [[m h] [x y]]
(let [x' (+ x cx)
y' (+ y cy)]
[(assoc m [x' y'] \#) (max h y')]))
[chamber height]
rock)]
(assoc state
:chamber chamber'
:height height')))
#2022-12-1717:30Miķelis Vindavswhat’s position, is it the bottom left corner of the rock?#2022-12-1717:31Miķelis Vindavsand how do you detect cycles for p2?#2022-12-1717:31AleksYes, it is#2022-12-1717:32AleksFor part 2 I did it manually with a notepad 🙃#2022-12-1717:33Miķelis Vindavsnice#2022-12-1717:34Miķelis Vindavsbtw, another finding that was surprising to me
;;(def intersects? (comp seq set/intersection))
(defn intersects? [a b]
(if (< (count a) (count b))
(some b a)
(some a b)))
Doing this (avoiding construction of the overlapping set, instead breaking early if anything overlaps) didn’t change the run time much#2022-12-1717:34Miķelis Vindavsin general, i keep getting surprised by how ok it is to generate lots of garbage#2022-12-1720:39Alex AlemiI enjoyed this one, was able to get something that solves part-2 in about a second: https://github.clerk.garden/alexalemi/clerktudes/commit/2da0d9e6008e02078e524bf6df368a410e11f132/notebooks/advent-2022-17.html#2022-12-1715:54Alekstoday’s easter egg https://music.youtube.com/watch?v=I8LnIY8rOCA#2022-12-1806:01normanDay 18 - Solutions#2022-12-1806:04normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day18/main.clj
I'm actually quite happy with this code for a change. Thankfully the technique suggested by the problem statement turned out to be a good direction...#2022-12-1806:38rjrayI got part 1 easily-enough, but I'm getting one more air-pocket than I should when running part-2 on the example data.#2022-12-1806:41rjrayIt's weird-- I checked it out and the "wrong" air-pocket is in fact surrounded by blocks on all 6 faces.#2022-12-1807:04Miķelis Vindavs@U0954HGDQ i like the brutal way to get the (cubic) bounds 😄#2022-12-1807:22rjrayHmmm... from reading reddit, looks like I should be doing a BFS or flood-fill. Think I'll try the BFS first.#2022-12-1807:23Miķelis Vindavson my input it didn’t matter, but i tried expanding the area by a lot and DFS was much much faster. It makes sense — if you want to check if you can reach the edge, try going far in one direction first vs circling around the origin#2022-12-1807:37Miķelis Vindavshttps://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/y2022/day18.clj#2022-12-1809:09mishaflood
https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2022/day18.clj#L10-L57#2022-12-1809:22mishap2 3200ms -> 75ms
https://github.com/akovantsev/adventofcode/commit/9e88dc04c34ec1b674047b310f3fd44d3aa5f8bd#2022-12-1811:58nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2022/src/day18.clj#2022-12-1812:05mishabtw, bubbling might be way faster than flood: most of voxels are surface, and the rest would need a several-steps-long search#2022-12-1813:08AleksProbably not an ordinary solution for part 1. It was my first attempt before I realized BFS saves the day
(defn surfaces [[x y z :as coords]]
(map #(-> #{%1 (mapv + %1 %2)})
(concat (repeat 3 coords)
(repeat 3 [(inc x) (inc y) (inc z)]))
[[ 1 1 0] [ 1 0 1] [ 0 1 1]
[-1 -1 0] [-1 0 -1] [ 0 -1 -1]]))
(->> (parse large-example)
(mapcat surfaces)
(group-by identity)
(vals)
(filter #(== (count %) 1))
(count))
#2022-12-1813:09Miķelis Vindavsgroup-by + count can be replaced with frequencies #2022-12-1813:12Aleksnice catch
(->> (parse large-example)
(mapcat surfaces)
(frequencies)
(filter #(== (second %) 1))
(count))
#2022-12-1813:28Aleks“Unfortunately, you forgot your flint and steel in another dimension.” 🧊#2022-12-1814:07Alex AlemiToday was a welcome reprieve from the last couple days: https://github.com/alexalemi/advent/blob/main/2022/clojure/p18.clj#2022-12-1819:19Felipehttps://github.com/FelipeCortez/advent-of-code/blob/master/2022/18.clj proud of this one 🎉#2022-12-1819:21Felipeimmediately not proud anymore after seeing your solutions in half the line count#2022-12-1908:20Benjaminhttps://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day18-2.clj#2022-12-1918:07bhaumanWell my flood fill seems to work so I’m curious what I’m missing for the second part.#2022-12-1918:08bhaumanI’m also counting surfaces that are “out of bounds”#2022-12-1919:55bhaumanfound it 😞#2022-12-1920:14bhaumanDay 18
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day18/sol.clj#2022-12-2401:32wevremI’m slowly catching up. Wrote a very concise flood
function.
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_18_droplets.clj#2022-12-1816:22nbardiukToday has started another advent style puzzles challenge https://hanukkah.bluebird.sh/ . First day looks fun, on the level of first week of advent of code#2022-12-1907:10normanDay 19 - Solutions#2022-12-1907:22normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day19/main.clj
This is really a terrible effort. The code is very slow - basically I'm searching the space with some really sketchy pruning out of states when geodes and obsidian can be made. But I'm doing the pruning kind of late. It's a mess... I started rewriting while waiting for part1 to finish, anticipating I'd need to do something better for part2, should my solution work at all. It turns out it did and that part2 required almost no changes, so I dropped it in favor of sleep. Almost ashamed to post this...#2022-12-1913:24misha^^^ © basically everyone on reddit kappa#2022-12-1915:29normanHa - yeah, seems like it. My first attempt was raw full search. Then I rewrote so that if you could build any bot it would build it, but that go stuck building ores and clays. Then I went back to full search trying to filter out previously seen states, thinking that would help prune enough. It didn't. I added the max geode check as a test to see if always building geodes worked but otherwise not constraining. It did, but it was slow. Then I added the max obsidian check for states that had the max geodes. Looking at the code this morning I don't think that check is exactly doing what I wanted. But it works. Weird. It didn't really speed things up much, but it gets to the answer. It seems lots of people are doing some variant of these checks, but I'm not seeing anything that stands out as a "good" way#2022-12-1916:18Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/19.clj
this one was a real beast, also unhappy with what feels like a huge pile of hacks and poorly justified "heuristics" 😅
• branch and bound with a truly awful bound of "assume you can build another geo robot in every remaining minute"
• if you can afford a geo robot, always build it immediately
• if we opted not to build a robot we could have built last turn, don't build it this turn either (it would have been better to build it before)
• don't build a robot if we have more than 16 of its resource already (horrible hack, but cuts the search space down a lot)
finishes in 4.6s for part 1 and 1.6s for part 2#2022-12-1918:02misha(sort of) fast p1 solution gave wrong result for sample p2
=> (42 62)
instead of
=> (56 62)
p1 "Elapsed time: 19290.007506 msecs" with heuristic
p2 "Elapsed time: 23966.599927 msecs" with commented out heuristic#2022-12-1918:42tschady> The second blueprint has ID 2 and can open 12 geodes
Anybody stuck with 10 geodes then figure it out? Or if anyone has the full path for the answer to the example ID2, I’d appreciate it. I get the correct answer “9” for ID1, and my answer path has the same as provided. I’m missing some case, data would help. (Edit: think I found it)#2022-12-1919:23Miķelis VindavsI'm sure this can all be expressed as a matrix of costs in materials/time, and solved in more or less constant time somehow
#2022-12-1919:24Miķelis Vindavs@U1Z392WMQ do you still need the path for p2?#2022-12-1919:25Callum OakleyI was stuck on 10 for example 2 for a bit too, obviously a carefully chosen counter example!#2022-12-1919:27Miķelis VindavsFor me, p2 on the example is many times slower than both parts on the real input #2022-12-1920:04rjrayWhelp. First pass at part 1 overflows the stack on the first blueprint of the test data. And that's with some (weak) heuristics to prune the search-space.#2022-12-1920:09Callum Oakley@UEF091BP0 sure you're not in an infinite loop somehow? I would have thought the recursion depth would be 24 at most even if you're doing a full on brute force? :thinking_face:#2022-12-1920:10rjrayI'm doing it as a BFS search, but I can't rule out an infinite loop. I'm basing this on a Python solution from reddit. The Python is slow, but it succeeds.#2022-12-1920:15rjrayI just think my tail-recursion loop
constructs are passing values that grow too large for the stack.#2022-12-1920:15Miķelis Vindavsbtw @U1Z392WMQ here’s what i get for the p2 example for the second blueprint#2022-12-1920:15Miķelis Vindavs0 wait
1 wait
2 ore
3 wait
4 ore
5 clay
6 clay
7 clay
8 clay
9 clay
10 clay
11 obsidian
12 obsidian
13 obsidian
14 obsidian
15 ore
16 obsidian
17 geo
18 obsidian
19 geo
20 obsidian
21 geo
22 obsidian
23 geo
24 obsidian
25 geo
26 geo
27 geo
28 clay
29 geo
30 geo
31 geo
#2022-12-1920:19Miķelis Vindavs@UEF091BP0 what are your loop variables? for collections, the size should not matter as the only thing on the stack is the pointer to them#2022-12-1920:20Miķelis Vindavsif i had to guess, your stop condition is probably incorrect , e.g. it keeps going after time is zero, or doesn’t decrement time when recursing#2022-12-1920:21rjrayThree elements: a list of moves, the current best value, and a set of seen states.#2022-12-1920:22rjrayI had a similar problem with day 16, and just used my own Python code to get the points and stars for that one. I still don't have a Clojure version for that day.#2022-12-1920:35rjrayJust using some simple prn-based debugging lines, I can see my queue of moves growing to almost 30000 before I stopped it.#2022-12-1920:49Miķelis Vindavswhere do you track time?#2022-12-1920:50rjrayIt's the last element of each move-value.#2022-12-1920:50Miķelis Vindavsalso, i might be wrong but i think in this puzzle there is no benefit to searching breadth first, so instead of a large queue, you could use a stack to conj/pop , or just use recursion#2022-12-1920:53rjrayDunno. Busy with my "real" job for now, will have to look at it later.#2022-12-1921:45mishaconcat/cons
(instead of into
) of lazy seqs can overflow on fairly small amounts in loop
s#2022-12-1921:46rjrayHmmm... I do have that. I use concat
to ensure that the new moves go at the end of the list.#2022-12-1921:50misha(first (loop [i 3500 xs []]
(if (pos? i)
(recur (dec i) (concat xs (range 0 i)))
xs)))
Execution error (StackOverflowError) at (REPL:1).
null
#2022-12-1921:50mishause queue#2022-12-1921:50misha(defn queue [init]
#?(:cljs (into #queue[] init)
:clj (into PersistentQueue/EMPTY init)))
#2022-12-1921:51mishapeek
will take first, into
will append#2022-12-1922:51AleksThe worst day, even if you solve it for your input, it doesn’t mean that it will work for others. Hate these type of problems.#2022-12-1922:56rjrayWell, that was educational. I replaced my makeshift-queue with PersistentQueue and got the first part correct. Once I've finished part 2, I'll try to fix Day 16 with PersistentQUeue, as well.#2022-12-1922:57AleksI wrote a solution similar as @U0954HGDQ did, and it looked like it worked fine until I got a wrong answer. Moreover, when I tested it with another input (for which I knew correct number of geodes), It turned out only for exactly one blueprint it got a wrong answer.#2022-12-1923:01AleksI just leave it here, some good ideas to try maybe later
https://www.reddit.com/r/adventofcode/comments/zpy5rm/2022_day_19_what_are_your_insights_and/#2022-12-1923:10rjrayAaaand... part 2 results in an OutOfMemoryError in Java heap space...#2022-12-1923:40rjrayInteresting. Bumped up the heap and restarted my CIDER REPL and it still dies on the test input. But run it from lein on the real data and I get the correct answer. I guess nREPL has it's own overhead...#2022-12-1923:53bhaumanI’m still working hard on this#2022-12-1923:53bhaumanThat's not the right answer; your answer is too low.
#2022-12-1923:56bhaumanI like my approach of doing a bfs one level at a time sorting the results via a geo heavy heuristic and taking the top 2000?#2022-12-1923:57bhaumanI’m still widening my heuristic until it stabilizes somewhere.#2022-12-1923:59bhaumanAnd part 1 is done!#2022-12-2000:20bhaumanand part2 rolls out
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day19/sol.clj#2022-12-2000:21bhaumanI think that’s the trick, doing bfs level by level and sorting and trimming each level as input to the next level#2022-12-2000:26bhauman(defn do-turn [blu robot]
(cond-> blu
robot (pay-for-robot robot)
true robots-work
robot (add-robot robot)))
(defn children [blu]
(->> (conj (can-build? blu) nil)
(map (partial do-turn blu))
(map #(update % ::depth inc))))
(defn bfs-leveler [previous-level]
(->> previous-level
(mapv children)
(reduce into #{})
(sort-by blu-value >)
(take 3000)))
(defn optimizing-game-player [blueprint minutes]
(->> (iterate bfs-leveler [(assoc blueprint ::depth 0)])
(take (inc minutes))
last
first))
#2022-12-2000:26ACI spent way too much time overthinking how to prune states and still haven’t come up with anything I like. (I’ve been skimming responses to avoid spoilers).
I’ve gotten it down to ~3 minutes, but I’m not proud of it. I’m going to take that as a win for now and go back to Day 15 Part 2. I think I know what I need to do but I just can’t get motivated to write it.#2022-12-2000:26bhaumanYeah I’m heading back to day 17 part 2#2022-12-2003:34Alex AlemiToday was brutal, but I ended up with something I'm not too embarrassed by: https://github.com/alexalemi/advent/blob/main/2022/clojure/p19.clj#2022-12-2003:35Alex AlemiTrick was to set a target machine and fast-forward potentially many steps#2022-12-2003:38Alex AlemiIn the end, gets part 1 in 4 seconds and part 2 in 25 seconds#2022-12-2006:11Alex AlemiDay 20 - Solutions#2022-12-2006:11Alex AlemiRelatively straight forward once I realized numbers were repeated in the input: https://github.com/alexalemi/advent/blob/main/2022/clojure/p20.clj#2022-12-2006:12rjrayI'm struggling with the actual "mix" operation. The rest I've got working.#2022-12-2006:20Alex AlemiThe edges were a pain to get correct.#2022-12-2006:22rjrayIt's my lack of experience with Clojure and FP. I can see several ways to do it, but not with immutable data structures.#2022-12-2007:28normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day20/main.clj
Wow. I 100% was stumped for well over an hour before I discovered the non-unique numbers in the input. The lengths of the lists really made that annoying to debug and discover. Once I eventually got that, I apparently was so mentally out of it that I decided to store the original index in metadata rather than just add it to the data like @U02P133R2SZ did above. I guess this why I shouldn't feed my code after midnight....
On the topic of edges, I originally spent at least 15 minutes of my first pass worrying about how to get things at the front or back of the cycle to work before I realized it didn't matter as long as order was maintained. When you start from "0" it's all the same.#2022-12-2012:01AleksUsed my prev implementation of circular list, but now a bit tuned it
https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_20.clj#2022-12-2013:26Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/20.clj
store prev and next index in vectors and update those rather than moving things around. thought it would be faster to make the vectors transient but doesn't actually make much of a difference 🤷 . part 1 1s, part 2 10s#2022-12-2013:57Callum Oakleycan cut the runtime in half by never moving more than halfway round the ring (move in the other direction instead)#2022-12-2015:24Aleks@U0954HGDQ you are not only one, on Reddit people complain about it. I also was bitten by this assumption, but almost immediately realized what went wrong.#2022-12-2017:48bhauman@U0954HGDQ I made this mistake as well#2022-12-2018:06bhaumanhmmm but my answer is still off … and so it begins#2022-12-2018:07bhaumanI had such a nice solution though 🙂#2022-12-2018:21bhaumansure it could be a hash collision I’m sure thats it (sarcasm) ……. otherwise I’ll have to write an alternative simple/slow implementation of the move function to test it against my main one to see if there is a disparity#2022-12-2019:11rjrayFinally, a solution I'm happy with. https://github.com/rjray/advent-2022-clojure/blob/master/src/advent_of_code/day20.clj#2022-12-2019:12bhauman@UEF091BP0 congrats I’m still poking away here#2022-12-2019:14rjrayI had to (literally) sleep on it (the puzzles unlock at 9PM in my time zone).#2022-12-2021:51bhaumanyeah this feels pretty mean, the example doesn’t cover several of the edge cases#2022-12-2022:30bhaumanHere it is finally:
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day20/sol.clj#2022-12-2022:32bhaumanI used a priority map, so there was no need to renumber indexes#2022-12-2104:18bhaumanI really thought about this and I think I got it down to nothing using some lazy trickery to simulate a circular list.
(defn item-mover [lst [index-diff _ :as item-a]]
(if (zero? index-diff)
lst
(let [new-size (dec (count lst))]
(->> (cycle lst)
(drop-while #(not= item-a %))
rest
(take new-size)
cycle
(drop (mod index-diff new-size))
(take new-size)
(cons item-a)))))
#2022-12-2109:27Aleks@U064J0EFR how long will it calculate?#2022-12-2111:45bhaumanforever?#2022-12-2111:45bhaumana few minutes for sure#2022-12-2111:59oddsorI used a mutable list to perform the reordering to cut down the runtime from 80 seconds to 2 in my solution :face_with_open_eyes_and_hand_over_mouth:
Not too happy with that, but I couldn’t think of something more clever than just moving the numbers around in a data structure!
https://github.com/Oddsor/advent-of-code-clj/blob/master/src/y2022/d20.clj#2022-12-2400:55Eugene Huang> On the topic of edges, I originally spent at least 15 minutes of my first pass worrying about how to get things at the front or back of the cycle to work before I realized it didn’t matter as long as order was maintained. When you start from “0” it’s all the same.
omg… coming back to days i missed and i spent much more than 15 minutes trying to understand the edges until i saw this. 🙏#2022-12-2018:57AleksBtw, who remembers this? 🦀 🎲
https://www.reddit.com/r/adventofcode/comments/zqh272/2022_day_20_flashbacks/#2022-12-2020:14Miķelis Vindavsyep, the mod off by 1 error was what cost me the most time today 😞#2022-12-2106:33normanDay 21 - Solutions#2022-12-2106:46normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day21/main.clj
When part 2 came up, I wrote the code to generate an expression as a string. For the sample input, I was able to give that expression to wolfram alpha to solve, which it did. The full input was too long for wolfram. I was tempted to find something else that would solve it for kicks, but in the end i just wrote the code. The solver wasn't too hard, but it took at least an hour to figure out the cases correctly, which seems quite excessive...#2022-12-2111:18Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/21.clj
I did the symbolic manipulation... sort of. let human input be h
, then I kept track of the pair [a b]
(represents ah + b
) and then optimistically assumed that we'd never have to deal with an h^2
or h^-1
term... which turned out to be true 😅#2022-12-2111:45oddsorI’m not sure my solution works for all datasets 🙈
Instead of replacing the root operator with =
I replaced it with compare
and used it to recursively narrow down to the right number.
I created the expression as a list first and then created a function simplify
that postwalks up the expression and evaluates all lists that contain just an operator and a number.
https://github.com/Oddsor/advent-of-code-clj/blob/master/src/y2022/d21.clj#2022-12-2111:47genmeblogMacro for part-1 (still working on part-2):
(defn parse [line] (split-line line #":\s|\s"))
(def data (map parse (read-data 2022 21)))
(defmacro build-oparations
[]
`(do
#2022-12-2111:57Alekshttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_21.clj#2022-12-2112:28Callum Oakleytotally changed my approach since someone pointed out that the graph is a tree (should have been obvious given the "root" hint :face_with_rolling_eyes:). since it's a tree the resulting function is guaranteed to be linear in h
, so you can take the value at two points and extrapolate
https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/21.clj#L20-L24#2022-12-2112:33Aleks@U01HL2S0X71 brilliant, just came to the same#2022-12-2112:57AleksUpdated my part 2 https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_21.clj#L35-L42#2022-12-2114:59Alex AlemiI enjoyed today's puzzle. https://github.com/alexalemi/advent/blob/main/2022/clojure/p21.clj For the first part, I implemented a memoized recursive evaluator because I feared he would be unkind and have us recompute lots of things lots of times, but that turned out to be overkill. For part 2 I looked at the data and saw it was tree-like, so I wrote a solver but it simply 'unwinds' the equality at each stage. i.e. if we are sitting on a = x + b at the top, where a and b are numbers, we know that x = a - b. You can iterate this until you find the number.#2022-12-2115:15normanWow, yeah, it is linear. You can just search for it. (or compute it)#2022-12-2115:33tschadyUsing promises & futures. (I recycled my code with very few changes from 2015 day 7.)
These are the only 2 where I keep state, but I like how this reads:
(defn run-prog! [memory prog]
(reset! memory {})
(alloc-registers! memory prog)
(doseq [inst prog]
(exec-inst! memory inst)))
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2022/d21.clj#2022-12-2117:03misha;; p1
(let [parse (fn [line]
(let [[id x op y] (map read-string (str/split line #":?\s"))]
[id (if (number? x) x (list op x y))]))
db (->> input (str/split-lines) (map parse) (into {}))]
(->> 'root db
(clojure.walk/prewalk-replace db)
(eval)
(time)))
"Elapsed time: 30.751088 msecs"
=> 353837700405464
#2022-12-2120:13Felipepart 1 using promises. let me see if I can do the same for part 2
https://github.com/FelipeCortez/advent-of-code/blob/master/2022/21.clj#2022-12-2121:19bhaumanpart 2 “Elapsed time: 61.375238 msecs”#2022-12-2121:20bhaumanthis is a problem made for lispers#2022-12-2121:47bhaumanDay 21: This was the funnest one for me. I did the symbolic algebra.
https://github.com/bhauman/advent-of-code-2022/blob/main/src/adv2022/day21/sol.clj#2022-12-2121:56bhaumangeez I made the mistake of reading the other solutions… great job! not as much fun as symbolic solver 😉 but I wished I’d thought of the fact that it was a linear function. Would have definitely would have saved some time.#2023-12-0706:57rjrayStruggled way too much with sorting the hands within their ranks. And, of course, my first run of part 2 errored out for the obvious reason...#2023-12-0707:52erdosSolution: https://github.com/erdos/advent-of-code/blob/master/2023/day07.clj
for me, the trick was to call (comp sort vals frequencies)
on the String representation of each hand and it gives a signature that could be used to identify the type of hand.#2023-12-0707:58Sam Ferrellhttps://github.com/samcf/advent-of-code/blob/main/2023-07-camel-cards.clj
Nothing interesting here, just brute forcing joker combinations. Runs in about 1s#2023-12-0708:02oyakushevfrequencies
is MVP https://gist.github.com/alexander-yakushev/ff300602825af2d639276df3c456d457#2023-12-0708:03oyakushevHandling jokers is easy if you recognize that the most useful thing a joker can do is always counting as the other most frequent card in the hand. It is deterministic.#2023-12-0708:04Andrew Belohttps://github.com/andrewbelo/aoc2023/blob/1a4503fc67fcf1b8b82c6feb13726411db100ce4/src/day_7_camel_cards.clj
Also used frequencies#2023-12-0708:10Andrew BeloDidn't see the JJJJJ case ahead of time though :melting_face:#2023-12-0802:56mauricio.szaboKinda liked this one: https://gitlab.com/mauricioszabo/advent-of-code-2023-clj/-/blob/master/src/advent_2023_clj/day07.clj?ref_type=heads#2023-12-1313:54Ryan MartinI dont like it, but here's my solution: https://github.com/rmrt1n/advent-of-code-2023-clj/blob/main/src/aoc/day07.clj#2023-12-0805:59normanDay 8 - Solutions#2023-12-0806:11normanhttps://gitlab.com/maximoburrito/advent2023/-/blob/main/src/day08/main.clj
After getting tricked by not trying the brute force approach, this time I wasted time on a brute force solution. When it was clear it wouldn't work, I wrote some code to explore the data a bit. Thankfully all the cycles repeated exactly, so it it was easy to calculate the solution and math where they all meet.#2023-12-0806:20erdossolution: https://github.com/erdos/advent-of-code/blob/master/2023/day08.clj
went with counting reductions
over the cycle
of the instructions and using reduced
to shortcut.#2023-12-0807:12Andrew Belohttps://gist.github.com/andrewbelo/7d0ae27b04da17da2b44081fc81f985c
Pretty much the same solution, using reduce
over the cycle
#2023-12-0808:51Arnaud GeiserThank you norman for the hint.
https://github.com/arnaudgeiser/advent-of-code/blob/master/2023/clojure/src/advent_of_code/day8.clj#2023-12-0808:54karlishttps://github.com/skazhy/advent/blob/master/src/advent/2023/day8.clj nice and easy 🙂#2023-12-0809:32Piotr Kaznowski(Was lazy and added numeric-tower
to deps...)#2023-12-0900:49Michaël SalihiNice solution @UA2U3KW0L!
mapcat
would be a good candidate on line 11:
;;(into {} (comp (map parse-mapping) cat) mappings)
VS
(into {} (mapcat parse-mapping) mappings)
#2023-12-0900:51bhaumanmapcat isn’t a transducer though?#2023-12-0900:52Michaël SalihiMy version of day 8 part 1 : https://github.com/prestancedesign/advent-of-babashka-template/blob/main/src/aoc23/day08.cljc#2023-12-0900:55IvanaNot sure about transduser (need chek at clojredocs), but it is definitelly List monads bind, so that is why it widelly used in algorythms based on lists 😀#2023-12-0900:55bhaumanoh wait mapcat is a transducer it’s definition is (comp (map f) cat)
#2023-12-0910:43alpoxI guess that wouldn’t have been solvable without proper data inspection 👀#2023-12-1415:51Ryan Martinhere's my solution: https://github.com/rmrt1n/advent-of-code-2023-clj/blob/main/src/aoc/day08.clj#2024-01-2207:14cdpjenkinsI just did day 8 In Clojure, having previously done it Kotlin. I'm pretty proud of how much more succinct my Clojure solution (very functional) is than my Kotlin one (which is a bit more OO).
https://github.com/cdpjenkins/advent-of-code/blob/main/2023/clj-aoc-2023/src/clj_aoc_2023/day08.clj#2023-12-0905:20normanDay 9 - Solutions#2023-12-0905:22normanhttps://gitlab.com/maximoburrito/advent2023/-/blob/main/src/day09/main.clj#2023-12-0905:25wevremMy https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_09.clj.#2023-12-0905:28erdoshttps://github.com/erdos/advent-of-code/blob/master/2023/day09.clj
figured that a recursive solution is the simplest, although, it can be done with loop+recur and reduce as well.#2023-12-0905:37wevremMy https://github.com/wevre/advent-of-code/blob/3193fdd801e4a25fc104ceda5597b0f62ce05dda/notes/notes-aoc2023.txt#L210 for day 09.#2023-12-0905:39ACa surprisingly straight-forward puzzle for a weekend. I was expecting something much more complicated.#2023-12-0905:43normanI hadn't considered just using reverse for part 2.#2023-12-0905:51Applehttps://pastebin.com/raw/Jid9sHKf#2023-12-0905:51wevrem@U2E1D7WUB I like your reduce
version.#2023-12-0905:59erdos@UTFAPNRPT I like your use of transduce
!#2023-12-0906:01Alekshttps://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_09.clj#2023-12-0906:31Aleks@UTFAPNRPT nice solution, it helped me simplified mine ^_^#2023-12-0906:34wevremI’ve learned a lot from you over the years, @U067R559Q, I’m glad you are posting solutions.#2023-12-0906:59wevremA very, very https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_09_v2.clj after imbibing those of @U2E1D7WUB and @U067R559Q.#2023-12-0907:17wevrem@U067R559Q might I suggest you add a transducer arity to your take-until
?#2023-12-0907:21Aleks@UTFAPNRPT sure, actually I copied it from https://groups.google.com/g/clojure-dev/c/NaAuBz6SpkY#2023-12-0907:37AleksUntil the last year I strived to not use libraries at all. However, I guess it’d better to pick take-upto
from medley
now#2023-12-0908:04rjrayOK, I'm stumped. My puzzle data has to be corrupt or something. I wrote part 1, the answer I submitted was said to be too high. I've copy-pasted 4-5 different working solutions (in both Clojure and Python) and every one of them give the same answer for my input (the one my code produces). Anyone seen a similar problem?#2023-12-0908:12wevremIs there any chatter on reddit that puzzle data is iffy? It seems very unlikely that would go unnoticed.#2023-12-0908:14rjrayNone so far. I just posted an explicit question to that effect.#2023-12-0908:15rjrayI tried two Python solutions from reddit, and Apple's pastebin, and norman's original. All 4 gave the same answer my code does.#2023-12-0908:19wevremIs this helpful: my input had 200 lines.#2023-12-0908:20rjrayWell, Wastl himself answered saying that I had the right answer for my input, I should try entering it again really really carefully.
The third time, it worked...#2023-12-0908:24rjrayAnd, thanks to knowing the "reverse" trick, part 2 is already done. I'm really chuffed about part 1, though.#2023-12-0909:24karlisShort and sweet with iterate
+ take-while
and reduce
https://github.com/skazhy/advent/blob/master/src/advent/2023/day9.clj#2023-12-0911:49tschadynothing new to offer, except my often used intervals
helper:
(defn intervals
"Returns the seq of intervals between each element of `xs`, step `n` (default 1)"
([xs] (intervals 1 xs))
([n xs] (map - (drop n xs) xs)))
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2023/d09.clj#2023-12-0912:03alpoxThis was… much easier than expected 👀#2023-12-0912:48borkdude@U6JS7B99S his solution https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBPcmlnaW5hbCBzb2x1dGlvbiBieSBFbGlhcyBCZXJuaGF1dAoKOzsgUmVtZW1iZXIgdG8gdXBkYXRlIHRoZSB5ZWFyIGFuZCBkYXkgaW4gdGhlIGZldGNoLWlucHV0IGNhbGwuCihkZWYgaW5wdXQgKGpzLWF3YWl0IChmZXRjaC1pbnB1dCAyMDIzIDkpKSkKCihkZWZuIHBhcnNlLWxpbmUgW2xpbmVdIChtYXB2IHBhcnNlLWxvbmcgKHJlLXNlcSAjIi0%2FXGQrIiBsaW5lKSkpCgooZGVmbiBwYXJzZS1pbnB1dCBbaW5wdXRdIChtYXB2IHBhcnNlLWxpbmUgKHN0ci9zcGxpdC1saW5lcyBpbnB1dCkpKQoKKGRlZm4gZGlmZmVyZW5jZXMgW251bWJlcnNdICh2ZWMgKGZvciBbW2xlZnQgcmlnaHRdIChwYXJ0aXRpb24gMiAxIG51bWJlcnMpXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgtIHJpZ2h0IGxlZnQpKSkpCgooY29tbWVudAogIChwYXJzZS1pbnB1dCBpbnB1dCkKICAoZGlmZmVyZW5jZXMgWzEgMiAzXSkKICApCgooZGVmbiBkaWZmLXRyZWUgW251bWJlcnNdICgtPj4gKGl0ZXJhdGUgZGlmZmVyZW5jZXMgbnVtYmVycykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICh0YWtlLXdoaWxlICMobm90IChldmVyeT8gemVybz8gJSkpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJldmVyc2UpKSkKCihjb21tZW50CiAgKGRpZmYtdHJlZSBbMSAyIDNdKQogICkKCihkZWZuIGdlbmVyYXRlLW5leHQgW3JlZHVjZXIgbnVtYmVyc10KICAocmVkdWNlIHJlZHVjZXIgMCAoZGlmZi10cmVlIG51bWJlcnMpKSkKCihkZWZuIHJ1biBbaW5wdXQgcmVkdWNlcl0KICAoLT4%2BIChwYXJzZS1pbnB1dCBpbnB1dCkKICAgIChtYXAgKHBhcnRpYWwgZ2VuZXJhdGUtbmV4dCByZWR1Y2VyKSkKICAgIChhcHBseSArKSkpCgooZGVmbiBwYXJ0LTEgW2lucHV0XSAocnVuIGlucHV0IChmbiBbYWNjIHJvd10gKCsgYWNjIChsYXN0IHJvdykpKSkpCihkZWZuIHBhcnQtMiBbaW5wdXRdIChydW4gaW5wdXQgKGZuIFthY2Mgcm93XSAoLSAoZmlyc3Qgcm93KSBhY2MpKSkpCgooY29tbWVudAogIChwYXJ0LTEgaW5wdXQpCiAgKHBhcnQtMiBpbnB1dCkKICAp#2023-12-0913:42Arnaud GeiserNot a smart solution, but it works : https://github.com/arnaudgeiser/advent-of-code/blob/master/2023/clojure/src/advent_of_code/day9.clj#2023-12-0914:27genmeblogreverse
was a key https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day09.clj#2023-12-0914:27Felipespent a long time looking for a catch. no catch! was kind of proud until I saw the one liners
https://github.com/FelipeCortez/advent-of-code/blob/master/2023/09.clj#2023-12-0914:52IvanaEasy task, both parts in a same evaluation:
(->> input
str/split-lines
(map (fn [s]
(let [d (read-string (str "[" s "]"))
data (loop [v d
r (list d)]
(let [t (mapv - (rest v) v)]
(if (every? zero? t)
(cons t r)
(recur t (cons t r)))))]
(reduce (fn [{:keys [f l]} v]
{:f (- (first v) f)
:l (+ l (last v))})
{:f 0 :l 0} data))))
(apply merge-with +))
#2023-12-0915:38bhaumanDay 9 really rewards recursive thinking
https://github.com/bhauman/adv2023/blob/main/src/adv2023/day09/sol.clj#2023-12-0916:43borkdude@U064J0EFR amazing. https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBTb2x1dGlvbiBieSBiaGF1bWFuOgo7OyBodHRwczovL2dpdGh1Yi5jb20vYmhhdW1hbi9hZHYyMDIzL2Jsb2IvbWFpbi9zcmMvYWR2MjAyMy9kYXkwOS9zb2wuY2xqCgooZGVmIGlucHV0CiAgKC0%2BPiAoanMtYXdhaXQgKGZldGNoLWlucHV0IDIwMjMgOSkpCiAgICAoc3RyL3NwbGl0LWxpbmVzKQogICAgKG1hcCAjKGFzLT4gJSB4CiAgICAgICAgICAgIChzdHIgIlsiIHggIl0iKQogICAgICAgICAgICAoc3RyL3JlcGxhY2UgeCAiICIgIiwiKQogICAgICAgICAgICAoanMvSlNPTi5wYXJzZSB4KSkpKSkKCihkZWZuIGRpZmZzIFtsXQogICgtPj4gbCAocGFydGl0aW9uIDIgMSkgKG1hcHYgIyhhcHBseSAtIChyZXZlcnNlICUpKSkpKQoKKGRlZm4gbmV4dC1udW0gW251bS1zZXFdCiAgKGxldCBbZHMgKGRpZmZzIG51bS1zZXEpXQogICAgKGlmIChldmVyeT8gemVybz8gZHMpCiAgICAgIChsYXN0IG51bS1zZXEpCiAgICAgICgrIChsYXN0IG51bS1zZXEpCiAgICAgICAgKG5leHQtbnVtIGRzKSkpKSkKCjs7IHBhcnQgMQooY29tbWVudAogIChyZWR1Y2UgKyAobWFwIG5leHQtbnVtIGlucHV0KSkKICApCgooZGVmbiBwcmV2LW51bSBbbnVtLXNlcV0KICAobGV0IFtkcyAoZGlmZnMgbnVtLXNlcSldCiAgICAoaWYgKGV2ZXJ5PyB6ZXJvPyBkcykKICAgICAgKGZpcnN0IG51bS1zZXEpCiAgICAgICgtIChmaXJzdCBudW0tc2VxKQogICAgICAgIChwcmV2LW51bSBkcykpKSkpCgo7OyBwYXJ0IDIKKGNvbW1lbnQKICAocmVkdWNlICsgKG1hcCBwcmV2LW51bSBpbnB1dCkpCiAgKQ%3D%3D#2023-12-0916:49Charles Comstockhttps://github.com/dgtized/advent-of-code/blob/master/2023/src/day09/mirage_maintenance.clj#L1#2023-12-0918:21rjrayOK, now that I've slept and am a little less salty about the input glitching...
https://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day09.clj#2023-12-0921:41bhauman@U04V15CAJ oh very cool#2023-12-0921:51bhaumanI really like @U2E1D7WUB’s recursive solve
and the diffs
method as well.
(defn diffs [coll] (map - (next coll) coll))
Nice!#2023-12-0921:51borkdude@U064J0EFR if you want to switch to cherry, just change /squint/
to /cherry/
in the url#2023-12-0921:53bhauman@U04V15CAJ oh interesting. What’s the reload-ability story for squint?#2023-12-0921:54borkdudewhat do you mean reload-ability? as in incremental REPL behavior?#2023-12-0921:54bhaumanreloading namespaces?#2023-12-0921:56borkdudein the playground, if the REPL mode is on (see on the right). you can evaluate form by form using Cmd-Enter
reloading namespaces: I usually rely on vite
for hot-reloading with squint front-end projects + squint watch
for re-compiling changes files#2023-12-0921:56borkdudehere is an example of that https://github.com/squint-cljs/squint/tree/main/examples/vite-react#2023-12-1001:26RaghavLove me some iterate magix.#2023-12-1102:01rjrayUsing @U05H1PF60G1's iterate
magic, I revised my Day 9:
https://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day09bis.clj#2023-12-1102:01rjrayCut the run-times in half.#2023-12-1416:40Ryan MartinDay 9 is like a breath of fresh air: https://github.com/rmrt1n/advent-of-code-2023-clj/blob/main/src/aoc/day09.clj#2023-12-1006:37wevremDay 10 - Solutions#2023-12-1006:38wevremI have my stars for Day 10, but boy it was a slog. I’ve got to clean up my code a bit before I post. Probably in the morning (my morning).#2023-12-1006:52wevremMy (not very elegant) https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_10_pipes.clj.#2023-12-1007:22normanhttps://gitlab.com/maximoburrito/advent2023/-/blob/main/src/day10/main.clj I couldn't figure out how to make what I thought was the obvious solution work, so instead I literally converted the pipe map to 3x size so I could do a trivial bfs to find what is inside and outside. Looking at @UTFAPNRPT's solution, I'm still not entirely sure why it works and why you don't have to also check vertically, but I'm sure it'll make more sense in the morning 🙂#2023-12-1007:33erdoshttps://github.com/erdos/advent-of-code/blob/master/2023/day10.clj
For the second part, I went through the path again and cleared all other cells. Then I went thought the path the third time and kept track of the cells to my left hand side and used these as an input to a flood fill.#2023-12-1007:34wevremI did an https://en.wikipedia.org/wiki/Point_in_polygon algorithm for determining whether a point is inside a polygon. I tried to be fancy and check along rows or columns depending on which edge was closer, but I gave that up and just checked ‘above’.#2023-12-1007:34erdoslooks like we have 3 merely different approaches so far.#2023-12-1007:36wevremThe trick was that if these types of patterns are above a point:
7 F
| |
J L
they don’t count as crossing, but these do count:
7 F
| |
L J
and obviously
-
counts as a crossing.#2023-12-1009:31Aleks@UTFAPNRPT thanks a lot for pointing to https://en.wikipedia.org/wiki/Point_in_polygon and the trick, it helped me solve the part 2 🙌:skin-tone-2:. I’m not good at geometry ☺️#2023-12-1015:07Alekscleaned the code up, wrote a fn to determine start shape https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_10.clj#2023-12-1018:14rjrayAlso used the even-odd rule for part 2. Part 1 was fun, if kind of long to code. I'll be revising this code later; I have some hard-coded values I don't like to see.
https://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day10.clj#2023-12-1018:48IvanaNice task! For part 2 after unsuccessful tries with ray-crossing etc finally I just zoomed input field in 2 times, fill the area and check allinitial tiles in filled set. A bit surprized that we have to calculate all internal tiles (not only ground), so I had to make my zoom pipes different than initial ones.#2023-12-1019:39Arnaud GeiserAll credits go to @UTFAPNRPT, but here I am : https://github.com/arnaudgeiser/advent-of-code/blob/master/2023/clojure/src/advent_of_code/day10.clj#2023-12-1019:51genmeblogHere is how the pipe looks like.#2023-12-1019:55Aleks#2023-12-1020:08genmeblogAnd my verbose solution... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day10.clj#2023-12-1020:39FelipeI'm so close, but my flood fill is filling everything 😕#2023-12-1020:58IvanaAnd mine zoomed x2#2023-12-1100:16FelipeI got it! spent more than one hour looking for a hole in my flood fill. off by one error; turns out I was skipping the position adjacent to the starting one. for part 2 I decided to zoom in like @U05T4JC21J6
(def expand
{\| [".X."
".X."
".X."]
\- ["..."
"XXX"
"..."]
\L [".X."
".XX"
"..."]
\7 ["..."
"XX."
".X."]
\J [".X."
"XX."
"..."]
\F ["..."
".XX"
".X."]
\. ["..."
"..."
"..."]})
debugging this one was a chore, but very satisfying to get it right at the end
https://github.com/FelipeCortez/advent-of-code/blob/master/2023/10.clj#2023-12-1105:29bhaumanDay 10
https://github.com/bhauman/adv2023/blob/main/src/adv2023/day10/sol.clj#2023-12-1117:03m_travenHi folks! My Day 10 https://github.com/mtravers/aoc2023/blob/main/src/aoc2023/day10.clj#2023-12-1215:36danielnealOmg day 10 took far too long, I think it’s time for me to bow out of advent of code so I have some headspace for my real job
https://github.com/danielneal/advent-of-code-2023/blob/main/src/day10.clj#2023-12-1220:20alpoxThis one took me much too long and the code didn’t end up nice either 😕 at least its solved… Also went with the even-odd rule#2023-12-1105:42wevremDay 11 - Solutions#2023-12-1105:43wevremMy https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_11_galaxies.clj.#2023-12-1105:43erdoshttps://github.com/erdos/advent-of-code/blob/master/2023/day11.clj
used sorted-set to quickly find the empty rows/cols in the path between two galaxies.#2023-12-1105:45wevremI like the use of sorted set. I’ve never used that before. I just rolled my own. :-)#2023-12-1105:57erdossorted-set only helps if you keep track of the gaps instead of the galaxies (this universe is dense so there are much more galaxies than gaps)#2023-12-1106:05wevremthat makes sense. I also just kept track of the gaps, but not with a sorted set. Just with a sorted list and then (this is what I meant by “rolled my own”) I filtered based on the two subject galaxies. I assume that is basically what a sorted set does, though perhaps more efficiently?#2023-12-1106:12erdosyes, sorted-set is practically a tree that can be used for fast interval search.
but since you used filter
, sorting the seq was really not necessary?#2023-12-1106:13wevremtrue. I think it was left over from an initial plan of maybe using drop and take. Just stayed in the code there even though it was no longer needed.#2023-12-1106:18wevremTomorrow I’m going to learn more about sorted set and play around with a version 2. Good night!#2023-12-1106:43Aleksnot fancy, but it just does its job
https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_11.clj#2023-12-1107:25Aleks@U2E1D7WUB I like your solution. Don’t remember if I’ve ever used subseq
before. Looks like a good place to employ it#2023-12-1109:31tschadyfirst pass, used the excellent tails
I got from somebody here last year to get the combos:
https://github.com/tschady/advent-of-code/blob/main/src/aoc/2023/d11.clj#2023-12-1110:14genmeblogSame as others I suppose. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day11.clj#2023-12-1110:47AleksGot rid of the extra passes of the input. All we need is galaxies coordinates, so we can build sets of it and then use it to find spaces
https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_11.clj#2023-12-1111:26Piotr KaznowskiI chose "brutal" list operations to get coordinates instead of smart arithmetic... https://github.com/caseneuve/aoc2023/blob/master/day11/solution.clj#2023-12-1111:51IvanaAfter some fixes & improvements
(let [scale 1000000 ;; 2
gals (->> input (keep-indexed #(when (= \# %2) %1)))
d (-> input (str/index-of \newline) inc)
[grs gcs] (map (fn [f] (->> gals (map #(f % d)) set)) [quot rem])
dn (fn [a b s] (->> (range (min a b) (max a b))
(reduce (fn [acc i] (+ acc (if (get s i) 1 scale))) 0)))]
(->> (for [a gals
b gals
:when (< a b)]
(let [[[r1 c1] [r2 c2]] (map #(vector (quot % d) (rem % d)) [a b])]
(+ (dn r1 r2 grs) (dn c1 c2 gcs))))
(apply +)))
#2023-12-1114:07borkdudeI took @U2E1D7WUB his solution and added stuff to #C03U8L2NXNC until it worked (mostly sorted-set and subseq)
https://squint-cljs.github.io/squint/?repl=true&boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxMSkpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMpKQooZGVmIGdyaWQgKG1hcHYgdmVjIGlucHV0KSkKCihkZWYgZW1wdHktcm93cwogIChpbnRvIChzb3J0ZWQtc2V0KQogICAgKGtlZXAtaW5kZXhlZCAoZm4gW2kgcm93XSAod2hlbiAoZXZlcnk%2FICN7XC59IHJvdykgaSkpKQogICAgZ3JpZCkpCgooZGVmbiB0cmFuc3Bvc2UgW210eF0KICAodmVjCiAgICAoZm9yIFtpIChyYW5nZSAoY291bnQgKGZpcnN0IG10eCkpKV0KICAgICAgKHZlYyAoZm9yIFtqIChyYW5nZSAoY291bnQgbXR4KSldCiAgICAgICAgICAgICAoLT4gbXR4IChudGggaikgKG50aCBpKSkpKSkpKQoKKGRlZiBlbXB0eS1jb2xzCiAgKGludG8gKHNvcnRlZC1zZXQpCiAgICAoa2VlcC1pbmRleGVkIChmbiBbaiBjb2xdICh3aGVuIChldmVyeT8gI3tcLn0gY29sKSBqKSkpCiAgICAodHJhbnNwb3NlIGdyaWQpKSkKCihkZWYgZ2FsYXhpZXMKICAoZm9yIFtbaSByb3ddIChtYXAtaW5kZXhlZCB2ZWN0b3IgZ3JpZCkKICAgICAgICBbaiBjZWxsXSAobWFwLWluZGV4ZWQgdmVjdG9yIHJvdykKICAgICAgICA6d2hlbiAoPSBcIyBjZWxsKV0KICAgIFtpIGpdKSkKCihjb21tZW50CiAgKGNvdW50IGdhbGF4aWVzKQogICkKCihkZWZuIG1hbmhhdHRhbjIgW1thIGJdIFt4IHldIHNjYWxlXQogIChsZXQgW2FhIChjb3VudCAoc3Vic2VxIGVtcHR5LXJvd3MgPiAobWluIGEgeCkgPCAobWF4IGEgeCkpKQogICAgICAgIGJiIChjb3VudCAoc3Vic2VxIGVtcHR5LWNvbHMgPiAobWluIGIgeSkgPCAobWF4IGIgeSkpKV0KICAgICgrIChhYnMgKC0gYSB4KSkKICAgICAgKGFicyAoLSBiIHkpKQogICAgICAoKiAoZGVjIHNjYWxlKSAoKyBhYSBiYikpKSkpCgooY29tbWVudAogIChtYW5oYXR0YW4yIChmaXJzdCBnYWxheGllcykgKHNlY29uZCBnYWxheGllcykgMikKICApCgooZGVmbiBzb2x2ZSBbbGFiZWwgc2NhbGVdCiAgKC0%2BPiAoZm9yIFthIGdhbGF4aWVzLGIgZ2FsYXhpZXNdIChtYW5oYXR0YW4yIGEgYiBzY2FsZSkpCiAgICAocmVkdWNlICspCiAgICAoKiAxLzIpIChsb25nKQogICAgKHRpbWUpKSkKCihjb21tZW50CiAgKHNvbHZlICJGaXJzdCIgMikKICAoc29sdmUgIlNlY29uZCIgMTAwMDAwMCkKICAp#2023-12-1116:03Felipetook me a while to realize that
(defn shortest-path-length [[j1 i1] [j2 i2]]
(let [[[j1 i1] [j2 i2]] [[(min j1 j2) (min i1 i2)] [(max j1 j2) (max i1 i2)]]]
(count
(take-while #(not= % [j2 i2])
(iterate (fn [[p1 p2]]
(if (< (dist [(inc p1), p2 ] [j2 i2])
(dist [ p1, (inc p2)] [j2 i2]))
[(inc p1), p2]
[ p1, (inc p2)]))
[j1 i1])))))
is just
(defn shortest-path-length [[j1 i1] [j2 i2]]
(+ (abs (- j1 j2)) (abs (- i1 i2))))
map expansion logic was also a bit tricky to get right. happy with my solution!
https://github.com/FelipeCortez/advent-of-code/blob/master/2023/11.clj#2023-12-1116:06FelipeI always have the ugliest code to deal with grids represented as nested vecs. this is very nice:
[[i row] (map-indexed vector grid)
[j cell] (map-indexed vector row)
#2023-12-1116:27IvanaThere were already a lot of tasks with 2D-array model input. And most of the participants parsed it from string to vector of vectors, and then feel pain vith indexing, iteration, filtering etc. I suggest you keep it as it is - as string 😀 It supports get
by index, it implements associative?
and return nils on indices outside of its range, it may be easy processed with keep-indexed
, str/index-of
, regex etc. Only thing you have to do for modelling 2D array with it - convert one linear index to 2 2D. But keep in mind, that even raw C-like 2D arrays are actually 1D arrays with indices converting by quot & rem
, so you may do it by yourself and get away from naive "2D" arrays model of most langs (Java/C/etc). You may look into my this aoc tasks code solutions for examples & details#2023-12-1116:28Felipe@U05T4JC21J6 nice! makes sense#2023-12-1119:06rjrayMy solution:
https://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day11.clj
Not my best code, because I did part 1 by actually expanding the matrix representation of the input "image". The pure-math code for part 2 can easily be made to work with part 1. I'll do a revision of this one later.#2023-12-1121:28Arnaud GeiserIt went quite well, thanks to clojure.math.combinatorics : https://github.com/arnaudgeiser/advent-of-code/blob/master/2023/clojure/src/advent_of_code/day11.clj#2023-12-1121:33Ivana(comb/permuted-combinations locations 2)
may be simply implemented as
(->> (for [a locations
b locations
:when (< a b)]
without extra libs#2023-12-1121:36Arnaud GeiserThank you Ivana for the hint!#2023-12-1121:38IvanaActually in your case when location is vector <
may not work but you may use (pos? (compare a b))
#2023-12-1121:39Arnaud GeiserWorks like a charm : https://github.com/arnaudgeiser/advent-of-code/blob/master/2023/clojure/src/advent_of_code/day11.clj#L25#2023-12-1122:40bhaumanDay 11 - for part 2 I just translated the initial coords into the new expanded coord system.
https://github.com/bhauman/adv2023/blob/main/src/adv2023/day11/sol.clj#2023-12-1203:28standI know from many years of running that if you want to get from point A to point B, it's the same number of blocks regardless of what path you take. 😃#2023-12-1204:03m_travenhttps://github.com/mtravers/aoc2023/blob/main/src/aoc2023/day11.clj Fortunate that I did part 1 in a way that made part 2 trivial.#2023-12-1208:04roklenarcicI accumulated coordinate adjustments with reductions
:
https://gist.github.com/RokLenarcic/00a3a14c975d0ace582ff9a3695226b0#2023-12-1218:49Felipe@U0608BDQE relevant xkcd, maybe https://xkcd.com/85/#2023-12-1317:40alpoxThis was quite a bit more chill than d10#2023-12-1206:13AleksDay 12 - Solutions 🤯#2023-12-1206:37erdoshttps://github.com/erdos/advent-of-code/blob/master/2023/day12.clj
memoize
can help speed up the recursive calls. This seems to be a dynamic programming problem, where we can quickly match the prefix of a pattern, and then recursively process all the possible suffixes of the remaining pattern as well.#2023-12-1207:59roklenarcicyeah this one was easy just wrap the whole thing in memoize#2023-12-1208:00roklenarcicSidenote, no idea why it takes 26ms to fetch a memoized solution…
(time (p2 input))
"Elapsed time: 26.741197 msecs"
#2023-12-1210:16borkdudewhen objects are not identical, you have to determine value equality. for big objects this can entail walking the entire object graph. not sure if that is into play here but could be#2023-12-1214:31borkdude@U2E1D7WUB’s solution in https://squint-cljs.github.io/cherry/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBsaW5lcyAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxMikpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMpKQoKKGRlZm4gcGFyc2UtbGluZSBbbGluZV0KICAobGV0IFtbcm93IG5yc10gKC5zcGxpdCBsaW5lICIgIildCiAgICBbKHN0ciAoLnJlcGxhY2VBbGwgcm93ICJcXC5cXC4rIiAiLiIpKQogICAgIChtYXAgcGFyc2UtbG9uZyAoLnNwbGl0IG5ycyAiLCIpKV0pKQoKKGRlZm4gdmFsaWQtc3VmZml4ZXMgW3JvdyBudW1iZXJdCiAgKGZvciBbaSAocmFuZ2UgKGluYyAoLSAoY291bnQgcm93KSBudW1iZXIpKSkKICAgICAgICA6d2hpbGUgKGV2ZXJ5PyAje1wuIFw%2FfSAodGFrZSBpIHJvdykpCiAgICAgICAgOndoZW4gKGV2ZXJ5PyAje1wjIFw%2FfSAodGFrZSBudW1iZXIgKGRyb3AgaSByb3cpKSkKICAgICAgICA6d2hlbiAoI3tcLiBcP30gKG50aCByb3cgKCsgaSBudW1iZXIpIFwuKSldCiAgICAoZHJvcCAoKyBpIG51bWJlciAxKSByb3cpKSkKCihkZWZuIGFjcyBbcm93IG51bWJlcnNdCiAgKGlmLWxldCBbW24gJiBucnNdIChzZXEgbnVtYmVycyldCiAgICAocmVkdWNlICsgKGZvciBbcyAodmFsaWQtc3VmZml4ZXMgcm93IG4pXSAoYWNzIHMgbnJzKSkpCiAgICAoaWYgKGV2ZXJ5PyAje1wuIFw%2FfSByb3cpIDEgMCkpKQoKKGRlZiBhY3MgKG1lbW9pemUgYWNzKSkKCjs7IHBhcnQgMQooY29tbWVudAogICgtPj4gbGluZXMKICAgIChtYXAgcGFyc2UtbGluZSkKICAgIChtYXAgKHBhcnRpYWwgYXBwbHkgYWNzKSkKICAgIChyZWR1Y2UgKykKICAgICh0aW1lKSkpCgooZGVmbiAqNSBbW2xpbmUgcnVsZV1dCiAgWyhzdHIvam9pbiAiPyIgKHJlcGVhdCA1IGxpbmUpKQogICAoYXBwbHkgY29uY2F0IChyZXBlYXQgNSBydWxlKSldKQoKOzsgcGFydCAyCihjb21tZW50CiAgKGFzLT4gbGluZXMgJAogICAgKG1hcCBwYXJzZS1saW5lICQpCiAgICAobWFwICo1ICQpCiAgICAobWFwIChwYXJ0aWFsIGFwcGx5IGFjcykgJCkKICAgIChyZWR1Y2UgKyAkKQogICAgKGpzLWF3YWl0ICQpCiAgICAodGltZSAkKSkp#2023-12-1214:31borkdudeI tried to use https://github.com/bruceon/jsworkers for pmap
but couldn't get it to work in just the browser with dynamic import etc#2023-12-1216:01oyakushevCaching solution, 230ms.
(ns day12
(:require [clojure.string :as str]
[clojure.java.io :as io]))
(def lines (line-seq (io/reader "2023/day12.txt")))
(def parsed
(for [line lines]
(let [[field hints] (str/split line #" ")]
[(str "." (str/join "?" (repeat 5 field)) ".")
(vec (apply concat (repeat 5 (map parse-long (str/split hints #",")))))]
#_[(str "." field ".") (map parse-long (str/split hints #","))])))
(defn variants [[^String field, hints]]
(let [cache (volatile! {})]
(letfn [(f [i j start c]
(let [key (+ (* 10000 i) j)]
(or (and (nil? c) (nil? start) (@cache key))
(let [c (or c (when (< i (.length field))
(.charAt field i)))]
(case c
nil (if (= j (count hints)) 1 0)
\. (if start
(let [len (- i start)]
(if (= len (nth hints j nil))
(recur (inc i) (inc j) nil nil)
0))
(recur (inc i) j nil nil))
\# (recur (inc i) j (or start i) nil)
\? (let [res (+ (f i j start \.)
(f i j start \#))]
(when (nil? start)
(vswap! cache assoc key res))
res))))))]
(f 0 0 nil nil))))
(defn task2 []
(time (reduce + (map variants parsed))))
#2023-12-1218:44borkdude@U06PNK4HG’s solution https://squint-cljs.github.io/cherry/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cjs7IFJlbWVtYmVyIHRvIHVwZGF0ZSB0aGUgeWVhciBhbmQgZGF5IGluIHRoZSBmZXRjaC1pbnB1dCBjYWxsLgooZGVmIGxpbmVzICgtPj4gKGpzLWF3YWl0IChmZXRjaC1pbnB1dCAyMDIzIDEyKSkKICAgICAgICAgICAgIHN0ci9zcGxpdC1saW5lcykpCgooZGVmIHBhcnNlZAogIChmb3IgW2xpbmUgbGluZXNdCiAgICAobGV0IFtbZmllbGQgaGludHNdIChzdHIvc3BsaXQgbGluZSAjIiAiKV0KICAgICAgWyhzdHIgIi4iIChzdHIvam9pbiAiPyIgKHJlcGVhdCA1IGZpZWxkKSkgIi4iKQogICAgICAgKHZlYyAoYXBwbHkgY29uY2F0IChyZXBlYXQgNSAobWFwIHBhcnNlLWxvbmcgKHN0ci9zcGxpdCBoaW50cyAjIiwiKSkpKSldCiAgICAgICNfWyhzdHIgIi4iIGZpZWxkICIuIikgKG1hcCBwYXJzZS1sb25nIChzdHIvc3BsaXQgaGludHMgIyIsIikpXSkpKQoKKGRlZm4gdmFyaWFudHMgW1teU3RyaW5nIGZpZWxkLCBoaW50c11dCiAgKGxldCBbY2FjaGUgKGF0b20ge30pXQogICAgKGxldGZuIFsoZiBbaSBqIHN0YXJ0IGNdCiAgICAgICAgICAgICAgKGxldCBba2V5ICgrICgqIDEwMDAwIGkpIGopXQogICAgICAgICAgICAgICAgKG9yIChhbmQgKG5pbD8gYykgKG5pbD8gc3RhcnQpIChAY2FjaGUga2V5KSkKICAgICAgICAgICAgICAgICAgICAobGV0IFtjIChvciBjICh3aGVuICg8IGkgKC4tbGVuZ3RoIGZpZWxkKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKC5jaGFyQXQgZmllbGQgaSkpKV0KICAgICAgICAgICAgICAgICAgICAgIChjYXNlIGMKICAgICAgICAgICAgICAgICAgICAgICAgbmlsIChpZiAoPSBqIChjb3VudCBoaW50cykpIDEgMCkKICAgICAgICAgICAgICAgICAgICAgICAgXC4gKGlmIHN0YXJ0CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGxldCBbbGVuICgtIGkgc3RhcnQpXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGlmICg9IGxlbiAobnRoIGhpbnRzIGogbmlsKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlY3VyIChpbmMgaSkgKGluYyBqKSBuaWwgbmlsKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocmVjdXIgKGluYyBpKSBqIG5pbCBuaWwpKQogICAgICAgICAgICAgICAgICAgICAgICBcIyAocmVjdXIgKGluYyBpKSBqIChvciBzdGFydCBpKSBuaWwpCiAgICAgICAgICAgICAgICAgICAgICAgIFw%2FIChsZXQgW3JlcyAoKyAoZiBpIGogc3RhcnQgXC4pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZiBpIGogc3RhcnQgXCMpKV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAod2hlbiAobmlsPyBzdGFydCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChzd2FwISBjYWNoZSBhc3NvYyBrZXkgcmVzKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXMpKSkpKSldCiAgICAgIChmIDAgMCBuaWwgbmlsKSkpKQoKKGRlZm4gdGFzazIgW10KICAodGltZSAocmVkdWNlICsgKG1hcCB2YXJpYW50cyBwYXJzZWQpKSkp - somehow the squint version doesn't work properly, gonna check now#2023-12-1218:55borkdudehttps://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBvcmlnaW5hbCBzb2x1dGlvbiBieSBAYWxleHlha3VzaGV2Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBsaW5lcyAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxMikpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMpKQoKKGRlZiBwYXJzZWQKICAodmVjIChmb3IgW2xpbmUgbGluZXNdCiAgICAobGV0IFtbZmllbGQgaGludHNdIChzdHIvc3BsaXQgbGluZSAjIiAiKV0KICAgICAgWyhzdHIgIi4iIChzdHIvam9pbiAiPyIgKHJlcGVhdCA1IGZpZWxkKSkgIi4iKQogICAgICAgKHZlYyAoYXBwbHkgY29uY2F0IChyZXBlYXQgNSAobWFwIHBhcnNlLWxvbmcgKHN0ci9zcGxpdCBoaW50cyAjIiwiKSkpKSldCiAgICAgICNfWyhzdHIgIi4iIGZpZWxkICIuIikgKG1hcCBwYXJzZS1sb25nIChzdHIvc3BsaXQgaGludHMgIyIsIikpXSApKSkpCgooZGVmbiB2YXJpYW50cyBbW15TdHJpbmcgZmllbGQsIGhpbnRzXV0KICAobGV0IFtjYWNoZSAoYXRvbSB7fSldCiAgICAobGV0Zm4gWyhmIFtpIGogc3RhcnQgY10KICAgICAgICAgICAgICAobGV0IFtjIChvciBjIG5pbCkKICAgICAgICAgICAgICAgICAgICBrZXkgKCsgKCogMTAwMDAgaSkgaildCiAgICAgICAgICAgICAgICAob3IgKGFuZCAobmlsPyBjKSAobmlsPyBzdGFydCkgKGdldCBAY2FjaGUga2V5KSkKICAgICAgICAgICAgICAgICAgICAobGV0IFtjIChvciBjICh3aGVuICg8IGkgKC4tbGVuZ3RoIGZpZWxkKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKC5jaGFyQXQgZmllbGQgaSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5pbCldCiAgICAgICAgICAgICAgICAgICAgICAoY2FzZSBjCiAgICAgICAgICAgICAgICAgICAgICAgIG5pbCAoaWYgKD0gaiAoY291bnQgaGludHMpKSAxIDApCiAgICAgICAgICAgICAgICAgICAgICAgIFwuIChpZiBzdGFydAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIChsZXQgW2xlbiAoLSBpIHN0YXJ0KV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChpZiAoPSBsZW4gKG50aCBoaW50cyBqIG5pbCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZWN1ciAoaW5jIGkpIChpbmMgaikgbmlsIG5pbCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlY3VyIChpbmMgaSkgaiBuaWwgbmlsKSkKICAgICAgICAgICAgICAgICAgICAgICAgXCMgKHJlY3VyIChpbmMgaSkgaiAob3Igc3RhcnQgaSkgbmlsKQogICAgICAgICAgICAgICAgICAgICAgICBcPyAobGV0IFtyZXMgKCsgKGYgaSBqIHN0YXJ0IFwuKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGYgaSBqIHN0YXJ0IFwjKSldCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHdoZW4gKG5pbD8gc3RhcnQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoc3dhcCEgY2FjaGUgYXNzb2Mga2V5IHJlcykpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzKSkpKSkpXQogICAgICAoZiAwIDAgbmlsIG5pbCkpKSkKCihkZWZuIHRhc2syIFtdCiAgKHRpbWUgKHJlZHVjZSArIChtYXAgdmFyaWFudHMgcGFyc2VkKSkpKQ%3D%3D facepalm and it's a lot slower, so need to check why#2023-12-1219:05roklenarcicmine: https://gist.github.com/RokLenarcic/ce35afd4d5c72c825f5961442d937c70#2023-12-1219:05roklenarcictakes about 1.5 sec#2023-12-1219:11roklenarcicIt tries to match the whole group in one step. So if you have 3
as group count it will try to remove prefix of 3 ?
or #
and an additional .
or ?
, immediately returning 0 if not able.#2023-12-1219:13roklenarcicProbably could make it faster by accessing string characters by index, instead of using string as a seq, but the code would be way uglier#2023-12-1219:17rjrayhttps://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day12.clj
Solved part 1 with brute force, then did a little analysis on how big part 2 was. Chose to sleep. Today, due to time-constraints, I just adapted a DP solution from some Python. I knew it needed to be a DP solution with memoize
, but it was this or spend hours reviewing my DP notes...#2023-12-1219:48borkdude@U06PNK4HG’s solution in https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBvcmlnaW5hbCBzb2x1dGlvbiBieSBAYWxleHlha3VzaGV2Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBsaW5lcyAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxMikpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMpKQoKKGRlZiBwYXJzZWQKICAodmVjIChmb3IgW2xpbmUgbGluZXNdCiAgICAgICAgIChsZXQgW1tmaWVsZCBoaW50c10gKHN0ci9zcGxpdCBsaW5lICMiICIpXQogICAgICAgICAgIFsoc3RyICIuIiAoc3RyL2pvaW4gIj8iIChyZXBlYXQgNSBmaWVsZCkpICIuIikKICAgICAgICAgICAgKHZlYyAoYXBwbHkgY29uY2F0IChyZXBlYXQgNSAobWFwIHBhcnNlLWxvbmcgKHN0ci9zcGxpdCBoaW50cyAjIiwiKSkpKSldCiAgICAgICAgICAgI19bKHN0ciAiLiIgZmllbGQgIi4iKSAobWFwIHBhcnNlLWxvbmcgKHN0ci9zcGxpdCBoaW50cyAjIiwiKSldICkpKSkKCihkZWZuIHZhcmlhbnRzIFtbXlN0cmluZyBmaWVsZCxoaW50c11dCiAgKGxldCBbY2FjaGUge31dCiAgICAobGV0Zm4gWyhmIFtpIGogc3RhcnQgY10KICAgICAgICAgICAgICAobGV0IFtjIChvciBjIG5pbCkKICAgICAgICAgICAgICAgICAgICBrZXkgKCsgKCogMTAwMDAgaSkgaildCiAgICAgICAgICAgICAgICAob3IgKGFuZCAobmlsPyBjKSAobmlsPyBzdGFydCkgKGdldCBjYWNoZSBrZXkpKQogICAgICAgICAgICAgICAgICAobGV0IFtjIChvciBjICh3aGVuICg8IGkgKC4tbGVuZ3RoIGZpZWxkKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICguY2hhckF0IGZpZWxkIGkpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmlsKV0KICAgICAgICAgICAgICAgICAgICAoaWYtbm90IGMgKGlmICg9IGogKGNvdW50IGhpbnRzKSkgMSAwKQogICAgICAgICAgICAgICAgICAgICAgKGNhc2UgYwogICAgICAgICAgICAgICAgICAgICAgICBcLiAoaWYgc3RhcnQKICAgICAgICAgICAgICAgICAgICAgICAgICAgKGxldCBbbGVuICgtIGkgc3RhcnQpXQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIChpZiAoPSBsZW4gKG50aCBoaW50cyBqIG5pbCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocmVjdXIgKGluYyBpKSAoaW5jIGopIG5pbCBuaWwpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlY3VyIChpbmMgaSkgaiBuaWwgbmlsKSkKICAgICAgICAgICAgICAgICAgICAgICAgXCMgKHJlY3VyIChpbmMgaSkgaiAob3Igc3RhcnQgaSkgbmlsKQogICAgICAgICAgICAgICAgICAgICAgICBcPyAobGV0IFtyZXMgKCsgKGYgaSBqIHN0YXJ0IFwuKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGYgaSBqIHN0YXJ0IFwjKSldCiAgICAgICAgICAgICAgICAgICAgICAgICAgICh3aGVuIChuaWw%2FIHN0YXJ0KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIChhc3NvYyEgY2FjaGUga2V5IHJlcykpCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcykpKSkpKSldCiAgICAgIChmIDAgMCBuaWwgbmlsKSkpKQoKKGRlZm4gdGFzazIgW10KICAodGltZSAocmVkdWNlICsgKG1hcCB2YXJpYW50cyBwYXJzZWQpKSkp#2023-12-1219:52genmeblogI hate it... Three complete rewrites for part 2... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day12.clj#2023-12-1219:55borkdude@U06PNK4HG do you have your part 1 also somewhere? I'd like to include it in the squint hall of fame solutions ;)#2023-12-1219:56oyakushevLet me edit my comment#2023-12-1219:59oyakushevActually, here https://gist.github.com/alexander-yakushev/7f40fbafa4fa29b93706ca823be4250a#2023-12-1220:03borkdude@U06PNK4HG https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBvcmlnaW5hbCBzb2x1dGlvbiBieSBAYWxleHlha3VzaGV2Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBsaW5lcyAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxMikpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMpKQoKKGRlZm4gcGFyc2UgW3Rhc2tdCiAgKHZlYyAoZm9yIFtsaW5lIGxpbmVzXQogICAgICAgICAobGV0IFtbZmllbGQgaGludHNdIChzdHIvc3BsaXQgbGluZSAjIiAiKV0KICAgICAgICAgICAoY2FzZSB0YXNrCiAgICAgICAgICAgICAxIFsoc3RyICIuIiBmaWVsZCAiLiIpIChtYXAgcGFyc2UtbG9uZyAoc3RyL3NwbGl0IGhpbnRzICMiLCIpKV0KICAgICAgICAgICAgIDIgWyhzdHIgIi4iIChzdHIvam9pbiAiPyIgKHJlcGVhdCA1IGZpZWxkKSkgIi4iKQogICAgICAgICAgICAgICAgKGludG8gW10gKGFwcGx5IGNvbmNhdCAocmVwZWF0IDUgKG1hcCBwYXJzZS1sb25nIChzdHIvc3BsaXQgaGludHMgIyIsIikpKSkpXSkpKSkpCgooZGVmbiB2YXJpYW50cyBbW15TdHJpbmcgZmllbGQsaGludHNdXQogIChsZXQgW2NhY2hlIHt9XQogICAgKGxldGZuIFsoZiBbaSBqIHN0YXJ0IGNdCiAgICAgICAgICAgICAgKGxldCBba2V5ICgrICgqIDEwMDAwIGkpIGopXQogICAgICAgICAgICAgICAgKG9yIChhbmQgKG5pbD8gYykgKG5pbD8gc3RhcnQpIChnZXQgY2FjaGUga2V5KSkKICAgICAgICAgICAgICAgICAgKGxldCBbYyAob3IgYyAod2hlbiAoPCBpICguLWxlbmd0aCBmaWVsZCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoLmNoYXJBdCBmaWVsZCBpKSkpXQogICAgICAgICAgICAgICAgICAgIChpZi1ub3QgYyAoaWYgKD0gaiAoY291bnQgaGludHMpKSAxIDApCiAgICAgICAgICAgICAgICAgICAgICAoY2FzZSBjCiAgICAgICAgICAgICAgICAgICAgICAgIFwuIChpZiBzdGFydAogICAgICAgICAgICAgICAgICAgICAgICAgICAobGV0IFtsZW4gKC0gaSBzdGFydCldCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGlmICg9IGxlbiAobnRoIGhpbnRzIGogbmlsKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZWN1ciAoaW5jIGkpIChpbmMgaikgbmlsIG5pbCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDApKQogICAgICAgICAgICAgICAgICAgICAgICAgICAocmVjdXIgKGluYyBpKSBqIG5pbCBuaWwpKQogICAgICAgICAgICAgICAgICAgICAgICBcIyAocmVjdXIgKGluYyBpKSBqIChvciBzdGFydCBpKSBuaWwpCiAgICAgICAgICAgICAgICAgICAgICAgIFw%2FIChsZXQgW3JlcyAoKyAoZiBpIGogc3RhcnQgXC4pCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZiBpIGogc3RhcnQgXCMpKV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgKHdoZW4gKG5pbD8gc3RhcnQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGFzc29jISBjYWNoZSBrZXkgcmVzKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzKSkpKSkpKV0KICAgICAgKGYgMCAwIG5pbCBuaWwpKSkpCgooZGVmbiBzb2x2ZSBbdGFza10KICAodGltZSAocmVkdWNlICsgKG1hcCB2YXJpYW50cyAocGFyc2UgdGFzaykpKSkpCgojXyhzb2x2ZSAxKSAKI18oc29sdmUgMik%3D - still have to add the cat
transducer#2023-12-1220:06borkdudeadded it here now https://github.com/squint-cljs/squint/blob/main/examples/aoc/solutions.md#2023-12-1220:08oyakushevSorry, didn't mean to add extra stuff:))#2023-12-1220:08oyakushevCouldn't help refactoring a bit#2023-12-1220:09borkdudeno worries, porting was minor#2023-12-1220:56roklenarcicyeah I made it way faster by making the function use indexes instead of sequences (which affects memoize speed).#2023-12-1221:10roklenarcicbut the code is way uglier#2023-12-1221:15roklenarcicComparison:
https://gist.github.com/RokLenarcic/d39edc908f8d59146d2436fe2ede834c#2023-12-1300:59IvanaManual memoization with local atom, 450 msec
(defn process-row [s]
(let [[s v] (str/split s #"\s+" 2)
s (->> s (repeat 5) (str/join "?"))
v (->> v (repeat 5) (str/join ","))
v (read-string (str "[" v "]"))
dp (atom {})
go (fn go [si vi]
(cond (>= vi (count v)) (if (str/index-of s \# si) 0 1)
(>= si (count s)) 0
:else (let [dp-k (+ vi (* 10000 si))]
(or (get @dp dp-k)
(let [n (get v vi)
dot-i (or (str/index-of s \. si) (count s))
r (+ (if (or (<= si dot-i (+ si n -1))
(= \# (get s (+ si n))))
0
(go (+ si n 1) (inc vi)))
(if (= \# (get s si))
0
(go (inc si) vi)))]
(swap! dp assoc dp-k r)
r)))))]
(go 0 0)))
(->> input
str/split-lines
(map process-row)
(apply +))
#2023-12-1304:25wevremMy https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_12.clj. I’m on a business trip on the east coast and, sadly, not much time to work on these.#2023-12-1320:38roklenarcicif you care about performance, why use atom and persistent map to cache things? Why not use java.util.Hashmap?#2023-12-1418:35bhaumanDay 12 beat me up a bit for not thinking more about the problem first.
https://github.com/bhauman/adv2023/blob/main/src/adv2023/day12/sol.clj#2023-12-2113:57alpoxAre there any weird edge cases? I am pretty sure that my solution works and it looks right in all cases I picked. But for some reason it tells me the result is too low - so I wonder if I missed something specific in the input.#2023-12-2114:01genmeblogFor part 2 i missed ?
as a separator of the copies.#2023-12-2114:06alpoxAh well i’m still at part 1 😄 thanks for the heads up though#2023-12-2114:10genmeblogAh sorry for spoiling a little bit...#2023-12-2114:17alpoxThis is basically a spoil-channel so no worries 😉#2023-12-2210:16alpoxUpdate: I found the issue. A typical off-by-one error#2023-12-1215:38danielnealDay 1 - 10 using a lot of instaparse … https://github.com/danielneal/advent-of-code-2023/tree/main/src
Not even going to look at Day 11, better quit now, as day 10 took me most of Sunday ha.#2023-12-1310:03thomasI considered using instaparse for day 2.... but ended up with several lines of replace
etc. instead.#2023-12-1310:06danielnealI enjoyed how it reveals the structure of the input each time - I personally think you can look at it a grammar and get a feel for what the input looks like more easily than reading combinations of regexes#2023-12-1310:08thomasyes, very true... and a couple of regex are much more error prone IMHO... just one added space or so and it can go wrong. Regexes seem to be much more tied to the exact format. but maybe that is more perception TBH.#2023-12-1309:57genmeblogDay 13 - Solutions 🪞#2023-12-1309:59genmeblogNot hard today fortunately... https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day13.clj#2023-12-1310:30borkdudeI have @U1EP3BZ3Q’s solution working https://squint-cljs.github.io/cherry/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxMykpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMpKQoKKGRlZiBkYXRhICh2ZWMgKC0%2BPiAocGFydGl0aW9uLWJ5ICMobm90PSAiIiAlKSBpbnB1dCkKICAgICAgICAgICAgICAgICAocmVtb3ZlICMoPSAiIiAoZmlyc3QgJSkpKSkpKQoKKGRlZm4gZXF1YWw%2FIFtbYSBiXV0gKD0gYSBiKSkKKGRlZm4gbWlycm9yZWQ%2FIFtwYWlyXSAoZXZlcnk%2FIGVxdWFsPyBwYWlyKSkKKGRlZm4gb3JwYWlyIFtbYSBiXV0gKG9yIGEgYikpCihkZWZuIHJldmVyc2UtYSBbW2EgYl1dIChtYXAgdmVjdG9yIChyZXZlcnNlIGEpIGIpKQoKKGRlZm4gZGlmZi1zdW0gW1thIGJdXQogICgtPj4gKG1hcCAoZm4gW2MxIGMyXSAoaWYgKD0gYzEgYzIpIDAgMSkpIGEgYikKICAgIChyZWR1Y2UgKykpKQoKKGRlZm4gbWlycm9yZWQtYnV0LW9uZT8gW3BhaXJdCiAgKGxldCBbYyAobWFwIChqdXh0IGVxdWFsPyBkaWZmLXN1bSkgcGFpcildCiAgICAoYW5kIChldmVyeT8gb3JwYWlyIGMpCiAgICAgICg9IDEgKHJlZHVjZSArIChtYXAgc2Vjb25kIGMpKSkpKSkKCihkZWZuIGlkLW9mIFtibG9jayBtPyByb3dzIGlkXQogICh3aGVuICgtPj4gYmxvY2sgKHNwbGl0LWF0IGlkKSByZXZlcnNlLWEgbT8pCiAgICAoKiByb3dzIGlkKSkpCgooZGVmbiBmaW5kLWlkIFtibG9jayBtPyByb3dzXQogICgtPj4gKGNvdW50IGJsb2NrKQogICAgKHJhbmdlIDEpCiAgICAoc29tZSAocGFydGlhbCBpZC1vZiBibG9jayBtPyByb3dzKSkpKQoKKGRlZm4gZmluZC1pZC1hbGwgW20%2FIGJsb2NrXQogIChvciAoZmluZC1pZCBibG9jayBtPyAxMDApCiAgICAoZmluZC1pZCAoYXBwbHkgbWFwIHZlY3RvciBibG9jaykgbT8gMSkpKQoKKGRlZm4gc29sdXRpb24gW2RhdGEgbT9dCiAgKC0%2BPiAobWFwIChwYXJ0aWFsIGZpbmQtaWQtYWxsIG0%2FKSBkYXRhKQogICAgKHJlZHVjZSArKSkpCgooY29tbWVudAogIDs7IHBhcnQgMQogIChzb2x1dGlvbiBkYXRhIG1pcnJvcmVkPykKICA7OyA9PiAzMTg3NwogIDs7IHBhcnQgMgogIChzb2x1dGlvbiBkYXRhIG1pcnJvcmVkLWJ1dC1vbmU%2FKQogICk%3D - now squint...#2023-12-1310:33borkdudehere's the https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxMykpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMpKQoKKGRlZiBkYXRhICh2ZWMgKC0%2BPiAocGFydGl0aW9uLWJ5ICMobm90PSAiIiAlKSBpbnB1dCkKICAgICAgICAgICAgICAgICAocmVtb3ZlICMoPSAiIiAoZmlyc3QgJSkpKSkpKQoKKGRlZm4gZXF1YWw%2FIFtbYSBiXV0KICAoPSBhIGIpKQooZGVmbiBtaXJyb3JlZD8gW3BhaXJdIChldmVyeT8gZXF1YWw%2FIHBhaXIpKQooZGVmbiBvcnBhaXIgW1thIGJdXSAob3IgYSBiKSkKKGRlZm4gcmV2ZXJzZS1hIFtbYSBiXV0gKG1hcCB2ZWN0b3IgKHJldmVyc2UgYSkgYikpCgooZGVmbiBkaWZmLXN1bSBbW2EgYl1dCiAgKC0%2BPiAobWFwIChmbiBbYzEgYzJdIChpZiAoPSBjMSBjMikgMCAxKSkgYSBiKQogICAgKHJlZHVjZSArKSkpCgooZGVmbiBtaXJyb3JlZC1idXQtb25lPyBbcGFpcl0KICAobGV0IFtjIChtYXAgKGp1eHQgZXF1YWw%2FIGRpZmYtc3VtKSBwYWlyKV0KICAgIChhbmQgKGV2ZXJ5PyBvcnBhaXIgYykKICAgICAgKD0gMSAocmVkdWNlICsgKG1hcCBzZWNvbmQgYykpKSkpKQoKKGRlZm4gaWQtb2YgW2Jsb2NrIG0%2FIHJvd3MgaWRdCiAgKHdoZW4gKC0%2BPiBibG9jayAoc3BsaXQtYXQgaWQpIHJldmVyc2UtYSBtPykKICAgICgqIHJvd3MgaWQpKSkKCihkZWZuIGZpbmQtaWQgW2Jsb2NrIG0%2FIHJvd3NdCiAgKC0%2BPiAoY291bnQgYmxvY2spCiAgICAocmFuZ2UgMSkKICAgIChzb21lIChwYXJ0aWFsIGlkLW9mIGJsb2NrIG0%2FIHJvd3MpKSkpCgooZGVmbiBmaW5kLWlkLWFsbCBbbT8gYmxvY2tdCiAgKG9yIChmaW5kLWlkIGJsb2NrIG0%2FIDEwMCkKICAgIChmaW5kLWlkIChhcHBseSBtYXAgKGNvbXAgc3RyL2pvaW4gdmVjdG9yKSBibG9jaykgbT8gMSkpKQoKKGRlZm4gc29sdXRpb24gW2RhdGEgbT9dCiAgKC0%2BPiAobWFwIChwYXJ0aWFsIGZpbmQtaWQtYWxsIG0%2FKSBkYXRhKQogICAgKHJlZHVjZSArKSkpCgooY29tbWVudAogIDs7IHBhcnQgMQogIChzb2x1dGlvbiBkYXRhIG1pcnJvcmVkPykKICA7OyA9PiAzMTg3NwogIDs7IHBhcnQgMgogIChzb2x1dGlvbiBkYXRhIG1pcnJvcmVkLWJ1dC1vbmU%2FKQogICk%3D - I needed to add a str/join
in there since you can't straightly compare arrays with characters in JS :)#2023-12-1310:33borkdude(defn find-id-all [m? block]
(or (find-id block m? 100)
(find-id (apply map (comp str/join vector) block) m? 1)))
#2023-12-1310:38genmeblogThanks!#2023-12-1310:40genmeblogBtw, windows key + enter doesn't work for me on Edge.#2023-12-1310:40borkdudecan you try:
localStorage.setItem("editor.modifier", "Ctrl")
in the console and then refresh?#2023-12-1310:40borkdudeI should probably switch to Ctrl for the modifier key since Windows/Cmd gives problems on other OSes than mac#2023-12-1310:44genmeblogStill the same...#2023-12-1310:46borkdudeAlso after refresh? Damn, I should check at home in Windows #2023-12-1310:48genmeblogyes, after refresh, prv#2023-12-1310:51genmeblogwait! works on squint but not on cherry#2023-12-1310:52borkdudeAh yes makes sense #2023-12-1310:52borkdudeI haven’t made this tweak in cherry but I’ll just change the default key on non-Mac#2023-12-1313:01erdoshttps://github.com/erdos/advent-of-code/blob/master/2023/day13.clj
I could not yet figure out how to do without loop-recur.#2023-12-1314:26AleksMy solution for today, I’m not happy with it https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_13.clj#2023-12-1317:15Aleks@U2E1D7WUB impressed by your solution, so neat and nice!#2023-12-1319:02Piotr KaznowskiSame code for both parts: https://github.com/caseneuve/aoc2023/blob/master/day13/solution.clj#2023-12-1320:54rjrayI'm stuck on part 2... my answer keeps coming up low.#2023-12-1321:01rjrayI'm def overthinking it... looking at other solutions, I'm using 3x (or more) code.#2023-12-1322:26IvanaMy solution, after some fixes, finally i may share without my shame
(defn errs [a b] (apply + (map #(if (= %1 %2) 0 1) a b)))
(defn refl [c es]
(->> (range 1 (count c))
(keep (fn [i] (let [[a b] (split-at i c)]
(when (= es (apply + (map errs (reverse a) b))) i))))
first))
(defn transpose [m] (apply mapv vector m))
(defn task [s es]
(let [m (str/split-lines s)]
(or (some-> (refl m es) (* 100)) (refl (transpose m) es))))
(->> (str/split input #"\n\n")
(map #(-> [(task % 0) (task % 1)]))
(reduce (partial mapv +) [0 0]))
#2023-12-1402:07wevremMy https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_13_mirrors.clj. It’s rather bulky. I read the part 1 quickly before going off to a day of meetings and while thinking about it during the day I made a guess what part 2 would be. I was completely wrong. I tried to keep all the info as I went along, none of which I needed, it turned out, for part 2. Oh well. A few tweaks to my logic and both parts run with same code.
@U2E1D7WUB I like your stack trick for finding the mirror pair.#2023-12-1405:37bhaumanhttps://github.com/bhauman/adv2023/blob/main/src/adv2023/day13/sol.clj#2023-12-1405:38bhaumanMy basic trick was
(let [[a b] (split-at n rows)] (every? identity (map = (reverse a) b)))
#2023-12-2211:46Felix DornerHere’s one from a clojure noob, 100% not clever, I feel lots of attention goes to figuring out the clojure stuff instead of thinking about the actual problem 😞 https://github.com/felixdo/aoc23/blob/main/src/aoc23/day13.clj#2023-12-1310:06genmeblogQuestions to all:
• Maybe we should remove an url to the github from the channel topic? It's been dead for 3 years now
• What do you think about new leaderboard just for this year (and maybe new every year)? Current one is almost full with more than half people are inactive.#2023-12-1314:10wevremWhat does “almost full” mean? Is there a limit to the number of members in a channel?#2023-12-1314:13elkenPrivate leaderboards are limited to 200 yeah#2023-12-1314:14elken(don't care about the ID I just made/wiped it)#2023-12-1314:18pezDid you irrevocably obliterate it?#2023-12-1314:26elkenIt is forever lost to the annals of time#2023-12-1317:15IvanaDay 13 - can't understand the task description clearly
I want to solve all the AOC by myself without reading suggestions, but can't clearly understand the task & examples. What means "perfect reflection" - should we check palindrome ONLY with (inc (quot cnt 2))
center (rows or cols) and may drop only line/col #1 (all the examples from description shows this case!) or we have to find all the palindromes? What to do if patters has more than 1 reflection - first example in description has also reflection between rows 3 and 4 (two pairs of rows) - what to do in this case? What to do if pattern has no reflections at all, even with 2 rows/columns?#2023-12-1319:17genmeblogThere should be such reflection which covers one side fully. Let c_n
is a column. [c1 c2 c3 c3 c2 c1 c0]
has a reflection, Full left side is reflected on the right side. Right side contains additional column which can be ignored in reflection.#2023-12-1319:17genmeblog[c1 c2 c3 c3 c2 c0]
has no reflection.#2023-12-1319:20genmeblogThere is no reflection in rows in the first example. Because of that (one side is not fully reflected in the other)#2023-12-1321:14IvanaOk, thanks, got it!#2023-12-1405:43bhaumanThe day 12 thread is borked for me. Anyone else?#2023-12-1407:30pezBorked how? It seems to work for me…#2023-12-1414:21bhaumanI can’t reply to the thread… tried restarting app. Maybe there is a cache thats fouling things up#2023-12-1414:56pezI could reply.#2023-12-1417:36bhaumanwell I got some debuggin to do#2023-12-1406:19rjrayDay 14 Part 2 is bonkers 😳.#2023-12-1408:12erdosSolution: https://github.com/erdos/advent-of-code/blob/master/2023/day14.clj
My approach is quite slow due to transposing the data back an forth all the time, so there is a lot to improve.
The trick with part 2 is that the spin cycle becomes periodical after a while, so we just have to find that point as well as the length of periodicity.#2023-12-1408:42AleksI remember Tetris (Day 17: Pyroclastic Flow) last year — the same trick
https://adventofcode.com/2022/day/17#2023-12-1408:52AleksYet another slow solution (~4 secs) https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_14.clj#2023-12-1410:14Arno JacobsThink of analog clocks. 😉#2023-12-1411:18genmeblog5 secs for part-2 https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day14.clj#2023-12-1411:20genmeblog@UEF091BP0 could you mark this thread as a solution thread?#2023-12-1414:32Piotr KaznowskiFor the p.2 I assumed there will be some frequency finding in the cycles, so I didn't bother with the code and found it pretty quickly with some printing and pencil. Both solutions go in ~0.8 sec together 😛
https://github.com/caseneuve/aoc2023/blob/master/day14/solution.clj#2023-12-1417:36gabor.veres~A fast one, 3-5 ms for part 2 on the real input~ (Edited: sorry, flawed measurement)
https://github.com/gveres/advent-of-code-2023-clojure/blob/main/src/day14.clj
I'm pretty proud of the "line-tilt" ;
(defn tilt-left [line]
(->> line
(partition-by #(= % \#))
(mapcat (comp reverse sort))
(apply str)))
#2023-12-1417:37bhaumanMy Day 14 (4s)
https://github.com/bhauman/adv2023/blob/main/src/adv2023/day14/sol.clj#2023-12-1417:40bhauman@U4XJNL67P very very similar!#2023-12-1417:41bhaumanexcept yours is fast#2023-12-1418:39gabor.veres@U064J0EFR, yes it is very similar, cool, except your tilt is even more elegant 👍#2023-12-1419:03Piotr KaznowskiI really like tilt
with partition-by
, but, interestingly, it makes my code run twice as long in comparison to my not so elegant loop
(cc @U064J0EFR, @U4XJNL67P) Also @U4XJNL67P, I tried your solution on my machine, but can't go under 3 sec with it.#2023-12-1419:05rjrayhttps://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day14.clj
When I first wrote part 1, I tried to anticipate what part 2 would be. I was wrong, and to add insult to injury my part 1 took 20s to run. So I slept on it, and this morning I rewrote part 1, getting it to run in about 43ms. Part 2, once I had time to think about it, is a familiar pattern (there's usually one of these every year).#2023-12-1419:29gabor.veres@UUAKPEMJ9, sounds weird, but thanks for reporting, I'll check again#2023-12-1420:08gabor.veres@UUAKPEMJ9, my mistake - I accidentally measured with a pre-warmed memoized function in the REPL. I stand corrected - mea culpa.#2023-12-1420:20Piotr KaznowskiCool, just started to worry there's something wrong with my machine!#2023-12-1503:45IvanaNice task! 830 ms for whole part 2 (150 rotation cycles in my case), after replacing immutable strings processing by mutable char-array
with aget & aset
by indexes
(let [ca (char-array input)
cols (str/index-of input \newline)
rows (quot (count input) cols)
lis (mapv (fn [r] (mapv #(+ % (* (inc cols) r)) (range cols))) (range rows))
ris (mapv (comp vec reverse) lis)
tis (mapv (fn [c] (mapv #(+ (* % (inc cols)) c) (range rows))) (range cols))
bis (mapv (comp vec reverse) tis)
swaps (fn [i j] (let [t (aget ca i)] (aset ca i (aget ca j)) (aset ca j t)))
process-line (fn [xs] (reduce (fn [iis i]
(let [c (aget ca i)]
(case c
\O (if (empty? iis)
iis
(do (swaps (first iis) i)
(conj (subvec iis 1) i)))
\# []
(conj iis i))))
[] xs))
move (fn [dir] (doseq [d dir] (process-line d)))
rotate (fn [] (move tis) (move lis) (move bis) (move ris))]
(doseq [_ (range 150)] (rotate))
(north-support (String. ca)))
#2023-12-1504:37wevremMy https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_14_v2.clj. I loaded the \O
and \#
into a locmap (keyed by [r c]
) and then for the cycles I did a rotation transformation on the keys of the locmap. I had a few spare moments in between meetings and rewrote my split-grouped-lines
and locmap<-
utility functions https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/common2.clj. I’m quite pleased with those.#2023-12-1509:59BastianTo practice I wrote a stateful transducer to tilt one line. cut my time in half for part 2, but did not optimize the rest, so still 10sec total...
(def tilt-transducer
"transforms a line into sequences of the form OOO....# by remembering round rocks and dots until # is read (or end of line)"
(fn [rf]
(let [dots (volatile! 0)
rounds (volatile! 0)]
(fn ([] (rf))
([result] (let [tmp (concat (repeat @rounds \O) (repeat @dots \.))
result (if (empty? tmp)
result
(unreduced (rf result tmp)))]
(vreset! dots 0)
(vreset! rounds 0)
(rf result)))
([result input]
(condp = input
\. (do (vswap! dots inc) result)
\O (do (vswap! rounds inc) result)
\# (let [out (concat (repeat @rounds \O) (repeat @dots \.) '(\#))]
(vreset! dots 0)
(vreset! rounds 0)
(rf result out))
result))))))
(transduce tilt-transducer concat '(\# \. \O \O \. \O \# \. \O))
;=> (\# \O \O \O \. \. \# \O \.)
#2023-12-1610:28Arnaud GeiserStill catching up over the week-end : https://github.com/arnaudgeiser/advent-of-code/blob/master/2023/clojure/src/advent_of_code/day14.clj#2023-12-2812:39alpox~1.8s without trying to optimize. Not the best.#2023-12-3023:09AleksUpdated my solution with some optimizations. It is still Clojure without fancy things and mutations, now it takes 730 msecs.
https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_14.clj
For tilt
came up with this code
(defn tilt-part [^String part dir]
(if (str/blank? part)
part
(let [rocks (.repeat "O" (aoc/cnt part \O))
space (.repeat "." (aoc/cnt part \.))]
(case dir
:left (str rocks space)
:right (str space rocks)))))
(defn tilt-row [^String row dir]
(->> (str/split row #"#" -1)
(map #(tilt-part % dir))
(str/join "#")))
(defn tilt [platform dir]
(mapv #(tilt-row % dir) platform))
TIL about string.repeat
. It’s there since JDK 11. One more interesting thing — str/split
can accept 3rd argument — limit. If the limit is negative then the pattern will be applied as many times as possible and the array can have any length#2023-12-1508:52Piotr KaznowskiDay 15 - Solutions#2023-12-1508:53Piotr Kaznowskiarray-map
ftw https://github.com/caseneuve/aoc2023/blob/master/day15/solution.clj#2023-12-1509:08gabor.veresVery nice and concise, @UUAKPEMJ9! Mine is https://github.com/gveres/advent-of-code-2023-clojure/blob/main/src/day15.clj#2023-12-1510:15borkdude@UUAKPEMJ9 I tried to port your solution to #C03U8L2NXNC and #C03QZH5PG6M but the number I get for my input for part 1 is too low, I'll double check in .clj now#2023-12-1510:20genmeblogNothing elegant linear search on vector + rewriting was enough https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day15.clj#2023-12-1510:21borkdudeah it works in .clj, maybe a JS vs JVM difference, I'll keep digging#2023-12-1510:24borkdudeah yes, it's a platform difference, with planck (self-hosted CLJS) I get the same answers as cherry/squint#2023-12-1510:31borkdudelol, with @U1EP3BZ3Q’s solution I have the same problem for part 1 in CLJS#2023-12-1510:33borkdudehttps://squint-cljs.github.io/cherry/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KOzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxNSkpCiAgICAgICAgICAgICBzdHIvdHJpbSkpCgooZGVmbiBwYXJzZSBbZGF0YV0gKHN0ci9zcGxpdCBkYXRhICMiLCIpKQoKKGRlZiBkYXRhIChwYXJzZSBpbnB1dCkpCgooZGVmbiBIQVNIIFt0b2tlbl0gKHJlZHVjZSAoZm4gW3YgY10gKGJpdC1hbmQgMHhmZiAoKiAxNyAoKyB2IChpbnQgYykpKSkpIDAgdG9rZW4pKQoKKGRlZiBwYXJ0LTEgKHJlZHVjZSArIChtYXAgSEFTSCBkYXRhKSkpCgpwYXJ0LTE%3D#2023-12-1510:40borkdudeaaah this gives (0 0 0 0)
in CLJS:
(map int "shn-")
#2023-12-1510:41borkdudecharCodeAt to the rescue#2023-12-1510:44borkdudehttps://squint-cljs.github.io/cherry/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KOzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBSZW1lbWJlciB0byB1cGRhdGUgdGhlIHllYXIgYW5kIGRheSBpbiB0aGUgZmV0Y2gtaW5wdXQgY2FsbC4KKGRlZiBpbnB1dCAoLT4%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxNSkpCiAgICAgICAgICAgICBzdHIvdHJpbSkpCgooZGVmbiBwYXJzZSBbZGF0YV0gKHN0ci9zcGxpdCBkYXRhICMiLCIpKQoKKGRlZm4gaGFzaCogW2N4XQogIChyZWR1Y2UKICAgIChmbiBbYWNjIGNoXQogICAgICAocmVtICgqIDE3ICgrIGFjYyAoIz8oOmNsaiBpbnQKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDpjbGpzIC5jaGFyQ29kZUF0KSBjaAogICAgICAgICAgICAgICAgICAgICAgICAgIz8oOmNsanMgMCkpKSkgMjU2KSkgMCBjeCkpCgooZGVmbiBsZW5zZXMgW2lucHV0XQogIChyZWR1Y2UKICAgIChmbiBbYWNjIFtsYWIgZm9jXV0KICAgICAgKHVwZGF0ZSBhY2MgKGhhc2gqIGxhYikgKGlmIGZvYyAjKGFzc29jICUgbGFiIGZvYykgIyhkaXNzb2MgJSBsYWIpKSkpCiAgICAoemlwbWFwIChyYW5nZSAyNTYpIChyZXBlYXQgKGFycmF5LW1hcCkpKQogICAgKG1hcHYgIyhyZS1zZXEgIyJcdysiICUpIGlucHV0KSkpCgooZGVmbiBmb2N1c2luZy1wb3dlcnMgW2xlbnNlc10KICAodmVjIChrZWVwCiAgICAgICAgIChmbiBbW2JveCBzbG90c11dCiAgICAgICAgICAgKHdoZW4tbGV0IFt2cyAodmFscyBzbG90cyldCiAgICAgICAgICAgICAoYXBwbHkgKyAobWFwLWluZGV4ZWQgKGZuIFtpIHZdICgqIChpbmMgYm94KSAoaW5jIGkpIChwYXJzZS1sb25nIHYpKSkgdnMpKSkpCiAgICAgICAgIGxlbnNlcykpKQoKKGNvbW1lbnQKICAobGV0IFtpbnB1dCAoLT4%2BIGlucHV0IChyZS1zZXEgIyJbXixdKyIpIHZlYyldCiAgICB7OnBhcnQxIChhcHBseSArIChtYXAgaGFzaCogaW5wdXQpKQogICAgIDpwYXJ0MiAoYXBwbHkgKyAoZm9jdXNpbmctcG93ZXJzICh2ZWMgKGxlbnNlcyBpbnB1dCkpKSl9KSk%3D#2023-12-1511:00genmeblog@UUAKPEMJ9 you're lucky here:
(class (reduce #(assoc %1 %2 %2) (array-map) (range 8)))
;; => clojure.lang.PersistentArrayMap
(class (reduce #(assoc %1 %2 %2) (array-map) (range 9)))
;; => clojure.lang.PersistentHashMap
#2023-12-1511:24Piotr Kaznowski@U1EP3BZ3Q Looks like a novice's luck! Was looking for exactly this kind of data structure and found it, but didn't read through all the caveats. Max key count of particular array-map
in my input is 6, so luck it is! But then -- what is the point of such behavior??#2023-12-1511:25borkdude@UUAKPEMJ9 array-map is an optimization for small maps#2023-12-1511:27borkdudewhen the map grows, it converts automatically to a hash-map, all for performance trade-offs#2023-12-1511:30genmeblogSearch in array-map is linear, assoc/update/dissoc rewrites whole storage which is ok for maps with less than 9 elements.#2023-12-1511:32genmeblogThe storage is simple Object array which keeps key1,val1,key2,val2,... keyn,valn that's why the order is preserved.#2023-12-1511:35Piotr KaznowskiThanks, @U04V15CAJ, @U1EP3BZ3Q. What do you think about replacing it with ordered-map
from flatland.ordered.map
?#2023-12-1511:35borkdudeyou could do that, it's in babashka as well :) but maybe a nice challenge to solve it without it#2023-12-1511:36Piotr KaznowskiSure!#2023-12-1511:36borkdudein squint, which is based on JS objects, it's easy since they preserve insertion order#2023-12-1511:37borkdudemaybe you could also use the mutable LinkedHashMap in Java#2023-12-1511:39borkdude(defn lenses [input]
(reduce
(fn [acc [lab foc]]
(update acc (hash* lab) (if foc #(doto % (.put lab foc)) #(doto % (.remove % lab)))))
(zipmap (range 256) (repeat (new java.util.LinkedHashMap)))
(mapv #(re-seq #"\w+" %) input)))
seems to work#2023-12-1511:40borkdudeonly for the first part, the second part doesn't work because of the mutability probably#2023-12-1512:11Piotr KaznowskiJust for fun quickly sketched alternative assoc*
and dissoc*
to keep my original solution (mostly) intact (would need only to change the condition in focusing-powers
, and, obviously, exchange maps to vectors):
(defn assoc* [mx a b]
(let [i (.indexOf (mapv first mx) a)]
(if (< i 0) (conj mx [a b]) (assoc mx i [a b]))))
(defn dissoc* [mx a]
(let [i (.indexOf (mapv first mx) a)]
(if (< i 0) mx (into [] cat [(take i mx) (drop (inc i) mx)]))))
It's ~4 ms less performant than array|ordered-map
and it's +6 locs, but can live with it 😄#2023-12-1512:13genmeblogInstead of take/drop you can use subvec which should be more performant.#2023-12-1512:18Piotr KaznowskiNot seeing any difference on my machine (but still, the whole solution runs in ~20 ms).#2023-12-1513:51bhaumanToday I made liberal use of :pre
and :post
conditions. It seemed to go much smoother. Testing and typing helps sometimes who knew????
https://github.com/bhauman/adv2023/blob/main/src/adv2023/day15/sol.clj#2023-12-1515:08IvanaWhith the help of custom bare bones ordered map
(defn h [s] (reduce (fn [r c] (-> c int (+ r) (* 17) (rem 256))) 0 s))
(->> (str/split input #"\,")
(reduce (fn [acc s]
(let [[l v] (str/split s #"[\=\-]")
b (h l)
acc (vary-meta acc update :i (fnil inc 0))]
(if v
(update-in acc [b l] (fn [[k _]] [(or k (-> acc meta :i)) (read-string v)]))
(update acc b dissoc l))))
{})
(reduce (fn [acc [b m]]
(->> m
(sort-by (comp first second))
(map-indexed (fn [i [_ [_ v]]] (* (inc b) (inc i) v)))
(apply + acc)))
0))
#2023-12-1517:20rjrayhttps://github.com/rjray/advent-2023-clojure/blob/master/src/advent_of_code/day15.clj
Man, I needed a day this easy...#2023-12-1518:03Alekshttps://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_15.clj#2023-12-1519:25borkdude@U064J0EFR thank! the pre/post was indeed very useful also in squint, with that I detected that one thing came in as a string instead of a number which was caused by storing stuff in a JS object, changing that to a js/Map
fixed it!
https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa6e9992b079e20e21d753e8c75a7353c5908b225%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4Cgo7OyBvcmlnaW5hbCBzb2x1dGlvbiBieSBAYmhhdW1hbjoKOzsgaHR0cHM6Ly9naXRodWIuY29tL2JoYXVtYW4vYWR2MjAyMy9ibG9iL21haW4vc3JjL2FkdjIwMjMvZGF5MTUvc29sLmNsagoKOzsgUmVtZW1iZXIgdG8gdXBkYXRlIHRoZSB5ZWFyIGFuZCBkYXkgaW4gdGhlIGZldGNoLWlucHV0IGNhbGwuCihkZWYgaW5wdXQgKC0%2BIChqcy1hd2FpdCAoZmV0Y2gtaW5wdXQgMjAyMyAxNSkpCiAgICAgICAgICAgICBzdHIvc3BsaXQtbGluZXMKICAgICAgICAgICAgIGZpcnN0CiAgICAgICAgICAgICAoc3RyL3NwbGl0ICMiXCwiKSkpCgo7OyBzcXVpbnQgdjAuNC44MiBkb2Vzbid0IGhhdmUgcmVtLCBuZXh0IHZlcnNpb24gd2lsbAooZGVmbiByZW0gW24gZF0KICAobGV0IFtxIChxdW90IG4gZCldCiAgICAoLSBuICgqIGQgcSkpKSkKCihkZWZuIGxlbnMtaGFzaCBbY2hzXQogICgtPj4gKG1hcCAjKC5jaGFyQ29kZUF0ICUgMCkgY2hzKQogICAgKHJlZHVjZQogICAgICAjKHJlbSAoKiAoKyAlMSAlMikgMTcpIDI1NikKICAgICAgMCkpKQoKOzsgcGFydCAxCiNfKC0%2BPiAobWFwIGxlbnMtaGFzaCBpbnB1dCkgKHJlZHVjZSArKSkKCihkZWZuIHBhcnNlLWluc3QgW3NdCiAgKGlmICguZW5kc1dpdGggcyAiLSIpCiAgICBbKHN1YnMgcyAwIChkZWMgKGNvdW50IHMpKSldCiAgICAodXBkYXRlIChzdHIvc3BsaXQgcyAjIlw9IikgMSBwYXJzZS1sb25nKSkpCgooZGVmbiB2ZWMtYXNzb2MgW2wgayB2XQogIHs6cHJlIFsodmVjdG9yPyBsKV0KICAgOnBvc3QgWyh2ZWN0b3I%2FICUpXX0KICAoaWYgKHNvbWUgI3trfSAobWFwIGZpcnN0IGwpKQogICAgKG1hcHYgIyhpZiAoPSBrIChmaXJzdCAlKSkgW2sgdl0gJSkgbCkKICAgIChjb25qIGwgW2sgdl0pKSkKCihkZWZuIHZlYy1kaXNzb2MgW2wga10KICB7OnByZSBbKHZlY3Rvcj8gbCldCiAgIDpwb3N0IFsodmVjdG9yPyAlKV19CiAgKHZlYyAocmVtb3ZlICMoPSBrIChmaXJzdCAlKSkgbCkpKQoKKGRlZm4gbWFwLWluc3QgW20gW2sgdl1dCiAgezpwcmUgWyhzdHJpbmc%2FIGspIChtYXA%2FIG0pXQogICA6cG9zdCBbKG1hcD8gJSldfQogICh1cGRhdGUgbSAobGVucy1oYXNoIGspCiAgICAoaWYgKG5pbD8gdikKICAgICAgICAgICAgIygoZm5pbCB2ZWMtZGlzc29jIFtdKSAlIGspCiAgICAgICAgICAgICMoKGZuaWwgdmVjLWFzc29jIFtdKSAlIGsgdikpKSkKCihkZWZuIHNjb3JlLXNsb3QgW2JveCBzbG90IFtrIGxlbl1dCiAgezpwcmUgWyhldmVyeT8gbnVtYmVyPyBbYm94IHNsb3QgbGVuXSldCiAgIDpwb3N0IFsobnVtYmVyPyAlKV19CiAgKCogKGluYyBib3gpIChpbmMgc2xvdCkgbGVuKSkKCihkZWZuIHNjb3JlLWJveCBbW2JveCB2ZWMtbWFwXV0KICAoLT4%2BIHZlYy1tYXAKICAgIChtYXAtaW5kZXhlZCAocGFydGlhbCBzY29yZS1zbG90IGJveCkpCiAgICAocmVkdWNlICspKSkKCjs7IHBhcnQgMgojXygtPj4gaW5wdXQKICAgICAgIChtYXAgcGFyc2UtaW5zdCkKICAgICAgIChyZWR1Y2UgbWFwLWluc3QgKG5ldyBqcy9NYXApKQogICAgICAgKG1hcCBzY29yZS1ib3gpCiAgICAgICAocmVkdWNlICspKQ%3D%3D#2023-12-1519:55wevremMy https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_15_tokens.clj. Since I was having so much fun with them the other day, I wrote my upsert-lens
as a transducer.#2023-12-2816:29alpoxVery simple with array-map
.#2023-12-1509:12gabor.veresAnyone else feels that day 15 is magnitudes easier than any of the previous 8-9 days?
My feeling is that it's a very good fit for Clojurists, as we're indoctrinated in the "reduce using instructions from a data DSL" way of thinking(?). Anyway, I'm curious how people from other languages and disciplines will feel about it...#2023-12-1513:15Alvydas VitkauskasLast year I did AoC in Clojure. This year I do in Crystal. And when you are keen on functional style, it does not look bad at all. Check it out:
input = File.read("input/input15.txt").delete('\n').split(',')
def hash(str)
str.chars.reduce(0) { |acc, c| (acc + c.ord) * 17 % 256 }
end
ans = input.sum { |s| hash(s) }
puts "Part 1: #{ans}"
boxes = Array.new(256) { |_| Hash(String, Int32).new }
boxes = input.reduce(boxes) do |boxes, step|
label, op, focal = step.partition /[=-]/
box = hash(label)
case op
when "="
boxes[box][label] = focal.to_i
when "-"
boxes[box].delete label
end
boxes
end
ans = boxes.each_with_index.sum do |(box, i)|
box.each_with_index.sum do |((_, focal), k)|
(i + 1) * (k + 1) * focal
end
end
puts "Part 2: #{ans}"
#2023-12-1513:23oyakushevNah, it should be dead easy in any language:) Bad difficulty pacing from Eric this year.#2023-12-1513:57bhaumanIt seems that it’s like this every year. Throwing hard ones in the middle.#2023-12-1513:59bhaumanI think Clojure is an excellent lang for these problems. I.E. I don’t think the problems are good for Clojure but rather the other way around. Clojure has strengths.#2023-12-1514:49roklenarcicThis year was super easy so far, no problems where I would get stuck for hours and a lot of really easy ones. I’ve solved all years and this one might be the easiest one of them all, so far. The 2015 was also quite easy, perhaps easier than this.#2023-12-1514:52roklenarcicThat crystal solution looks really clean, what really makes it work well here is the fact that you can always fetch the index of the element in a collection during reduce and such. In clojure we have to do with map-indexed and and then you need to pack and unpack tuples everywhere#2023-12-1515:19IvanaActually you may implement reduce-indexed
with one additional line (*vary-meta* acc update :index (*fnil* inc 0))
without altering initial collection and dealing with tuples. Of course, if acc is not of primitive type. Don't forget - we are not in Haskell, Clojure meta rules! 😄
(reduce (fn [acc c]
(let [i (-> acc meta :i (or 0))]
(assoc (with-meta acc {:i (inc i)}) c i)))
{} "hello!")
=> {\h 0, \e 1, \l 3, \o 4, \! 5}
#2023-12-1518:16standYeah, I only looked at the problem this morning and my reaction was, "where's the trick?"#2023-12-1518:18IvanaThe trick may realized if naive vector-lookup implementations was not enough by performance#2023-12-1520:36oyakushevBut it actually was enough.#2023-12-1606:26wevremDay 16 - Solutions#2023-12-1606:27wevremMy https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_16_mirrors.clj. It’s not optimized. Part 2 takes almost 8 seconds to run, but I’m not too bothered by that.#2023-12-1606:31erdossolution: https://github.com/erdos/advent-of-code/blob/master/2023/day16.clj
it is just a flood fill. I was playing with multimethods to dispatch on the cell type but the embedded case
expressions were shorter at the end.#2023-12-1607:58Andrew ByalaI haven't been posting my solutions this year, but they're all in my https://github.com/abyala/advent-2023-clojure. https://github.com/abyala/advent-2023-clojure/blob/main/src/advent_2023_clojure/day16.clj, as well as my https://github.com/abyala/advent-2023-clojure/blob/main/docs/day16.md (for non-Clojurians).#2023-12-1612:27Aleks@UTFAPNRPT Hehe, my part 2 takes ~2 minutes even with pmap
. I know how it could be optimized, but too lazy to do that. Maybe later ^_^#2023-12-1711:31gabor.veresMy take https://github.com/gveres/advent-of-code-2023-clojure/blob/main/src/day16.clj
Very simulation-ish as opposed to "think about a good algorithm", has a lot of conds... would like to clean it up, but gets the job done.
3.4 seconds on an M1 Pro Mac.#2023-12-1718:43AleksFigured out how it could be optimized. We can detect a beam loop. Once it’s detected, we eliminate the beam. Finally, once the all beams eliminated we can count energized tiles ⚡. It makes my solution 10-15 times faster. So part 1 takes only 41 msecs, and part 2 takes 1353 msecs ☺️
https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_16.clj#2023-12-1718:54gabor.veresThat's kind of what I'm also doing: keep a log of all [position incoming-direction] tuples, and if one comes up again, I drop that ray from my active rays set. I actually do an infinite lazy seq, and just drop-while until I have any rays. By the time all rays are gone (either left the grid or went into a loop), we're done. BUT, mine is still half as fast, so I'll need to look again facepalm.#2023-12-1722:40genmeblogAnd mine finally, 1.5s for part-2 (with pmap
) https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day16.clj#2023-12-2820:40alpoxFirst try: 1.6 seconds on my M1 - I did not attempt to optimize but something could probably be done with transient collections or similar.
I went with a breath-first-traversal using a queue in a loop
.#2023-12-2820:42alpox#2023-12-1614:55AleksDay 16 — Question
Guys, what do you think is there a way to find the best point to start the beam by analyzing a layout? or just bruteforce for rescue? Haven’t seen other’s solutions yet.#2023-12-1718:44Alekshttps://clojurians.slack.com/archives/C0GLTDB2T/p1702838638128659?thread_ts=1702707966.227309&cid=C0GLTDB2T#2023-12-1718:59cdpjenkinsNice, I need to study your solution when I have time.
I confess I did try something like this but my idea was quite unsophisticated and I just tried to memoise everything (which blew up my JVM heap because there are too many states).#2023-12-1707:10roklenarcicDay 17 - Solutions#2023-12-1707:10roklenarcicWas another quite easy day.#2023-12-1707:10roklenarcichttps://gist.github.com/RokLenarcic/5edaaa4a667217a8bf6f298163f48337#2023-12-1711:40AleksMy part 1 runs ~2.5 secs, and part 2 runs ~7.5 secs
https://github.com/zelark/AoC/blob/master/src/zelark/aoc_2023/day_17.clj