#adventofcode

generated UTC: 2023-11-22 19:43
latest data: https://clojurians-log.clojureverse.org/adventofcode/2023-11-05
messages: 13630
pro tips:
* Double click on text to filter by it. (doubleclick + cmd-f for extra points).
* Click on date to keep day visible regardless of filter.
* Click on time to keep hour visible regardless of filter.
#2015-12-1511:32nhathe repl is really useful for these kind of challenges#2015-12-1512:24pvinisyea#2015-12-1512:24pvinisi actually use lighttable for them, so i can use the instarepl feature#2015-12-1512:24pvinisbut i really wanna leanr how to use emacs or something more powerful that lighttable#2015-12-1512:26pvinisim using nvim usually, and i am thinking if switching to emacs evil might be a good move in general, so im in the process of this decision for now simple_smile#2015-12-1513:37nhaI was using vim before, but switched to emacs because of clojure#2015-12-1513:37nha(I was not a very advanced user in vim though)#2015-12-1513:37nhabut now I use emacs for everything#2015-12-1513:37nhaI actually did miss that there was a second part !#2015-12-1513:38nhajust did it ^^#2015-12-1515:15pvinisnice#2015-12-1515:15pvinisso emacs in evil or normal emacs?#2015-12-1515:15pvinisor should i say.. “normal”?#2015-12-1515:31nha"normal"#2015-12-1515:31nha^^#2015-12-1515:31nha(using a modified prelude now)#2015-12-1515:31nhabut I may give spacemacs a try#2015-12-1515:37pvinishm, didnt know about prelude. maybe i can try it sometime#2015-12-1515:38pvinisspacemacs was kinda cool, but i think it was too many new things..#2015-12-1515:38wamarallate to the party, I'm not following daily, still stuck on the 6th day... but here's my 5 solutions so far if you're interested (spoiler alert) https://github.com/wamaral/advent-of-code#2015-12-1515:39pvinisyea, i will upload mine too, sometime in the week#2015-12-1515:39wamaral(I switched from vim to spacemacs when I started learning clojure)#2015-12-1515:39wamaralbeen using vim for 4-5 years#2015-12-1515:40wamaralso far spacemacs is doing its job, though I do miss some things once in a while#2015-12-1515:40wamaralmagit is wonderful, though#2015-12-1515:41pvinisyea ive heard about magit.. wanna try it#2015-12-1515:41pvinisbtw, your day one, is interesting#2015-12-1515:41pvinispart 2 of day 1 took me like one hour to find, and its muuuuch more compicated#2015-12-1515:41pvinisi like yours#2015-12-1515:47wamaralthanks simple_smile#2015-12-1515:48wamaralI'm still a beginner though, so that's probably non-idiomatic code#2015-12-1515:53nhaI dont have a clean repo since i jsut do it quickly in the repl, but would you be interested in quick gists ? (maybe I should just make arepo though)#2015-12-1516:56pvinissure simple_smile#2015-12-1516:57nhaok I will in an hour or two from home simple_smile#2015-12-1516:57nha(I'll try to make a few more also to make it more interesting)#2015-12-1522:31wamaralfinally solved 6.1 !#2015-12-1522:31wamaralgotta try 6.2 later tonight#2015-12-1603:16wamaralalright, 6.2 solved with only some small changes from 6.1 simple_smile#2015-12-1608:28nhaMade a few gists for the first ones (just the REPL sessions so it may not looks as clean as a real repo):




#2015-12-1701:53mchampineAnother way to do 1.1: (reduce + (map {\( 1, \) -1} "(()()((()()")) ;; 3#2015-12-1710:22pvinisnice. yea i think 1.1 was kind of understandable. 1.2 was more intense#2015-12-1722:14borkdudedecided to write day 7 in a spreadsheet simple_smile https://www.reddit.com/r/adventofcode/comments/3x9nke/day_7_spreadsheet_solution/#2015-12-1815:52wamaral@borkdude: that's crazy#2015-12-1815:56wamaralI remember watching the SICP lectures, there was a video about this exact problem used to explain objects, I'll dig that out and try to solve that way in clojure simple_smile#2016-12-0107:27fellshardDay 1-B - I actually considered testing for line segment intersection. That was going to go down a very dark path and not even make it easy to catch weird edge cases (colinear lines, e.g.)#2016-12-0215:59abarylko@fellshard Same here... I did that for a bit...#2016-12-0216:57fellshardThat's what I love about these puzzles; the part A with hidden part B tests how you decide to reuse, refactor, and remodel your solution when confronted with change. It really is superb practice.#2016-12-0219:21mnesporIt really is. I had created a function that returns all the intermediate points in a line segment, but in retrospect I wish I'd done something like R8 L4 => R 1 1 1 1 1 1 1 1 L 1 1 1 1 instead#2016-12-0219:36fellshardBasically what I ended up doing, translated relative rotations and steps into static directions, e.g. :east :east :east :north :north :west#2016-12-0219:37fellshardfrom there it's trivial to generate a sequence of points visited#2016-12-0306:26abarylkoDay3 done!#2016-12-0306:58fellshardMade it on the leaderboard for the gold star!! (even if it is near the bottom)#2016-12-0306:58fellshardThis one was perfect for Clojure, too; part B was accomplished with just two additional lines.#2016-12-0307:01fellshardWell, and one function. I find myself writing transpose a lot...#2016-12-0307:02fellshard(defn transpose [s] (vec (apply map vector s)))#2016-12-0317:21abarylkogood job @fellshard !#2016-12-0506:15fellshardHaving a devil of a time with today's. I think it comes down to not being familiar / being able to find documentation on how to use arrays / byte arrays in Clojure.#2016-12-0507:20spfeifferhttp://clojure.org/reference/java_interop#2016-12-0507:21spfeifferScroll down to „Arrays“. Keep in mind they are mutable. That bite me in on of last years challenges.#2016-12-0507:29fellshardIn the end, it was mostly the array operations that were aggravating.#2016-12-0507:30fellshardEr, byte operations, that is#2016-12-0507:30fellshardThis problem works at the byte level, not the nibble level. So gotta do a little tinkering to get it working efficiently enough to search such a wide space.#2016-12-0507:55abarylkoJust finished day 5#2016-12-0507:55abarylkoThough didn't use byte arrays....#2016-12-0507:58fellshardHave the resulting code posted anywhere for comparison?#2016-12-0507:58fellshardI've been pushing the raw 'just get an answer' code, then going back and refactoring to see what could be done better, etc.#2016-12-0507:59fellshardGiven how painful it is to calculate these hashes, good time to learn this: is there a 'best method' to cache the resolved portions of an infinite sequence?#2016-12-0508:14abarylkogood idea on the cache .....#2016-12-0508:15abarylkomy code is here https://github.com/amirci/aoc_clj#2016-12-0508:16abarylkoany reviews and comments are welcome#2016-12-0508:24fellshardAhh, there's a digest lib?#2016-12-0508:26fellshardOkay, the source I found for MD5 digest did the same thing as the library. Internally, it's using the same thing#2016-12-0508:26abarylkocool#2016-12-0508:27fellshardI found that by short-circuiting that library's use of byte hash -> BigInteger -> string every time, there was at least a bit of time savings. Might have to profile and measure it later, but I was reaching for straws trying to get a feedback loop going even with the sample data.#2016-12-0508:27fellshardBut may have been more pain than it's worth. 🙂 I mostly used it to filter the initial results so I only generated string reps when I knew those first five nybbles were 0'd out.#2016-12-0509:28fellshardIn the end, it was by far not the MD5 that was the time constraint, it was me being really really bad about mixing eager and lazy 🙂#2016-12-0509:29fellshardIt does take some time to find all the matches - a couple minutes for my second round, since it has to find over 20 valid hashes until it found its position 3 entry, but that's just compounding the problem#2016-12-0510:02fellshardLots of learning tonight 😄#2016-12-0510:02fellshardhttps://github.com/armstnp/advent-of-code-2016/blob/variants/day-5-swiss/src/advent_of_code_2016/day5.clj#2016-12-0510:03fellshardIn the end, I did a refactor 'for the fun of it'. Using the swiss arrows library allowed me to A. reuse the initial part of the calculation, and B. run part A and part B pipelines in parallel#2016-12-0510:04fellshardThe parallel furcula is magic#2016-12-0517:11abarylko@fellshard pretty cool!#2016-12-0517:23fellshardGlad I finally found an excuse to try that lib 😛#2016-12-0517:59andrew.sinclairHello, @abarylko told me this is the best place to improve my Clojure! I'm looking forward to solve some AoC with some fellow Clojurians. I have lots to learn 😉#2016-12-0518:20fellshard4clojure may be a bit better for basic learning, but last year's AoC challenges are probably great, too 🙂#2016-12-0518:20fellshardThis year's AoC challenges are starting a bit higher level if I recall last year's problems correctly.#2016-12-0518:31andrew.sinclairYep, I did last years AoC with Clojure. 4clojure was where I cut my teeth.#2016-12-0518:32andrew.sinclairI'd consider myself competent, but I want to go from "hobby language" to "professional understanding" in Clojure.#2016-12-0518:39fellshard😄#2016-12-0518:39fellshardThen this is a fantastic place for it. All the problems have two parts, and usually the second part requires you to change your model or refactor your first solution in some way. Very cleverly written.#2016-12-0518:40fellshardAnd if you aim for the leaderboards, it's an extra bit of challenge 😄#2016-12-0519:37spfeifferI am still stuck around problem 20 of last years AoC because i am a hobbyist and i am lacking free time. I expect to finish this years AoC around 2021 ☺️#2016-12-0519:38spfeifferThese are the most fun programming exercises i stumbled upon ever…#2016-12-0519:38spfeifferHearing this years challenges are much harder frightens me ☺️#2016-12-0519:39mnesporI hope he doesn't throw anything harder than last year's problem 19 at us#2016-12-0521:11fellshard😄#2016-12-0521:11fellshardI'm at 14 from last year, 'cuz of free time too...#2016-12-0602:19bhaumanHey all, I've got my repo up https://github.com/bhauman/advent-of-clojure-2016 there's also a link to last years solutions as well. I'm open to discussion.#2016-12-0602:22bhauman@samueldev ^#2016-12-0605:04fellshardPFFF. And done.#2016-12-0605:04fellshardClojure was made for this ❤️#2016-12-0605:04fellshardWell, LISP#2016-12-0605:18andrew.sinclairYeah that was easiest so far...#2016-12-0605:22abarylkowhat rank did you get?#2016-12-0605:24andrew.sinclairI got 459 and 419. It is my best total for one day, but not my best for any 1 part.#2016-12-0605:24fellshard45 and 37 😄#2016-12-0605:25andrew.sinclairawesome!#2016-12-0605:25fellshardTranspose once again saves the day, so glad I have that stowed in my core for this#2016-12-0605:25andrew.sinclairahh transpose...#2016-12-0605:26andrew.sinclairI will refactor to use that... I wrote my own and called it pivot.#2016-12-0605:26andrew.sinclairSee I'm learning already!#2016-12-0605:26andrew.sinclairThank you 😉#2016-12-0605:31fellshardThat's a good name too 😄#2016-12-0605:32fellshardI'm just used to calling it transpose from matrix algebra hahah#2016-12-0606:22abarylkoIs there a transpose ?#2016-12-0607:04fellshardNot in the core lib, I just have one defined in my core file for quick importing, since these problems seem to use it frequently#2016-12-0607:04fellshard
(defn transpose
  "Transposes the given nested sequence into nested vectors, as
  in matrix transposition.  E.g., (transpose [[1 2 3] [4 5 6]])
  would return [[1 4] [2 5] [3 6]]."
  [s]
  (vec (apply map vector s)))
#2016-12-0607:05fellshardPresumes rectangular input.#2016-12-0607:17abarylkoOh I did that as well#2016-12-0615:12andrew.sinclairI found a transpose in clojure.core.matrix but then I ended up using (apply mapv vector data)#2016-12-0616:16fellshardOooh I forgot about mapv, good call...#2016-12-0700:05abarylkoI did that too#2016-12-0705:44fellshardHad a suspicion this was a trap. Should've recognized good ol' DFA theory in there 😛#2016-12-0706:06abarylkoDay 7 done!#2016-12-0707:26mnesporI ended up in a very different place: https://github.com/mnespor/advent2016/blob/master/src/advent/day7.clj#2016-12-0707:31fellshardAhh, negative lookahead#2016-12-0715:07samueldevgood work @bhauman, glad you aren't skipping this year 😛#2016-12-0715:07samueldevI'm trying my best to get todays problem without regex.#2016-12-0715:08samueldevnot a fan of todays problem in general#2016-12-0715:08bhaumanhaven't looked at it yet - no spoilers 🙂#2016-12-0715:08bhaumantrying not ot look at this channel first#2016-12-0716:18dexterDid it without regex but it feels a bit un-optimised. I can't help but feel like I could roll up some of the loop recurs into a reductions#2016-12-0716:32samueldevim in the same boat @dexter, overuse of loop recur and wanting to tidy it up#2016-12-0717:46fellshardPartition and filter do the trick in this case, but would be slower with more / longer strings, for sure.#2016-12-0717:48bhaumanjust finished up mine if folks want to take a gander#2016-12-0718:09samueldev@bhauman similar, but better, than mine 😛#2016-12-0718:09samueldevsame idea though (every? (complement contains-abba?) neg)#2016-12-0718:15samueldevso long as I'm learning things I am happy with my solutions#2016-12-0718:15samueldevtoday I learned about short-circuiting reduces via reduced#2016-12-0718:15samueldev---* the more you know!#2016-12-0718:15bhauman@samueldev oh for sure, the learning is the best part#2016-12-0718:16bhaumanI always try to go through the clojure cheatsheet afterward to see if I missed anything#2016-12-0718:16samueldevah thats a good idea, im gonna start doing that#2016-12-0718:51fellshardhttps://github.com/armstnp/advent-of-code-2016#2016-12-0718:51fellshardIf you've got a repository, post it here and I'll pin it so we can cross-pollinate ideas and problem-solving techniques 🙂#2016-12-0718:54bhaumanhttps://github.com/bhauman/advent-of-clojure-2016#2016-12-0718:54samueldevhttps://github.com/samstiles/advent-of-code-2016#2016-12-0719:16mnesporhttps://github.com/mnespor/advent2016#2016-12-0722:35bhauman@mnespor really liked the simplicity of your parsing on day7#2016-12-0722:38mnesporThanks! It's the first time I've used positive lookahead and I'm still not sure why the first character goes into capture group 2 instead of capture group 1#2016-12-0722:40bhauman@mnespor oh actually thats not what I'm talking about simple_smile#2016-12-0722:40mnesporIf there were a way to tell re-seq to look for overlapping matches explicitly (like python's findall) I might have done that instead#2016-12-0722:40mnesporha, never mind then 😄#2016-12-0722:41bhaumanI liked the initial grouping of#2016-12-0722:41bhaumanthe hyper and the super#2016-12-0722:42bhaumanso simple 🙂#2016-12-0722:43fellshardinvert-aba sounds like we should flip the frequency map of 'Dancing Queen'#2016-12-0722:44mnesporhaha#2016-12-0722:44bhaumanheh#2016-12-0806:27bhaumancrickets#2016-12-0806:32fellshardFinished, then refactored, ended up much later than I'd hoped. 😛#2016-12-0806:32fellshardBut pretty straightforward all things said#2016-12-0806:33fellshardNice rect!#2016-12-0806:37mnesporThat's an elegant parser—have you built a DSL before?#2016-12-0806:37fellshardSeeing your parse reminds me I have an unhealthy obsession with regexes 😞#2016-12-0806:39fellshardFor whatever reason I match on the entire instruction instead of just targeting the obvious bits#2016-12-0806:40fellshardmnespor, yours is perfect amount of detail, hahah. Just the matching bit in the instruction, then conveniently pulling the two ints out - no more and no less#2016-12-0806:40fellshardYou're also whipping around those core matrix functions, I need to look into that lib#2016-12-0806:41mnesporyeah, I spent an hour reading the core/matrix docs, then 15 minutes solving the problem 😕#2016-12-0806:41fellshardHeheh :<#2016-12-0806:41fellshardStill, once you know those, this ends up being super compact#2016-12-0806:42mnesporIt came in handy a lot last year, but I've forgotten everything since then#2016-12-0814:49samueldevtodays problem looks fun#2016-12-0814:49samueldevim excited to give it a go#2016-12-0817:46spfeifferI see i have to hurry up and catch up on the 2015 problems to get to the 2016 ones. Perhaps i should cancel sleeping ☺️#2016-12-0819:09bhaumanI think getting to know core.matrix could probably be helpful in the coming problems. But it doesn't seem to provide much help for last nights problem. numpy and pandas both have a huge advantage for problems like this.#2016-12-0819:15mnesporor J troll#2016-12-0819:19fellshardShould've used APL...#2016-12-0819:19bhaumanlol#2016-12-0819:46andrew.sinclairI would love to see someone's answers in J#2016-12-0820:14bhaumanthere are answers in J on the reddit thread#2016-12-0820:15bhaumanhttps://www.reddit.com/r/adventofcode/comments/5h52ro/2016_day_8_solutions/daxiz60/#2016-12-0820:25andrew.sinclairyay Thank you 😉#2016-12-0822:34samueldevdid anyone use https://github.com/mikera/core.matrix today?#2016-12-0822:35samueldevoh snap @bhauman mentioned it a few hours ago#2016-12-0822:41mnesporI did!#2016-12-0822:41samueldev@mnespor were you better off for having done so? 🙂#2016-12-0822:42mnesporNot really#2016-12-0822:42samueldevbahahaha#2016-12-0822:43mnesporpm was handy for checking my work, however#2016-12-0902:10bhaumanone thing I'm doing is really looking at medley https://github.com/weavejester/medley/blob/master/src/medley/core.cljc sure to come in handy#2016-12-0902:12samueldevI’m scratching my head as to why many of these aren’t in clojure.core#2016-12-0902:14bhaumanassoc-some is a really good one#2016-12-0902:15bhaumanhows the weather up there?#2016-12-0902:17samueldevfor real, assoc-some, deref-swap!, dissoc-in#2016-12-0902:18samueldevweather up here: cold. -10C (14F). fireplace is on and working on some cljs so can’t complain 🙂#2016-12-0902:20bhaumanits cold here today as well 0C#2016-12-0902:20bhaumanyou live in Fredericton?#2016-12-0902:20bhaumanI'm looking on the map#2016-12-0902:20samueldevI do! about 10 minutes outside of town#2016-12-0902:21bhaumanand its anglophone mostly?#2016-12-0902:21samueldevit’s an anglophone bastion in an otherwise bilingual-or-french-focused province, yep#2016-12-0902:22bhaumanIt's actually a pretty good looking town#2016-12-0902:22bhaumanI grew up in new england#2016-12-0902:22bhaumanConnecticut coast line#2016-12-0902:23samueldevit ain’t half bad 🙂 a little on the conservative side for my liking....#2016-12-0902:23samueldevotherwise great#2016-12-0902:23samueldevand new england is great#2016-12-0902:24samueldevunrelated: my colleague Angus Fletcher is doing AoC as well - https://github.com/angusiguess/advent-of-code2016 - he says you and he met in an elevator one time, not sure where haha#2016-12-0902:26bhauman@fellshard ^ pin away!#2016-12-0902:27fellshardYou, too, have the power to pin in the palm of your hand :) #2016-12-0902:27bhaumanreally! I had no idea!#2016-12-0902:30samueldevprivate leaderboards are perhaps the best addition to AoC this year#2016-12-0902:30samueldevhttps://puu.sh/sJ6CE/686782fd68.png#2016-12-0902:30samueldevcompete with your friends rather than.... fail to get in the top 100 every day 😛#2016-12-0902:31bhaumanthats sweet!!#2016-12-0902:32bhaumanso when you say its a bit conservative ...#2016-12-0902:32bhaumanyou mean social interactions? politically?#2016-12-0902:33bhaumanor in that rural provincial way?#2016-12-0902:34samueldevpolitically, in that rural provincial way. anecdote: there was a small chance that a strip club was going to open up. in order to thwart such an endeavor, the city swooped in and paid the lease on the empty building in question to eliminate the option. they are still paying that lease on that empty building to this day.#2016-12-0902:35fellshardIsn't that what zoning laws are usually for? Hah. That's a painful way to solve a problem.#2016-12-0902:35samueldev^ yeah the taxpayers agree. lol.#2016-12-0902:35samueldev:shrug_emoji:#2016-12-0902:36bhaumanwell they could at least be paying the strippers with that money...#2016-12-0902:36bhaumanit was a joke that I'm sure has been made many times up there#2016-12-0902:36samueldevit wasn’t a small sum of money either; something like $500,000 for 5 or 10 years of empty building or something#2016-12-0902:37bhaumanholy crap!#2016-12-0902:37bhaumanso all you have to do if your building isn't rented ...#2016-12-0902:37samueldevbahahaha I hadn’t considered that path#2016-12-0902:38samueldevnot a bad idea#2016-12-0902:38samueldev(this particular building is right in the heart of downtown, so I suspect that’s why they are willing to go the distance to prevent it from happening)#2016-12-0902:39bhaumanyeah but geez the could have started a tech incubator, 3d printing shop, or something#2016-12-0902:39bhaumanoffice space for start ups#2016-12-0902:39samueldevyeah im puzzled as to why it’s not… something… yet#2016-12-0902:40samueldevone could argue a strip club as a form of tech incubation#2016-12-0902:40bhaumanoh really ... the town is THAT backward#2016-12-0902:41samueldev(the building in question - former nightclub https://www.google.ca/maps/@45.9626913,-66.6454743,3a,75y,43.99h,87.09t/data=!3m6!1e1!3m4!1sjwsC3AHYW5OjL7oYI3EZKg!2e0!7i13312!8i6656?hl=en )#2016-12-0902:42bhaumanIt really is a nice looking town#2016-12-0902:42samueldevcome party!#2016-12-0902:42bhaumanlol#2016-12-0902:43samueldevthough I’ll admit that my particular employer has done nothing but irritate me for lack of willingness to adopt cljs (even though our entire backend is clojure)#2016-12-0902:43samueldevso maybe not the best employer for, you know, the author of figwheel#2016-12-0902:43fellshardEmployers are prickly things#2016-12-0902:44fellshardThere's always the 'introduction by insubordination' tactic#2016-12-0902:44fellshard"Well, too bad, because XYZ is already using it >:)"#2016-12-0902:44samueldevHaha I’ve seriously considered that approach#2016-12-0902:44fellshard(I have yet to pull this off, because consulting is very, very difficult to pull that off with)#2016-12-0902:45fellshardStructured consulting firm, not freelance#2016-12-0902:45samueldevall of the above said WRT conservativeness @bhauman : it’s also a university town where the students make up something like 25% of our population during the school year, so there’s no small amount of more modern mindsets around#2016-12-0902:45samueldevi tend to surround myself with those groups 🙂#2016-12-0902:47bhaumangotcha#2016-12-0902:49bhaumanthe rotate-vec method is still bothering me#2016-12-0902:49bhauman
(defn rotate-left [v i]
  (let [c (count v)]
    (vec (take c (drop (mod i c) (cycle v))))))
#2016-12-0902:50fellshardWhat's bugging you about it?#2016-12-0902:51fellshardI noticed one of the pinned ones was pretty compact, it just concated take and drop.#2016-12-0902:53fellshardhttps://github.com/amirci/aoc_clj/blob/master/src/aoc/2016/day8.clj#L13#2016-12-0902:53samueldev^ big fan of that#2016-12-0902:53fellshardWhat if...#2016-12-0902:55fellshard
(defn shift
  [l n]
  (let [n (- (count l) n)
        [first-part second-part] (split-at n l]]
    (vec (concat second-part first-part))))
#2016-12-0902:56fellshardI have a big soft spot for destructuring. This is what happens when you learn ML... >_>#2016-12-0902:56fellshardBut probably not worth it at that point, just yak shaving#2016-12-0903:11bhaumanwhat about transients?#2016-12-0903:14fellshardI've not used them yet. How would you apply them here?#2016-12-0903:23fellshardAhh, think I see. You'd perform mutations on the screen using transients, since the intermediates don't need to be used elsewhere.#2016-12-0904:07bhauman
(defn rotate-left [v x]
  (let [v (vec v) c (count v) offset (mod x c)]
    (loop [i 0 accum (transient [])]
      (if (= i c)
        (persistent! accum)
        (recur (inc i) (assoc! accum i (get v (mod (+ offset i) c))))))))
#2016-12-0904:07bhaumanso here is a more traditional imperative rotate#2016-12-0904:12bhaumanand ... simple benchmarking shows little difference#2016-12-0904:33fellshardWith a structure this size, yeah. Would probably make some difference with more operations / a bigger 'screen'.#2016-12-0904:52bhaumanoh shoot, transducers rock it though#2016-12-0904:52bhauman
(defn rotate-left2 [v i]
  (let [c (count v)]
    (sequence (comp (drop (mod i c)) (take c)) (cycle v))))
#2016-12-0904:52bhauman4 times as fast#2016-12-0905:40samueldevtodays problem doesn’t seem overly hard#2016-12-0905:40samueldevbut as I haven’t done yesterdays, ill have to do both later#2016-12-0906:03fellshardI'm at a total loss today, I get completely different results when I paste today's string in raw than when I suck it in through a file. (the latter totally not being recognized by regexes even though it works fine when tested by hand)#2016-12-0906:03fellshardAnd the former not giving a correct answer.#2016-12-0906:05samueldevoh snap. you mean day 9?#2016-12-0906:06samueldevif you’re having a hard time, then I feel as though I may have drastically underestimated the problem :^#2016-12-0906:08fellshardIt's not that hard, no#2016-12-0906:08fellshardFinally got it, but was being stymied by technical issues#2016-12-0906:09fellshardWill have to dig into it later 😐#2016-12-0906:24fellshardHoly moly, parinfer deals strangely with parentheses in any position#2016-12-0906:24fellshardCan't tell if it's parinfer or proto repl actually#2016-12-0907:16fellshard.... /sigh. Okay, lesson learned. Good ol' re-matches was stymied by the newline at the end of the input.#2016-12-0907:21abarylkoSame thing 😊#2016-12-0907:23fellshardTime to start using re-find instead...#2016-12-0907:28fellshardGiven how often this seems to happen in these coding challenges, maybe I should come up with a quick set of parsing methods for easy utility...#2016-12-0907:29abarylkoit's hard to say... but maybe worth it#2016-12-0907:29abarylkolike parse numbers with separator#2016-12-0907:30abarylkothough sometimes it depends how you use it...#2016-12-0907:36fellshardMore like 'lop off this pattern from the beginning, hand me the matched groups and the remainder of the string'#2016-12-0907:36fellshardVery dumb greedy parser#2016-12-0907:38abarylkoyes, one the regex libraries in haskell has exactly that#2016-12-0914:53mnesporDon't do what I did. Mine takes more than three hours to run 😕#2016-12-0916:03bhaumanwell all the test cases pass, and everything seems correct, but says I have the wrong answer#2016-12-0916:05bhaumanoooops found a bug#2016-12-0916:06bhaumanby the way I used trampoline for easy recursive parsing#2016-12-0916:07fellshardmnespor, for the last one, do you build out a string still or do you just consume the string and find the length?#2016-12-0916:07fellshardThe recursion depth doesn't require trampoline, though I did end up using mutual recursion...#2016-12-0916:07mnesporI just consume the string and find the length. Tail call optimization turned the recursion into a loop for me#2016-12-0916:08fellshardYou only have to go as deep as any grouping of repeater tags ends up nesting.
#2016-12-0916:08mnesporI consume characters until the first marker, drop the marker, and push its expansion back into the input#2016-12-0916:09bhauman
(def data (string/trim (slurp (io/resource "day9.txt"))))

(defn parse-dir [d]
  (let [[_ directive & args] (re-matches #"(\((\d+)x(\d+)\)).*" (apply str d))]
    (cons (u/to-ints args) (list (drop (count directive) d)))))

(defn parse-directive [d]
  (let [[[cnt rpt] xs]  (parse-dir d)
        part            (take cnt xs)]
    [(apply concat (repeat rpt part))
     (drop cnt xs)]))

(defn parse* [accum d]
  (cond
    (empty? d) accum
    (= (first d) \() (let [[res rst] (parse-directive d)]
                       #(parse* (vec (concat accum res)) rst)) 
    :else #(parse* (conj (vec accum) (first d)) (rest d))))

(defn parse [d]
  (trampoline parse* [] d))
#2016-12-0916:09fellshardahh#2016-12-0916:09bhaumanthat's what I have so far haven't looked at the second part yet#2016-12-0916:09fellshardIn the end you're building a string that's hundreds of thousands, if not millions of characters long#2016-12-0916:09fellshardI'm guessing you're shuffling your heap quite a bit trying to allocate new strings#2016-12-0916:11fellshardConsider this: inside of a repetition tag and the region it affects, do any of the tags have any influence on characters outside of that region?#2016-12-0916:11mnesporthinking#2016-12-0916:12fellshard(Hmm, there's actually nothing in the specification that guarantees that...)#2016-12-0916:15mnesporI think so?#2016-12-0916:15fellshardI'm pretty sure they only generate input that satisfies the above. It could be I got a lucky input, but that seems like a constraint they intended to add, given the 'not enough memory to decompress' comment.#2016-12-0916:16mnesporIn this case, the first (9x2) ends at E, but the nested (9x2) covers up to I:
(9x2)(9x2)ABCDEFGHIJ
(9x2)ABCDE(9x2)ABCDEFGHIJ
ABCDE(9x2ABCDE(9x2)ABCDEFGHIJ
ABCDE(9x2ABCDEABCDEFGHIABCDEFGHIJ
#2016-12-0916:16mnesporI don't think any of the real inputs split a marker like that, however#2016-12-0916:19mnespor(wasn't there a puzzle last year that asked you to tailor your solution to your input instead of solving the general case?)#2016-12-0916:21fellshardI don't recall, but that implicit constraint is almost necessary to make the problem work as desired here.#2016-12-0916:27mnesporThere's almost certainly a constraint that forbids inputs like (5x3)(5x3)A#2016-12-0916:29bhaumanyeah that would be insane#2016-12-0916:36fellshardI mean you could still have an algorithm that does that, and just assumes you'll return to the original string to consume when you run out of characters in the current region... but at that point you're in this really weird state, where the order of evaluation doesn't actually make sense....#2016-12-0916:40bhaumanhmmm wait a minute it looks like processing it backwards may be equivalent for problem 2#2016-12-0916:40bhaumanoh dang!!#2016-12-0916:40fellshardActually yeah, order of execution is more important#2016-12-0916:41fellshardConsider (9x2)(5x2)abcde#2016-12-0916:42fellshardDo you get (5x2)abcd(5x2)abcde, or (9x2)abcdeabcde?#2016-12-0916:42fellshard(well, ignoring the parenthesis overlap, but you get the idea of how this could play out)#2016-12-0916:44bhaumanthinksing#2016-12-0916:50mnesporWhat might that look like? It's probably not enough to seek backward to the first marker:
(5x3)(5x3)AAAB
(5x3)AAAAAAAAAAAAAAAB
AAAAAAAAAAAAAAAAAAAAAAAAAB
#2016-12-0916:50fellshardI think they tailored the input such that you don't have to worry about boundary crossing like that, too much ambiguity involved#2016-12-0916:50bhaumanI think backward may be equivalent in this case#2016-12-0916:51bhauman
(=   (parse   (concat  "(10x2)"  (parse "(5x2)abcde")))
       (parse2 "(10x2)(5x2)abcde"))
#2016-12-0916:52fellshardIt won't be. (5x3)(5x3)AAAAB would expand to (5x3)(5x3)(5x3)AAAAB if evaluated from the left, and that clearly blows up#2016-12-0916:52fellshardSo they can't hand you input like that#2016-12-0916:52fellshardExpanding from the right leaves you with AAAAA...AAB#2016-12-0916:52mnesporoh, so the real inputs could be equivalent backward#2016-12-0916:53bhaumanif there isn't boundary crossing#2016-12-0916:54bhaumanbut that is a long shot#2016-12-0916:57mnesporIs this boundary crossing? (6x3)(1x3)A#2016-12-0917:06fellshardYeah#2016-12-0917:06fellshardWait no#2016-12-0917:07fellshardIt's boundary crossing if the inner input consumes characters beyond the outer input#2016-12-0917:07fellshard(1x6)(2x2)ABCD#2016-12-0917:08mnesporOh, I get it#2016-12-0917:09fellshard(1x6) only extends through A, (2x2) extends beyond A necessarily#2016-12-0917:09mnesporThat makes working backward complicated. (6x3)(1x3)A is valid forward, but not backward#2016-12-0917:09fellshardA. I don't think they gave inputs like that#2016-12-0917:09fellshardB. The examples they give work left to right, outer to inner, and I think that's an intentional cue#2016-12-0917:10mnesporinteresting#2016-12-0917:11fellshardSo it should be equivalent to the 'expand single tag and prepend the result' method#2016-12-0917:11fellshardBut you can chop out a bunch of work assuming that the boundary is never crossed, since that leads to absurd ambiguities in the spec#2016-12-0917:16fellshardFrom the spec for part 1: > To decompress this marker, take the subsequent 10 characters and repeat them 2 times. Then, continue reading the file after the repeated data.#2016-12-0917:24bhaumanbackwards doesn't work 😞#2016-12-0917:27bhaumannow I don't why I thought it did#2016-12-0917:27bhaumanits obvious why#2016-12-0917:46bhaumannow I'm obsessed with getting it to run fast...#2016-12-0917:50fellshard😄#2016-12-0917:51fellshardMy next move would be to quit bouncing between seqs and strings and using regexes, and just manually chew through the character stream instead#2016-12-0917:51fellshardBut even as I have it now, string conversions and all, the calculation time is very short#2016-12-0917:52fellshardSo that's more a memory usage optimization than anything#2016-12-0919:59andrew.sinclairHey I was a bit late to start todays... I'm on part 2 and I'm wondering if we are agreeing or not whether the boundaries can overlap?#2016-12-0920:00andrew.sinclairIt seems you could just parse it recursively if you don't allow overlap. That would be nice...#2016-12-0920:03fellshardBased on a sample set of one - my own - I don't believe they intended for boundaries to overlap, no.#2016-12-0920:09andrew.sinclairI see, thank you.#2016-12-0921:37mnespor(spoilers) Here's some discussion on boundary crossing in day 9 inputs: https://www.reddit.com/r/adventofcode/comments/5hgd1f/day_9_part_2_everyone_assumes_it_but_its_not/dazzrm5/#2016-12-0922:55andrew.sinclairThe part I don't understand is, "The puzzle is about trying to get the user to do some kind of recursive expansion". But can you assume recursive expansion will work? I thought, "You can't"#2016-12-0923:02bhaumanso for me memoization was the key trimming all that computation, I had a crazy input#2016-12-0923:03bhaumanmy expansion was 10gigs: 10,931,789,799#2016-12-0923:03bhaumanand I had to count and not accumulate#2016-12-0923:03bhaumanthe result#2016-12-0923:04samueldev10 GIGS? holy cow#2016-12-0923:05bhaumanI think I have that right my answer was 10,931,789,799 characters#2016-12-0923:06bhaumanyep thats 10 Gigs#2016-12-0923:06bhaumanthis would have been better as a bash script#2016-12-0923:07bhaumanmy solution runs in 4 seconds#2016-12-0923:29fellshardYeah, exactly#2016-12-0923:29fellshardDon't expand - just tally#2016-12-0923:30fellshardSince no boundaries are crossed, you can safely say 'recursively count the decompression of this tag's region. Now multiply by this tag's number of repetitions.'#2016-12-0923:31fellshardThe recursion level is pretty flat for most inputs I'm guessing, so very little stack problems and you can deal with finite chunks of the input at a time.#2016-12-0923:59bhaumanwell that was a bastard, I remember this pain from from last year now...#2016-12-1000:32mnesporit goes a little faster assuming nothing crosses a boundary:
advent.day9> (time (decompress-3 input))
"Elapsed time: 58.791967 msecs"
#2016-12-1000:33fellshardJuuust a little.#2016-12-1002:57samueldevwondering if anyone can point me in the direction of how one might clear the cider repl#2016-12-1002:57samueldevfrom code#2016-12-1002:57samueldev(I’m trying to draw the new board fresh @ the top of the repl after every step in day 8)#2016-12-1003:53bhauman@samueldev c-c c-p is like c-x c-e but pretty prints it to a buffer#2016-12-1016:15thegeezmy code is here: https://github.com/thegeez/clj-advent-of-code-2016#2016-12-1019:29cjmurphyAnd my code is here: https://github.com/chrismurrph/advent-of-code#2016-12-1021:20bhaumanVery Cool!#2016-12-1118:07cjmurphyI'm not too sure how to go about first part of Day 11. Permutations?? Some kind of decision tree?? I've been looking at Clara rules engine to see if can enter in the rules and fire them and see what it comes up with. Funny thing - seems like it could be solved without code.#2016-12-1122:00abarylkoI was thinking about some kind of tree....#2016-12-1123:22samueldev@cjmurphy lots of people doing it on paperwithout issue#2016-12-1123:22samueldevone guy commented that he was frustrated that it was easier for him to solve on paper#2016-12-1123:22samueldevand the creator of AoC replied, stating;#2016-12-1123:23samueldev“if you have a hard time getting todays problem into code, you will have a bad time for the rest of the competition"#2016-12-1123:23samueldevwhich, I donno, doesn’t sound great 😕#2016-12-1402:19raspygold👋 I’m really enjoying AoC this year. I only solved about half the problems last year before I got too busy, but this year I’m hoping to solve them all. By default I'm solving them in Ruby, but I’ve started learning Clojure this year so hoping to solve them all with Clojure afterwards. Day 11 had me stumped for a good while!#2016-12-1402:23fellshardI've had to fall off the bandwagon; brother's wedding is coming up, so I've already fallen behind a couple days, and it'll only be more over the next week, hah.#2016-12-1409:35dexterSame here, I'm still on day 8, although i'm a bit stuck and I've got no idea what I've done wrong. The sample they give seems to work when I used reductions to spot check the translations around the edge cases and it all seemed to work, it happily wraps round with no issues etc. Short of actually manually doing the transformations one by one I'm a bit stuck. If anyone's feeling generous and got any tips I'd appreciate some advice on where to look https://github.com/feldoh/advent-2016/blob/day8/src/advent_2016/day8.clj#2016-12-1409:57cjmurphy@dexter: The approach I took was to just have one function that could turn a particular [x y] 'pixel' on or off. Then in terms of that operation you can do the rotations. That way the same code is used for either a row or column rotation.#2016-12-1410:48dexter@cjmurphy I've done something relatively similar but I used rotating a row as my basic operation wherein I transpose -> rot row -> transpose if it's a column. To rotate a row I used cycle to build a view over that row which I reverse then just drop the first n off. I can just start over but I'd love to know what I'm missing with the solution I've got. Given that I've clearly missed an edge case that my tests aren't catching it seems likely if I start over with a new approach I'll miss the same edge case again.#2016-12-1411:16cjmurphyTransposing then dropping off does sound tricky. I looked at your code but hard for me to see anything wrong. One thing that can help (and will help you with a later day/s), and might be better/easier than tests, is to have an actual visual representation, so like \. and '\# instead of :off :on, which won't line up nicely in a rectangle.#2016-12-1411:27dexterI've got a messy local copy where I was just trying that actually 😛#2016-12-1411:27dexterI drew it with quil#2016-12-1411:30dexterhmm, i'll try ascii art#2016-12-1411:30dexterits got pixels everywhere#2016-12-1411:32cjmurphyYou can do it with the data structure itself. See visual-validation here: https://github.com/chrismurrph/advent-of-code/blob/master/dev/server/advent/thirteen.clj#2016-12-1411:34dextercool#2016-12-1411:34cjmurphypprint seems to understand what 'all lined up properly' means, as far as having a \n at the end of every row.#2016-12-1411:38thegeez@dexter for day8 your solution and mine differ from input line 29 "rotate column x=32 by 1"#2016-12-1411:39thegeezand as a shameless plug: using clojure.spec to parse instructions might help: http://thegeez.net/2016/12/09/parsing_clojure_spec_advent_of_code.html#2016-12-1411:54dexteroooh, thanks @thegeez#2016-12-1415:21dexterinterestingly it seems to be mutating rows other than the one I'm changing which is really bizzare, ah well at least I have something to investigate. thanks for the pointers guys#2016-12-1417:19bhaumanday 11 was a bear, but you can reduce the computational complexity immensely, hit me up if you have questions#2016-12-1417:31mnesporYour representation of the generators and chips is very, very cool#2016-12-1420:16bhauman@mnespor thanks 🙂 getting the next states from it is harder but it reduces the number of next states dramatically#2016-12-1515:15mnesporThe terrible sound you never want to hear when you're working on Day 15: https://www.youtube.com/watch?v=Jnb6uYAzuno#2016-12-1702:01bhaumanSo just so folks know, day 11 was an anomaly and the problems since then have been relatively easy ... nothing too crazy #2016-12-1720:45emgartenI've fallen behind on my advent coding, time to knock all these out and catch up again today 🙂#2016-12-1801:37samueldevhttp://www.gicentre.net/aoctimes#2016-12-2202:25angusiguesshttps://github.com/angusiguess/advent-of-code2016#2016-12-2417:01angusiguess@bhauman I really like the use of iterate in your solutions. Most of my searches are still loop-recurs, that's a really cool way to structure search.#2016-12-2417:04bhauman@angusiguess thanks! iterate allows you to operate on the list of individual states that result from each step, loop has less overhead but requires more thinking 🙂#2016-12-2417:05bhaumanI'm working on day 24 right now#2016-12-2417:05angusiguessYeah, that's the bit. Any time I could prevent some heavily nested destructuring would be nice.#2016-12-2417:07angusiguess24 is pretty good. I really liked 23 too, a lil' bit of manual jitting#2016-12-2417:08bhauman@angusiguess I looked at you stuff the other day, the other thing I would recommend is to take advantage of read-string 🙂#2016-12-2417:08bhaumannothing like having your own parser#2016-12-2417:09bhaumaner I mean reusing clojures powerful parser#2016-12-2417:10angusiguessHahaha, yeah there's a lot of regular expression use in there admittedly.#2016-12-2417:10bhaumanwhen I read 24 I was like really, that seems like a lot of work#2016-12-2417:10bhaumanbut here goes#2016-12-2417:11angusiguessLuckily you've probably got loads of bfs code already written#2016-12-2417:16bhauman🙂#2016-12-2907:03cjmurphyI had some trouble with the second part of day 22. Can anyone suggest a finished/correct pinned Github repo to study?#2016-12-2915:08poooogles@cjmurphy Check the pinned items.#2016-12-2915:27mnespornot mine (yet)!#2016-12-2915:29cjmurphySo far I've looked at a couple. One cleanly coded and worked for the example but not the real data. Another has a comment to the effect that it works but is a bit scrappy. The cleanly coded one seems to get into a recursive loop moving the node-that-has-enough-capacity around. So I might change it to remove loops as a possibility. "My code isn't a mess and it works" <-- looking for that 🙂#2016-12-3005:10bhauman@cjmurphy so mine didn't work for you?#2016-12-3005:13bhaumanmy map was kind of easy, so I guess I just got lucky#2016-12-3006:43cjmurphyThanks @bhauman: Yours was the clean one that worked well for the test data and would get into loops for the real data. With some anti-loop code I got G to the top left in 235 steps - but that's too high. And my anti-loop code is just hacky. I don't know why it would work for you and get into recursive loops for me. It is as if I cut and pasted the data and missed a line, or I need to grab a more recent version of your code. Will get back to it next week...#2016-12-3015:41bhauman@cjmurphy my data was pretty easy. I'd love to give it a try on your data.#2016-12-3018:22cjmurphy@bhauman: Until now I assumed we all had the same puzzle input. Here's mine: https://github.com/chrismurrph/advent-of-code/blob/master/advent/twenty_two.txt.#2016-12-3019:34bhauman@cjmurphy so if you pprint (use view-grid with 27 instead of 30 for your data) our two sets of data in grid form you will see that there is one row that blocks the progress. Your row is much higher so my score function fails. The simple thing to do is to have the score function detect if the row is the "wall" row and change its behavior based on wether it's above it or below it.#2016-12-3020:07cjmurphyThanks @bhauman . I see what you mean about the wall. Mine is on the 3rd row and yours is on 18th row. (post transpose, given your view-grid function does apply map vector, so a row is where all the ys are the same i.e. its really a column).#2016-12-3020:09bhaumanWell it really is a row in relation to the problem statement #2016-12-3020:10bhaumanWhen all the ys are the same it's a row#2016-12-3020:17cjmurphyYes 🙂#2016-12-3022:41angusiguess@cjmurphy Mine didn't read super well but another way to sidestep those conditions is to do two searches. I did one bfs from the beginning to the goal, and then a search for each open space to move it to the point on the first path.#2017-01-0303:59cjmurphyWhat helped me was to do as suggested in the question and make a visualization of the grid with \#. \. and \_. What worked for my data was to define \# as (>= (used node) 100). As suggested by @bhauman I made sure that when the wall was hit from below the only choice was to go left (have only one from position be created, rather than all surrounding from positions). @angusiguess: Your solution sounds like it will work and not require such an intimate knowledge of the structure of the grid. I'll test it out with my data now...#2017-11-2811:30orestis“The first day will unlock on December 1st at midnight Eastern Time. See you then!”#2017-11-2811:31orestisLast year I learned Elixir by doing all the puzzles of AoC 2016 (and eventually 2015) with it. This year I’ll be learning Clojure with AoC 2017. I’ve already started with the 2015 puzzles (now at day 12). It would be nice to discuss our progress here.#2017-12-0110:18orestisI’ve done day 1. You can follow my code here (SPOILER ALERT): https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/#2017-12-0110:30erwinfor me: https://github.com/ekroon/adventofcode2017/tree/master/src/adventofcode#2017-12-0112:40quanmine 🙂 https://github.com/tentamen/adventofcode/blob/master/src/adventofcode2017/day1.clj#2017-12-0112:40quanis there any private board for this channel?#2017-12-0112:40quanhttps://adventofcode.com/2017/leaderboard/private#2017-12-0117:39bhaumanyou can follow my answers here: https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017#2017-12-0117:40bhaumanhere are some others:#2017-12-0117:40bhaumanhttps://github.com/borkdude/aoc2017/blob/master/src/#2017-12-0117:40bhaumanhttps://github.com/mfikes/advent-of-cljs/tree/master/src/advent_2017/day_01#2017-12-0118:22thegeezHi all, I have created a private leaderboard for Advent of Code clojurians, use the code: 217019-4a55b8eb#2017-12-0118:32thegeezShare your solutions here by linking your repo: https://github.com/adventofcode-clojurians/adventofcode-clojurians#2017-12-0211:52orestisThanks @thegeez, I’ve made a pull request 🙂#2017-12-0211:52orestisThis is what I love the most, seeing how other people solve it and I get to learn about clojure.core functions!#2017-12-0211:52borkdude@thegeez I’ve made a PR too! 😄#2017-12-0211:56borkdude(uh, only now, I forgot to push the button)#2017-12-0211:58borkdudeIf you won’t make them all, does it still make sense to join the leaderboard? I might this year, but who knows. Santa might kidnap me.#2017-12-0212:04orestisDo join the leaderboard, it’s good fun.#2017-12-0212:04borkdudeWon’t I pull down the score by not finishing a puzzle?#2017-12-0212:05borkdudeI made an announcement on Twitter, Reddit and ClojureVerse about the github repo#2017-12-0212:07thegeezThe leaderboard is for fun, it is not a commitment to have to do all of the puzzles#2017-12-0212:08borkdudeThanks!#2017-12-0212:09thegeezI've invited you guys as collaborators for the repo, so you can merge additions too#2017-12-0212:09borkdude😄#2017-12-0212:12borkdudeJoin the 2017 Advent of Clojure fun! Link your repo: https://github.com/adventofcode-clojurians/adventofcode-clojurians Join the private leaderboard: 217019-4a55b8eb#2017-12-0213:37val_waeselynckHey folks, this is fun, thanks @borkdude and @thegeez for setting this up#2017-12-0214:33borkdude@val_waeselynck @thegeez set it up, not me 😉#2017-12-0218:27noogahaha, captcha done in a one-liner#2017-12-0222:28jmbHere's my repo for advent of code#2017-12-0222:28jmbhttps://github.com/julioberina/AdventOfCode#2017-12-0222:30borkdude@jmb Feel free to submit a PR to https://github.com/adventofcode-clojurians/adventofcode-clojurians and to join the leaderboard, code: 217019-4a55b8eb#2017-12-0222:30jmbWill do. Thanks#2017-12-0302:00abarylkoPR submitted!#2017-12-0303:47jmb"Solve problems, not puzzles." Well puzzles are problems except they're fun 😃#2017-12-0305:35fellshardHeh. Part 1, was faster to just figure out the nearest 'square' it was in, then do the rest by quick hand math. Part 2... welp, back to actually computing values#2017-12-0305:38dpsuttonwhat do you mean nearest square?#2017-12-0305:40dpsuttonah never mind. i didn't realize the third was out. i'm only on the first two so far#2017-12-0305:41fellshardOop#2017-12-0305:45dpsuttonits really neat to read others solutions. much different styles from me. lots of transducers. cgrand's common transducer's lib, lots more comment macros than me as well#2017-12-0305:46dpsuttonsome good use of for which i almost never use#2017-12-0305:46fellshardI tend to finish it quickly for placement, then go back and refactor / tidy in subsequent commits so that the process is still visible in the git history#2017-12-0305:47fellshardSo the style tends to shift subtly between the early / refined versions#2017-12-0305:47dpsuttonlook at this. i didn't even know for loops could do this#2017-12-0305:47dpsuttonhttps://github.com/thegeez/clj-advent-of-code-2017/blob/master/src/advent/day2.clj#L49#2017-12-0305:48dpsuttonis your stuff in that github repo?#2017-12-0305:50fellshardI've got a PR for a link to it#2017-12-0305:50fellshardhttps://github.com/armstnp/advent-of-code-2017#2017-12-0305:51fellshardtbf, I checked the for docs for yesterday's, and it was... underwhelming#2017-12-0305:51fellshardIt pretty much assumes you have full knowledge of list comprehensions in other langs#2017-12-0305:52dpsuttonmfikes has such a clean style#2017-12-0305:53dpsuttoni think a lot of us have similar ideas#2017-12-0305:53dpsuttonhttps://github.com/dpsutton/advent#2017-12-0306:03fellshardI should really get in the habit of using let bindings and intermediate names over blocks of threading pipelines#2017-12-0306:25theeternalpulsehttps://github.com/deepee0086-clj/adventofcode-clojurians#2017-12-0311:41borkdude@dpsutton Do you mean :while and :when? I used that too in day 2: https://github.com/borkdude/aoc2017/blob/master/src/day2.clj#L24#2017-12-0311:46ajsenjoying looking over everyone's solutions this year, learning some stuff! lots of transducer users, something i never really adopted in my own code. wish I had more time to participate this month#2017-12-0311:59borkdudeAdded some docstrings to my day 3 solution: https://github.com/borkdude/aoc2017/blob/master/src/day3.clj#2017-12-0312:09borkdude@ajs Usually you don’t really need transducers, it’s more a performance enhancement, but it’s fun to play around with them#2017-12-0312:10borkdudeI’m becoming curious about @cgrand’s xforms library now too#2017-12-0312:39orestisToday was interesting; I resisted doing part 2 the obvious way in the hope of finding some neat math formula, but eventually gave up.#2017-12-0312:40borkdudeYeah, some weird variation of fibonacci maybe 😉#2017-12-0312:41orestisOh, I have to study your directions implementation.#2017-12-0312:45orestisMine is a bit more … explicit 🙂 https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day3.clj#2017-12-0312:45borkdudeHaha: “no code for today”: https://www.reddit.com/r/adventofcode/comments/7h7ufl/2017_day_3_solutions/dqovogc/#2017-12-0312:46orestisHah, I did the same thing for the first part! Though I had to write a bit of code to validate my thoughts.#2017-12-0312:48borkdudeCool!#2017-12-0312:52orestisThis probably from experience on previous AoCs; A lot of times you can avoid a ton of code by teasing out some properties of the input. Though I didn’t know you could search online for sequences of numbers 🙂#2017-12-0313:19borkdudeLOL, Perl solution for day 2: https://www.reddit.com/r/adventofcode/comments/7h0rnm/2017_day_2_solutions/dqnaxuu/#2017-12-0315:07val_waeselynckClojure sequences are so awesome https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day03.clj#2017-12-0317:18theeternalpulseI'm interested in solving some of these with clojure.spec destructuring.#2017-12-0317:23noogahm#2017-12-0317:24noogajust did the first part of today’s puzzle#2017-12-0317:24nooga9 lines in a repl 😂#2017-12-0317:44borkdude@theeternalpulse I did one of those in 2015. Want to see the code?#2017-12-0317:47borkdude@theeternalpulse - https://blog.michielborkent.nl/blog/2017/10/10/parsing-a-circuit-with-clojure-spec/ - @thegeez also did one: http://thegeez.net/2016/12/09/parsing_clojure_spec_advent_of_code.html#2017-12-0400:42theeternalpulseI'll check it out, I think this was posted on a thread in reddit I had made.#2017-12-0317:47borkdude(co-incidentally, I did not know about Gijs’ blog post after I finished mine)#2017-12-0318:37mfikesWow. The solutions to day 3 no longer have the uniformity seen with days 1 and 2. I think my favorites so fare are the ones by tentamen and moxaj.#2017-12-0319:34borkdude@mfikes Cool! I noticed that tentamen’s strategy for day 3 part 1 was isomorphic to mine, but he represented the data more straightforward#2017-12-0319:35borkdudeWhen you don't notice the square pattern, the solution becomes different#2017-12-0319:36borkdudePureScript solution for comparison: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day3.purs#2017-12-0404:57minikomiHallo fellow adventers#2017-12-0405:08fellshardo/#2017-12-0405:22minikomiwell, day3 upped the ante a little i see#2017-12-0406:04dpsuttonyeah this is a tricky one#2017-12-0406:37dpsuttonmy inputs agree with their outputs for the first 23 values but i'm not getting the right answer for part b#2017-12-0406:53fellshardMisread the value they're looking for?#2017-12-0407:01dpsuttonturns out what i thought was a special case for one number was in fact general#2017-12-0407:02dpsuttoni was thinking in terms of rings of the spiral. so i ask which cells are adjacent in the inner ring and then which are adjacent in the same ring#2017-12-0407:22fellshardAhh#2017-12-0407:23fellshardI went for a generic 3x3 scan so I didn't have to worry about details of which cells would or wouldn't be filled#2017-12-0407:29dpsuttonyeah. i compute mine on the fly. and looking at the walk and create method, it looks better#2017-12-0407:29dpsuttonand the code i saw uses the coordinates to know when to turn,, etc. it looks nice#2017-12-0407:29dpsuttoni've never seen the with-tests macro either. that's pretty nice#2017-12-0407:30dpsuttonbut i do like the way mine came together#2017-12-0407:30dpsutton
(defn cell-value [n]
  (if (= n 1)
    1
    (let [inner (inner-touching n)
          outer (outer-touching n)
          touching (distinct (concat inner outer))]
      ;; so a cell's value is the sum of the values it is touching,
      ;; either in its own ring or in the inner ring
      (apply + (map cell-value touching)))))
#2017-12-0407:30dpsuttonbut lots of edge cases in the outer touching functoin#2017-12-0407:31dpsuttoncan you link me your day3.clj?#2017-12-0407:32dpsuttonand then wrap that in a memoize and map it over a range and drop while lest than what they are looking for#2017-12-0408:46minikomitotally brute forced day3#2017-12-0408:56minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day3.clj#L9-L14 Once I blagged that out on the repl / with pen & paper, I got it.. but not a solution I'm happy with#2017-12-0409:08val_waeselynckday 4: almost a no-brainer 🙂#2017-12-0409:13borkdude@val_waeselynck Very nice solution#2017-12-0409:20minikomiyeah, day4 was a piece of cake 😄#2017-12-0409:29fellshardYeh. Hurrah for quick set conversion#2017-12-0409:29borkdude@fellshard Link to your solution?#2017-12-0409:29fellshardhttps://github.com/armstnp/advent-of-code-2017/blob/master/day-4.clj#2017-12-0409:30fellshardI dumped the entire input in, heh. 😫#2017-12-0409:30minikomihahaha#2017-12-0409:30borkdudecool 🙂#2017-12-0409:30minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day4.clj I just used distinct & sort#2017-12-0409:31borkdudeI had this too at first #(= (count %) (count (set %)) == (apply distinct? ...)#2017-12-0409:31fellshardI haven't used distinct much, that's one to add to the toolkit!#2017-12-0409:31borkdudeYeah, I’ve seen sort a couple of times now. I feel so dumb#2017-12-0409:32fellshardFirst thing to think when looking for anagrams is a lex-sort : )#2017-12-0409:32fellshardNot when making them, so much#2017-12-0409:33borkdudeYeah, checking whether they exist vs. creating them#2017-12-0410:04val_waeselynckI'd like to practice core.logic, anyone knows a problem from AoC 2016 or 2015 for which it's a nice fit?#2017-12-0410:05borkdude@val_waeselynck hmm, I think this problem should be solvable with core.logic: https://blog.michielborkent.nl/blog/2017/10/10/parsing-a-circuit-with-clojure-spec/#2017-12-0410:08val_waeselynck@borkdude yeah so mostly a graph computation. Clara-rules or plumatic/graph could be a nice fit for that too.#2017-12-0411:10orestisThe variability of answers for the “simple” puzzles is really an indicator of the language used, I’d think. I also used distinct and sort 🙂 https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day4.clj#2017-12-0411:20minikomiooh, thought of a better way to do day3-part1#2017-12-0411:33borkdudeIs there a better way of counting with transducers? https://github.com/borkdude/aoc2017/blob/master/src/day4.clj#L58#2017-12-0411:55erwinmaybe use (into [] ,,,) with count instead of transduce with highlighted line? #2017-12-0411:56borkdudeyeah, or (count (sequence xform input))#2017-12-0411:58borkdudeso:
(count
   (sequence (map identity)
             [1 2 3]))
  ;; vs
  (transduce (map (constantly 1))
             +
             [1 2 3])
#2017-12-0412:27minikomiAnother idea:
(def xf (comp (filter odd?) (map inc)))
(transduce xf #(inc %) 0 (range 5))
#2017-12-0412:42borkdudedoesn’t compile#2017-12-0412:42borkdudeday 4: I first checked for palindromes, but then realized they were not anagrams and then refactored… and eventually ended up with an inefficient solution 😳#2017-12-0412:57borkdudeThis one is nice. He just does it in the browser while having his input open: https://www.reddit.com/r/adventofcode/comments/7hf5xb/2017_day_4_solutions/dqqjrq2/#2017-12-0413:25thegeez@borkdude for counts with transducers use net.cgrand.xforms/count to replace the (map (constantly 1))#2017-12-0413:33borkdude@thegeez something like this?
(first (eduction x/count
              [1 2 3]))
#2017-12-0413:34borkdude(not yet familiar with this lib)#2017-12-0413:35borkdudeo no, this is better: (x/count (map identity) [1 2 3])#2017-12-0413:40borkdudeRefactored: https://github.com/borkdude/aoc2017/commit/3e035c04ba00d520741b20090951ed66b2801ff5#2017-12-0414:01dpsutton@mfikes can you explain your invariant in your step function for day 3? In looking for the next location, you tag the locations as visited or not. And you find the first one unvisited after one that is visited in the list of potential squares left, down, right, up. Can you tell me why this works?#2017-12-0414:28mfikes@dpsutton I unfortunately don’t have anything close to a proof of why that approach works. It intuitively matches what I would do if I were trying to “spiral counter-clockwise,” without knowing which “linear direction” I’m already moving: I would try to choose the “counter-clockwise-most” free location. Perhaps a proof by contradiction could be constructed where if you chose any other location, you wouldn’t trace a spiral, but I don’t know if that reasoning is too sketchy. In short, it is a physical intuition that matches the concept of keeping your left hand on the wall and just tracing your path.#2017-12-0414:30dpsuttonsounds good to me. that was very clever. I'm enjoying reading the code. People that are doing the spiral are having to enumerate how to make decisions. The one I've seen used the coordinates and the fact that it is a square to know when to turn. Yours didn't need this big decision tree and is quite clever#2017-12-0414:33mfikesIt would be very interesting to categorize the kinds of solution “trees” that people have. I imagine they involve recognizing and using perfect squares, keeping track of a current linear direction and knowing when to turn (by memory, or by counting, or by being at a place where x=y or x=-y), or left-hand on wall. Maybe those are the 3?#2017-12-0414:34minikomiFor me it was -- did we change layers? go :up (went over another odd square), is it a "corner"? turn left.. (worked out a formula on the repl to generate a set of corners for current layer) otherwise, continue on in the current direction#2017-12-0414:36mfikesYeah, I suspect a broad class of the solutions have a “state” in #{:up :left :down :right} that gets flipped at a corner, and then differences on how you detect a corner.#2017-12-0414:38mfikesFWIW, I think my solution is wasteful of memory, but I got lucky that the problem fit in RAM. 🙂#2017-12-0414:38dpsuttonalso your potential candidates function is written really well#2017-12-0414:39dpsutton
(defn adjacent-locations
  "Given a location, produces the eight adjacent locations."
  [[x y]]
  (map (fn [[dx dy]]
         [(+ x dx) (+ y dy)])
    [[-1  1] [ 0  1] [ 1  1]
     [-1  0]         [ 1  0]
     [-1 -1] [ 0 -1] [ 1 -1]]))
#2017-12-0414:39dpsuttonahh the formatting messed up but the grid layout and the hole for current location is super nice#2017-12-0414:39mfikesThat second category doesn’t require O(n^2) memory, I’d guess#2017-12-0414:41borkdude@mfikes It felt a bit like cheating in the second part to keep a map around with all the previous “tiles” (as I called them), because that required more memory than needed maybe#2017-12-0414:41dpsuttonmy solution feels wasteful in trying to determine which cells in the current ring and inner ring are necessary for computation#2017-12-0414:41dpsuttonand involved bringing edge cases rather than just a notion of "add 'em if you got 'em"#2017-12-0414:44mfikes@dpsutton Yes, I like using a “graphical” code solution sometimes. Here is another, where you need to parse digits from a file containing their representations. I chose to solve it by putting their representations in the code and then constructing a reverse mapping from those representations to the digits.
(def rendered-digit-lines
  "A sequence of 3 lines representing all of the digits in order."
  [" _     _  _     _  _  _  _  _ "
   "| |  | _| _||_||_ |_   ||_||_|"
   "|_|  ||_  _|  | _||_|  ||_| _| "])

(defn- lines->digit-representations
  "Converts a sequence of 3 lines into a sequence of representations
  of the digits on those lines, where each digit representation is
  a sequence of character triplets."
  [lines]
  (apply map list (map #(partition 3 %) lines)))

(def digit-representation->digit
  "A map from digit representation to digit."
  (zipmap (lines->digit-representations rendered-digit-lines)
          (range 10)))
If you look at digit-representation->digit, you’ll see what I mean.
#2017-12-0414:46borkdudeAh, now I see it in your solution @mfikes, nicely done 🙂#2017-12-0414:46mfikesWith the “hole” in the matrix, I had to be careful not to let my editor reformat the code 🙂
#2017-12-0414:47dpsutton
(def numerals-text (str " _     _  _     _  _  _  _  _ \n"
                        "| |  | _| _||_||_ |_   ||_||_|\n"
                        "|_|  ||_  _|  | _||_|  ||_| _|\n"))

(def numeral-streams (->> numerals-text
                          str/split-lines
                          (remove str/blank?)))

(defn chunk3
  "Partition a string into 3 character substrings"
  [s]
(map #(apply str %) (partition 3 s)))
#2017-12-0414:52minikomiI think the 2d syntax from racket takes that kind of thing to the extreme https://docs.racket-lang.org/2d/index.html#2017-12-0414:53minikomiascii art as syntax#2017-12-0414:47borkdudespaces in between are not usually formatted right?#2017-12-0414:47dpsuttoni did the same thing#2017-12-0414:47borkdudeIs the digits example from last year?#2017-12-0414:47mfikesCursive will ignore the spaces and just mess it all up 🙂#2017-12-0414:47dpsuttonit's a kata about ocr#2017-12-0414:47dpsuttonhttps://github.com/codingdojo-org/codingdojo.org/blob/master/content/kata/BankOCR.md#2017-12-0414:47mfikesNo the digits example is from a pre-screen interview I did#2017-12-0414:47dpsuttonha same#2017-12-0414:48mfikesDamn. You are right! 🙂#2017-12-0414:48dpsuttondid you get the gig?#2017-12-0414:48mfikesYes, but I didn’t take it#2017-12-0414:49mfikesWow, the whole Kata looks the same. OK: User Story 1: I created a new project using lein new bank-ocr and this is the core file: https://gist.github.com/mfikes/f43d382057efa017ebfb User Story 2: I created a bank-ocr2, and took the contents of the previous story and simply added a account-number-value? method to compute the validity of a bank account: https://gist.github.com/mfikes/17ec1cfcdddfdba2b2f4 User Story 3: I created a bank-ocr3, took the stuff from User Story 2 and added a account-number-illegible? and revised the account number printing logic to print “?” characters and the additional “ILL” and “ERR” descriptors https://gist.github.com/mfikes/3c714859cb3da9384d52#2017-12-0414:50dpsuttonyup. was it a health care company you interviewed with?#2017-12-0414:50mfikesNo, it was Outpace#2017-12-0414:50dpsuttonah. i had the same thing with healthfinch#2017-12-0414:51mfikesFWIW, Outpace is/was awesome. The issue was mine: I backed out because I didn’t want to jump into full-time pairing without having done any, and not knowing what it was like to actually do it full time.#2017-12-0415:11dpsuttonhealthfinch seemed cool as well. they did the full time pair thing as well. which i think i would like if i were working remotely for the comraderie#2017-12-0415:37mfikesMy Day 4 solutions are up. Wondering if anyone found anything simpler. I debated the aspect of counting the number of times a predicate matches a sequence, but in the end went with the obvious one. Perhaps there will be more interesting variation on how people detect valid passphrases. https://github.com/mfikes/advent-of-cljs/commit/4bff774da3e9760e10fbb6cb1e33d7614a185634#2017-12-0419:31val_waeselynck@mfikes pretty much the same for me, with frequencies instead of sort#2017-12-0415:40borkdude@mfikes I think that’s as simple/efficient as it gets. It would be even simpler if you would put the two parts in one namespace, because a lot of the logic is re-usable (matter of taste)#2017-12-0415:40mfikesYeah, that’s a recurring pattern with the part 1 / part 2 aspect.#2017-12-0415:41borkdudeNotice that this one is almost the same as part 1, except for this line: https://github.com/borkdude/aoc2017/blob/master/src/day4.clj#L58#2017-12-0415:41mfikesI might take tha approach of putting common bits in a shared core ns.#2017-12-0415:42mfikesYes, for me the addition of sort was the difference.#2017-12-0415:44mfikesI think that for this one, if you happen to remember that there is a core predicate that you can use, the problem is trivial. (Especially compared to Day 3.)#2017-12-0415:52mfikesAhh nice—tentamen’s use of frequencies instead of sort might be faster if the words are long. :thinking_face:#2017-12-0415:54borkdude@mfikes With my puzzle input it turned out to be the same (sloppy benchmark of course): https://github.com/borkdude/aoc2017/blob/master/src/day4.clj#L77#2017-12-0415:58mfikesYeah, if s contains the entire contents of /usr/share/dict/words, in self-hosted ClojureScript:
cljs.user=> (time (do (sort s) nil))
"Elapsed time: 4993.764097 msecs"
nil
cljs.user=> (time (do (frequencies s) nil))
"Elapsed time: 1341.280391 msecs"
nil
#2017-12-0416:00mfikesI wish there were a better way to know who, of the people listed at https://github.com/adventofcode-clojurians/adventofcode-clojurians have finished Day 4.#2017-12-0416:00borkdude@mfikes The leaderboard!#2017-12-0416:01mfikes👍#2017-12-0416:01borkdudehttps://adventofcode.com/2017/leaderboard/private/view/217019#2017-12-0416:01borkdudeI was looking at this yesterday. There’s an API that returns JSON. Maybe we could somehow hook it up to the README?#2017-12-0416:02borkdudeIt would be a bonus puzzle 😉#2017-12-0416:03mfikesWhat I really want to do: Survey each solution, trying to pick out novel aspects that never crossed my mind or made better use of core fns.#2017-12-0416:04dpsutton^ yeah. be nice to see a curated list of different interesting aspects#2017-12-0416:05borkdudeThat would be a manual effort I guess but worth doing!#2017-12-0416:05mfikesWhat I’m interested in, from a learning perspective for example. If you are doing (= (count (distinct xs)) (count xs)), there is a core predicate that makes this trivial.#2017-12-0416:06borkdudeYes, or (set xs) is what I was doing#2017-12-0416:06mfikesIn fact, this core predicate, is almost cheating—it nearly solves Day 4 with one fn.#2017-12-0416:07borkdudeTwo things I learned today: distinct? and normalize data if you want to compare it on one property (without actually generating solutions which you don’t need).#2017-12-0416:08mfikesBy “normalize data,” are you thinking of the sort in day 4 part 2?#2017-12-0416:09borkdudeYes, maybe projection is the better word: sort and frequencies are a projection of anagrams into a smaller search space#2017-12-0416:09borkdudeMaybe there are other projections possible#2017-12-0416:10mfikesYes, need to dig up one of my math books, the term they use for your “projection” is “hash”, when applied to the concept of defining a partition (induced by an equivalence relation)#2017-12-0416:29dpsuttonthe math term i'd think applied would be an injection or an embedding. embed the underlying representation into its equivalence class#2017-12-0416:30dpsuttonA -> equivalence classes over A#2017-12-0416:34borkdude> In mathematics, a projection is a mapping of a set (or other mathematical structure) into a subset (or sub-structure) https://en.wikipedia.org/wiki/Projection_(mathematics) > In mathematics, an injective function or injection or one-to-one function is a function that preserves distinctness https://en.wikipedia.org/wiki/Injective_function > In mathematics, an embedding (or imbedding[1]) is one instance of some mathematical structure contained within another instance https://en.wikipedia.org/wiki/Embedding It might be taste, but I find projection the most fitting, or hash if you’re programming 🙂#2017-12-0416:35borkdudeEmbedding seems to be about groups, category theory etc.#2017-12-0416:47dpsuttonembedding is structural preserving. most examples are the copies of the naturals in the integers, integers in the rationals, rationals in the reals, etc#2017-12-0416:47dpsuttonso since this would throw away structure it's not the right usage#2017-12-0416:47dpsutton(or add structure)#2017-12-0416:49borkdudeah yes, it was nice when I got those classes about countability, etc. https://en.wikipedia.org/wiki/Countable_set#2017-12-0416:51borkdudeThere seems to be no name for a function (which is a projection) that is nor injective, bijective and surjective#2017-12-0416:51borkdudeWith the word projection I think of physics where you see the light being concentrated through a lense.#2017-12-0416:59mfikesThere are functions that tend to be named with the suffix -by, which take a function which essentially maps the values prior to doing whatever that function was going to do. Maybe there is a curiously recurring concept there.#2017-12-0417:01mfikesApropos to the AoC problem, distinct-by is a common one. For example https://github.com/clojure/clojurescript/blob/544c1b77d76d48f234cdb03746ea993158c46aff/src/main/clojure/cljs/util.cljc#L286-L297#2017-12-0417:09borkdudewe also use distinct-by in JVM clojure. It would be cool if there was also a distinct-by?, that would be effectively the solution for part 2 with sort or frequencies as a key#2017-12-0417:16borkdude@mfikes Looking at that link, wondering what they use Levenshtein for#2017-12-0417:17mfikesIt is used to find compiler configuration keys that are slightly off#2017-12-0417:17borkdudeand then it gives a suggestion: “did you mean…” or does it blindly accept it#2017-12-0417:18mfikeshttps://dev.clojure.org/jira/browse/CLJS-1492#2017-12-0417:19borkdudeawesome#2017-12-0417:20mfikes(This was an attempt to validate configuration, prior to Spec’s release.)#2017-12-0417:21borkdudeLevenshtein + spec could still be cool 🙂#2017-12-0417:23borkdudeas a layer on top maybe, or does the user now get a raw spec error message?#2017-12-0417:24borkdude(haven’t messed around with cljs compiler config for a while, it’s been the same for a while)#2017-12-0419:46chrisblomi like the advent of code repo, i've already picked some nice tricks#2017-12-0419:46chrisblomhere are my solutions: https://github.com/ChrisBlom/advent-of-code/tree/master/src/adventofcode/2017#2017-12-0419:46borkdude@chrisblom welcome to the repo, just merged your PR#2017-12-0419:47borkdude@chrisblom I think we also met at EuroClojure 2016 if I’m not mistaking#2017-12-0419:48chrisblomah yes, we were on the same bus & had coffee#2017-12-0419:50mfikes@borkdude The ClojureScript compiler doesn’t use Spec to validate compiler configuration. On the other hand, I believe Figwheel uses this lib https://github.com/bhauman/strictly-specking#2017-12-0420:16val_waeselynckWhat are you guys using for parsing inputs? I find it rather tedious, I wish I could find some pattern-matching lib to speed up the process#2017-12-0420:18val_waeselynckI realize parsing has not been much of a problem so far in AoC 2017, but as I'm working through some problems from last year I find them more and more demanding in this regard#2017-12-0420:27chrisblomusually instaparse for complex things, otherwise clojure core & string function#2017-12-0420:27borkdudeusually just str/split etc, but at one point clojure.spec, although I first did it with regexes, which was good enough#2017-12-0420:29noogaI’m solving in cljs, planck so .split. tbh I used it today for the first time#2017-12-0420:32borkdudeI didn’t solve all of last year’s problems. Can you give an example of more complex parsing problems there?#2017-12-0420:33mfikes@U0ARQ14BA For problems involving parsing integers, frequently Clojure solutions involve clojure.core/read-string as opposed to Long/parseLong. FWIW, Planck now has planck.core/read-string in master. (For now, I’ve just been using js/parseInt.)#2017-12-0420:34noogaoh, I just wrap numeric tables with [] in emacs and paste them into the repl#2017-12-0420:35noogatoo lazy to create files#2017-12-0420:36borkdudeThis guy doesn’t even need an editor: https://www.reddit.com/r/adventofcode/comments/7hf5xb/2017_day_4_solutions/dqqjrq2/#2017-12-0420:36mfikesRight 🙂 Previously I was even wrapping strings with '[] and just working on the resulting symbols#2017-12-0420:37borkdude@mfikes That’s what I’ve also done. Wrap in [], then clojure.edn/read-string and process the rest using clojure.spec 🙂#2017-12-0420:38mfikesHey, since we are working in a language that is so data-centric, it doesn’t feel like cheating to paste the data into the source file.#2017-12-0420:39borkdudeSome people do this to avoid the IO monad 😉#2017-12-0421:02val_waeselynck@borkdude @mfikes clever!#2017-12-0421:02val_waeselynckI meant for problems like this one: https://adventofcode.com/2016/day/23#2017-12-0421:37noogaI’d totally quote that#2017-12-0421:51borkdude@val_waeselynck for that input i’d use the mentioned [] + read-string approach and then simply destructuring + case for processing#2017-12-0500:58bhauman@val_waeselynck read-string is your secret weapon https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2016/day23.clj#L7#2017-12-0420:30noogatodays puzzle is hilariously straightforward#2017-12-0420:34mfikesIt was distinctly easy 😜#2017-12-0420:36noogaand applying map will sort the second part ;D#2017-12-0423:10bhaumanMy solutions for day 3 and doy 4 are posted...#2017-12-0423:11bhaumannow to check everyone else's#2017-12-0501:27bhaumanwow I love how everyone is getting into it this year#2017-12-0501:46bhauman@grzm I'm digging how you generated the direction list for day3#2017-12-0502:38minikomisent a PR for readme!#2017-12-0504:16RJbeing brand new to Clojure and trying to figure out AoC is incredibly frustrating haha#2017-12-0505:12fellshardHmmmmm. Day 5 Part B is taking an awful long time to run with my soln#2017-12-0505:13fellshardProbably should've gone mutable or something#2017-12-0505:14fellshard... oooooh#2017-12-0505:22minikominot too tricky, 2nd part took a while to execute#2017-12-0505:24fellshardMine's not finishing, even giving it a fair chunk of time...#2017-12-0505:24minikomidon't forget you can go out both ends of the list#2017-12-0505:31minikomiswitching to a transient for the "instruction tape" sped it up a bit#2017-12-0505:33minikomi..actually a lot .. 2s vs 11s#2017-12-0505:39fellshardI've got an infinite loop or something in mine#2017-12-0505:39fellshardOstensibly it should always exit, all instructions gravitate towards +3#2017-12-0505:39fellshardChecking for both bounds#2017-12-0505:46fellshardIn the end, I made a mistake by using https://repl.it#2017-12-0505:46fellshard-_-#2017-12-0505:47fellshardLightning fast on local#2017-12-0506:41dpsuttonthat was fun. did we all just use maps and update?#2017-12-0506:45erwinI started my solution with also updating the new location, made the problem a lot harder and incorrect 😕 Part B took some time indeed#2017-12-0506:46dpsutton(time (solve2)) "Elapsed time: 22630.602584 msecs" for map with update#2017-12-0506:56dyankowskyHeading to bed, but I used a vector and update, no transients, and part 2 took about 10s to run for me.#2017-12-0507:09cjmurphyI used iterate - easy to think about a state -> state function and an exit condition on that state.#2017-12-0507:10borkdudeI want to start on day 5 but suddenly I’ve got CIDER problems…#2017-12-0507:15borkdudeStill managed with inf-clojure 🙂#2017-12-0508:12val_waeselynck@dpsutton I used an int-array, took about 120ms to solve 2 🙂#2017-12-0508:13Timmine is taking forever 😄#2017-12-0508:16val_waeselynckSo yeah, Clojure is fast 😇#2017-12-0508:41Timwooo, it’s finally finished! Probably took around 10 minutes, though I was running it through a REPL instance in Visual studio code.#2017-12-0508:45magic_bloatUsing update-in and a vector - Part 2 took 36 seconds on my little computer.#2017-12-0508:46magic_bloathttps://github.com/bloat/aoc2017/blob/master/src/net/slothrop/aoc2017/day5.clj#2017-12-0508:54TimThis is my slow solution: https://pastebin.com/Cj4VZVR3 I’m new to Clojure, if anyone can see something I’m doing that’s really stupid (and maybe explains the slowness) that’d be very helpful#2017-12-0508:56val_waeselynck@U892TNBRN you should inline inc-accordingly, when you define it as a function it will convert primitive ints to objects#2017-12-0508:59val_waeselynck@U892TNBRN and maybe more importantly, you should probably type-hint nrs with ^ints nrs#2017-12-0508:59val_waeselynckevaluate (set! *warn-on-reflection* true) before running your code to see if that's the case#2017-12-0509:12Timthanks for the suggestions, very interesting! I’m missing the understanding of why those things make a difference though, I’ll do some googling to find that out 🙂#2017-12-0509:12TimI am indeed getting some warnings after setting warn-on-reflection#2017-12-0509:12Tim
null:12 recur arg for primitive local: current_index is not matching primitive, had: Object, needed: long
Auto-boxing loop arg: current-index
Reflection warning, projects/clojure/advent-of-code/day5/solution.clj:8:37 - call to static method alength on clojure.lang.RT can't be resolved (argument types: unknown).
Reflection warning, projects/clojure/advent-of-code/day5/solution.clj:10:21 - call to static method aget on clojure.lang.RT can't be resolved (argument types: int, int).
#2017-12-0509:34val_waeselynck@U892TNBRN you have a bug actually, you want to do (alength nrs)#2017-12-0509:41val_waeselynckwell not a bug actually, but probably not what you intended either#2017-12-0510:43Timgood catch!#2017-12-0509:16borkdudeHow can I get rid of this warning:
Boxed math warning, ... - call: public static boolean (java.lang.Object,long).
Trying mutable arrays for speedup
#2017-12-0509:24orestisI used vectors and assoc, “Elapsed time: 23169.810878 msecs” for part 2.#2017-12-0509:25borkdudeMine takes about 5 seconds#2017-12-0509:28borkdudeI have one variant with a vector, a transient and an array: https://github.com/borkdude/aoc2017/blob/master/src/day5.clj I’m still wondering why the array version is so slow#2017-12-0509:30orestis@val_waeselynck Do you have your solution somewhere?#2017-12-0509:33minikomiyeah, transient seems fastest for me too:
advent.2017.day5> (c/quick-bench (solve2 input))
Evaluation count : 6 in 6 samples of 1 calls.
             Execution time mean : 6.091951 sec
    Execution time std-deviation : 254.233063 ms
   Execution time lower quantile : 5.895512 sec ( 2.5%)
   Execution time upper quantile : 6.518767 sec (97.5%)
                   Overhead used : 1.887221 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
advent.2017.day5> (c/quick-bench (solve2-int-array input))
Evaluation count : 6 in 6 samples of 1 calls.
             Execution time mean : 1.403268 sec
    Execution time std-deviation : 18.226029 ms
   Execution time lower quantile : 1.381179 sec ( 2.5%)
   Execution time upper quantile : 1.419574 sec (97.5%)
                   Overhead used : 1.887221 ns

advent.2017.day5> (c/quick-bench (solve2-transient input)))
Evaluation count : 6 in 6 samples of 1 calls.
             Execution time mean : 1.306124 sec
    Execution time std-deviation : 15.056565 ms
   Execution time lower quantile : 1.291127 sec ( 2.5%)
   Execution time upper quantile : 1.320360 sec (97.5%)
                   Overhead used : 1.887221 ns
#2017-12-0509:33val_waeselynck@orestis https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day05.clj#2017-12-0509:35minikomioh maybe it was not casting to int in the comparison#2017-12-0509:36minikomidoing so gives:
advent.2017.day5> (c/quick-bench (solve2-int-array input))
Evaluation count : 6 in 6 samples of 1 calls.
             Execution time mean : 1.393645 sec
    Execution time std-deviation : 10.345934 ms
   Execution time lower quantile : 1.381836 sec ( 2.5%)
   Execution time upper quantile : 1.404963 sec (97.5%)
                   Overhead used : 1.887221 ns
#2017-12-0509:36borkdudeah, alength instead of count#2017-12-0509:39val_waeselynckSome performance tips: - Vars lookups are slower and harder to optimize than locals lookups - Make sure to type hint primitives and primitive arrays when necessary - Primitive values (ints, bytes, booleans etc.) cannot travel across functions (they get boxed into objects) - Protocols are way faster than multimethods - Looking up a key in a record type is 5 to 10x faster than looking it up in a plain map#2017-12-0509:39minikomilength doesn't change so i set that in a let before the loop.. for me it was the comparison not being (int 3) which was slowing things down#2017-12-0509:47borkdudeok, fixed: https://github.com/borkdude/aoc2017/blob/master/src/day5.clj#L54#2017-12-0509:47borkdude240ms#2017-12-0509:52orestis@val_waeselynck I modified your version a bit, almost halved the execution time (650ms -> 380ms) - just moved the alength call outside.#2017-12-0511:32val_waeselynck@orestis Do you mean that moving the alength call outside improved the perf of my version by 2x?#2017-12-0514:45orestisI think that might be it, yes. I’m still a noob so I’m not really sure what I’m doing there; type hinting is a bit opaque, but I don’t get any reflection warnings so…#2017-12-0509:52orestishttps://github.com/orestis/adventofcode/blob/2bfc12415ab9681642b1b79fc04a846e795574a2/clojure/aoc/src/aoc/2017_day5.clj#L95#2017-12-0509:53orestisI thought I would be able to typehint a single ^int but I get this: https://stackoverflow.com/questions/15230061/cant-type-hint-a-local-with-a-primitive-initializer#2017-12-0509:54orestisAdding the (int i) in comparisons actually makes things slower.#2017-12-0509:55minikomiwow, borkdude's version smokes mine#2017-12-0509:55minikomi
advent.2017.day5> (c/quick-bench (bork-int-arr input))
Evaluation count : 6 in 6 samples of 1 calls.
             Execution time mean : 195.021813 ms
    Execution time std-deviation : 516.193459 µs
   Execution time lower quantile : 194.408773 ms ( 2.5%)
   Execution time upper quantile : 195.624313 ms (97.5%)
                   Overhead used : 1.887221 ns

#2017-12-0509:57minikomi
(defn solve2-int-array [input]
  (let [i (into-array Integer/TYPE input)
        len (count input)]
    (loop [idx (int 0) c (int 0)]
      (if (or (> 0 idx) (<= len idx)) c
          (let [v (aget ^ints i idx)]
            (if (<= (int 3) v)
              (aset-int i idx (dec v))
              (aset-int i idx (inc v)))
            (recur (+ idx v)
                   (inc c)))))))
#2017-12-0509:57minikomiAny ideas of where to type hint that?#2017-12-0509:58orestis@borkdude’s version takes 1000ms on my machine… Is running this inside a CIDER repl a bad idea?#2017-12-0509:58borkdude@minikomi put this in your code:
(set! *warn-on-reflection* true)
(set! *unchecked-math* :warn-on-boxed)
#2017-12-0509:59minikomiI have both, but neither is complaining#2017-12-0509:59borkdude@orestis Did you pull the most recent?#2017-12-0509:59borkdude@minikomi Maybe at ^ints before i in let#2017-12-0510:00borkdude@minikomi also don’t use count, but alength#2017-12-0510:00borkdude@minikomi also don’t use aset-int, I discovered that’s slower as well#2017-12-0510:01minikomiOK making those changes#2017-12-0510:01minikomisped up some#2017-12-0510:01orestis@borkdude Just did, got it to 600ms.#2017-12-0510:01borkdude@orestis what kind of machine are you on?#2017-12-0510:01minikomiwoah#2017-12-0510:01orestisI am using int-array instead of into-array, would that make a difference?#2017-12-0510:01minikomisped up a ton#2017-12-0510:01minikomihaha#2017-12-0510:02orestis@borkdude 2014 Macbook Pro, 2.8GHz i5#2017-12-0510:02borkdude@orestis Are you running exactly my code or an adaptation ?#2017-12-0510:03orestisTiny adaptation; I create the array with int-array, and don’t have the reducible-resource stuff; but I do this for all the adaptations.#2017-12-0510:03borkdudeThis is from 2015 btw: https://stackoverflow.com/questions/34153369/why-is-this-clojure-program-working-on-a-mutable-array-so-slow#2017-12-0510:04minikomithe ^ints in the let by itself took me from 1.3s -> 98ms#2017-12-0510:04orestis@borkdude Have a look at https://github.com/orestis/adventofcode/blob/6537d8dda0825871fdd9acad0daf95570d82ef87/clojure/aoc/src/aoc/2017_day5.clj#L95 ; it’s the fastest in this file.#2017-12-0510:04minikomiweird.. it's like, make an array of type integer (by the way, it's an integer array!)#2017-12-0510:05borkdude@orestis that’s effectively the same as mine?#2017-12-0510:05borkdudeoh yeah int-array#2017-12-0510:06orestisI wonder if try/catch OutOfBounds exception would work.#2017-12-0510:06borkdudebtw I pushed a new version, but the performance is the same#2017-12-0510:07orestisBTW, everyone has different inputs so we need a baseline if we are going optimize this silly thing 🙂#2017-12-0510:07minikomigood point 😆#2017-12-0510:07borkdudehaha oh yeah#2017-12-0510:07borkdudemy input file is on github as well#2017-12-0510:08borkdudetfw when you get out of bed somewhat earlier for Advent of Code, but CIDER won’t connect to your nrepl anymore and you have to fall back on inf-clojure …#2017-12-0510:09orestisIs there any project that could easily take those different implementations and run proper benchmarks etc? Not sure how warm/cold JIT makes any difference here.#2017-12-0510:10minikomiafter more poking around, aset vs aset-int does indeed seem to be the culprit.#2017-12-0510:11minikomiaset:
Evaluation count : 6 in 6 samples of 1 calls.
             Execution time mean : 102.748740 ms
aset-int:
Evaluation count : 6 in 6 samples of 1 calls.
             Execution time mean : 1.391871 sec
#2017-12-0510:11borkdudeAt this point you might want to write it in Java and just call from Clojure 😉#2017-12-0510:11minikomitrue. still fun to overthink 🙂#2017-12-0510:13orestis@borkdude Well, the “naive” Clojure version that uses a vector can look really similar to the one that uses int arrays. Still a 10 line function anyway 🙂#2017-12-0510:15borkdudetrue, but dealing with things like “should I use aset or aset-int” isn’t fun imho#2017-12-0510:16borkdudewhy so slow, aset-int#2017-12-0510:18orestisThat’s because y’all know too many core functions for your own good 🙂#2017-12-0510:24minikomiGoogling aset-int slow, this book seems to concur: https://books.google.co.jp/books?id=4QacPa1vwMUC&amp;pg=PA148&amp;lpg=PA148&amp;dq=%22aset-int%22+slow&amp;source=bl&amp;ots=2AACgvj4qk&amp;sig=ysLjEPVkInOBPUdMj9Wgdgyqrz0&amp;hl=en&amp;sa=X&amp;ved=0ahUKEwitpbCt0_LXAhUDNJQKHYiRDo8Q6AEIQzAE#v=onepage&amp;q=%22aset-int%22%20slow&amp;f=false Seems like something to stay away from in the future then!#2017-12-0512:23chrisblomIs there a usecase for aset-int if it is slower than aset? Or is it just a legacy function?#2017-12-0512:23borkdude@chrisblom very good question#2017-12-0512:24mfikesIt's looking like loop / recur is the most popular for day 5, followed by iterate#2017-12-0512:26borkdudeI usually start with reduce, but when I need multiple things as the argument of the reducing function, I give up and fall back on loop#2017-12-0512:26chrisblomif i macro expand the definition and clean it up a bit there are only 2 differences: aget has :inline metadata and uses .set instead of .setInt#2017-12-0512:26mfikesI actually used reduce (on (range) as the step counter)#2017-12-0512:27borkdude@mfikes Yeah, I think loop can mostly be rewritten to a reduce with destructuring#2017-12-0512:28borkdude@mfikes Neat that you’re doing it with cljc now#2017-12-0512:29mfikesThe nice trick I missed is relying on getto return nil, as opposed to pre-checking the index#2017-12-0512:29borkdude@mfikes That trick worked for me, until I got to primitive arrays#2017-12-0512:29mfikes(You can learn so much by studying the range of solutions. 🙂 )#2017-12-0512:30mfikesYeah, that's the story. You can write clean Clojure, and then when you want it to go faster, you delve into messiness. (I suppose that's true in any language.)#2017-12-0512:31mfikesAt least in Clojure we can really push hard on the "clean" end of the spectrum.#2017-12-0512:32borkdudeWell, Scala really is better (not the right word, I must say, friendlier/easier) at this kind of stuff, while still allowing you to do functional. I think the type system helps to generate more primitive stuff if needed.#2017-12-0512:33borkdudeBut I only need mutability this during Advent of Code really, and then only for extra performance, not for getting the answer, so 🙂#2017-12-0512:35mfikesAhh, right. Does Scala essentially generate code like C++ does when instantiating templates?#2017-12-0512:36mfikes(The closest I think I've seen Clojure come to this is how ClojureScript has macro variants of functions that can try to generate optimal code based on what is available at compile time.)#2017-12-0512:46borkdude@mfikes Don’t know, I just didn’t have as much trouble with it as in Clojure: https://gist.github.com/borkdude/b37563939639b40013f483361a7c5d8f#2017-12-0512:47borkdude(I was just learning Scala back then for fun)#2017-12-0512:50borkdude(@mfikes http://www.drmaciver.com/2008/06/scala-arrays/)#2017-12-0512:59mfikesAn example of how (I suppose essentially anything) can be done with macros is how str in ClojureScript passes the literal strings in something like (str "a" 1 "b") untouched. (I think in Clojure it may still end up invoking (.toString "a") and (.toString "b").)#2017-12-0513:00mfikesThat may not be the best example, but it illustrates that anything can be done at compile time with macros if you are trying to eek out perf for the generated code.#2017-12-0513:02borkdude@mfikes How does this relate to primitive array performance?#2017-12-0513:03mfikesI'm just saying that if Scala can do nice things with types, Clojure may also be capable of the same if you go down the road of using macros (and if you have access to inferred types).#2017-12-0513:04borkdudeWith the macro approach you can get rid of some calls like (str "foo" "bar"), but will it get you very far, I don’t know?#2017-12-0513:05mfikesI suppose Scala has the benefit of much richer type inference.#2017-12-0513:05borkdudeThere was also a talk about this topic at EuroClojure 2017: http://2017.euroclojure.org/nada-amin/#2017-12-0513:06borkdudewhere the type system was used to generate fast low level code: https://www.youtube.com/watch?v=QuJ-cEvH_oI#2017-12-0513:08mfikesI haven't thought about this too much, being on the JavaScript side of things 🙂 In that world, the engine watches the values fly by and infers their types, dynamically generating optimal machine code, and de-opting if it sees a value that violates assumptions, etc.#2017-12-0513:08mfikesThe end effect is that where in Clojure you can manually hint, in ClojureScript, you need to let the lower layers do it for you.#2017-12-0513:11borkdudeYeah, I kind of wondered why you don’t need to add type hints in ClojureScript, so that’s how it works#2017-12-0513:19borkdudePureScript solution: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day5.purs#2017-12-0513:20mfikesThe primary type hints in ClojureScript are ones that help avoid checked if: If the compiler knows it is dealing with a Boolean value for example, it can just use JavaScript's notion of truthiness.#2017-12-0513:25borkdude@mfikes Do you perhaps have a clojurescript version of day 5 which runs on Node, to compare it with the performance of PureScript day 5?#2017-12-0513:26mfikesI'll convert it to Lumo real quick#2017-12-0513:26mfikesOr are you interested in Closure-optimized code?#2017-12-0513:26mfikesI could write that fairly easily.#2017-12-0513:27borkdudedoes it help for performance? and mutable array version is fine#2017-12-0513:28mfikesI can take your fastest mutable array version, and produce an optimized Node-compatible JavaScript file for you to use to compare with PureScript.#2017-12-0513:28mfikesWhat is your recommended mutable array version?#2017-12-0513:32borkdudeI don’t about the absolute fastest, but this is my fastest: https://github.com/borkdude/aoc2017/blob/master/src/day5.clj#L54#2017-12-0513:43mfikesCool. I'm putting together a GitHub repo so it is possible to revise the code if needed and build and run it in Node#2017-12-0513:44borkdude@mfikes I only asked if you had this laying around, not if you wanted to put time in it, but if you like to do it, still thanks 🙂#2017-12-0513:44mfikesNah, it is close to trivial#2017-12-0514:16mfikes@borkdude For me, ClojureScript / Node.js is running that array-based solution 25% faster than Clojure. Here it is, set up so it is trivial for anyone to reproduce perf results or change the code: https://github.com/mfikes/advent-day-5-cljs-node#2017-12-0514:17borkdude@mfikes Awesome, I’ll try#2017-12-0514:22mfikesInterestingly Planck runs it at about the same speed as the Closure optimized JavaScript under Node.js. (JavaScriptCore is wicked fast.)#2017-12-0514:26borkdudeI get 240 ms on the JVM, 400 on Node#2017-12-0514:28borkdudehmm, weird enough, in lein I get 800 ms.. it’s slower than from my REPL it seems#2017-12-0514:33val_waeselynckMaybe the JVM didn't have enough time to warm up. V8 is probably more optimized than the JVM for quick warmup#2017-12-0514:42borkdude@mfikes boot: 240 ms, lein 800 ms?#2017-12-0514:43mfikesI think I need to add the -server JVM option to the lein setup in that project#2017-12-0514:44mfikes@val_waeselynck I specifically have the perf test running over and over again to avoid warm up issues. (Good point, though 🙂 )#2017-12-0514:45val_waeselynck@mfikes yeah I noticed but I'm wondering if that's enough, Criterium typically seems to do much more sophisticated things to take both warmup and GC into account :thinking_face:#2017-12-0514:45borkdudeOoh even faster with your input (I forgot the inputs differs)#2017-12-0514:46mfikes@val_waeselynck I agree. But we have a huge perf diff right now to sort out 🙂#2017-12-0514:47mfikesYeah, it needs -server#2017-12-0514:47borkdudereally weird, I run both tests from the repl. Exact same code now.#2017-12-0514:47mfikesPatching the repo#2017-12-0514:47borkdudedoes boot run with server by default maybe?#2017-12-0514:48borkdudeor maybe that’s the default and lein adds client#2017-12-0514:49mfikesYeah, lein run evidently wants to minimize startup latency#2017-12-0514:50borkdudeyeah, now it works 🙂 180ms#2017-12-0514:52borkdude@mfikes Thanks, that was a nice adventure#2017-12-0514:53mfikesYeah, with any perf tests you really really need to provide the code so others can try it as well 🙂#2017-12-0514:54val_waeselynck@borkdude so what are your numbers now?#2017-12-0514:54borkdude@val_waeselynck same as mike’s repo, ~ 180 ms on my machine in the JVM#2017-12-0514:55mfikesMy numbers are Clojure: 167 ms, ClojureScript, Closure / Node.js: 384 ms Planck: 570 ms#2017-12-0514:56val_waeselynckAlright, thanks!#2017-12-0514:57borkdudeSome guy on Reddit had 75 ms using C++… we’re not done yet 😉#2017-12-0514:58borkdudeMaybe we can write a Clojure program which generates C++ and run that one#2017-12-0514:58borkdudeDidn’t Rich write C++ like that as well in Common Lisp? 😉#2017-12-0514:59val_waeselynckYes, but was it the same input? 🙂#2017-12-0514:59borkdudeAssembly would probably be not so difficult for this problem#2017-12-0514:59borkdudeor maybe straight JVM bytecode?#2017-12-0515:00borkdudehttps://www.reddit.com/r/adventofcode/comments/7hngbn/2017_day_5_solutions/dqsdslv/#2017-12-0515:00borkdudewell, twice the speed of C++ ain’t bad#2017-12-0515:01val_waeselynckespecially when you haven't compiled it with heavy optimizations#2017-12-0515:02val_waeselynckJIT is probably the best strategy for low latency (including the whole write + debug + compile + run process)#2017-12-0515:06bhaumanso why does the array implementation take so long???#2017-12-0515:10bhaumanchecking it out with ints instead of longs#2017-12-0515:10dyankowsky@mfikes AFAIK, Scala's generics aren't like C++ templates. Scala's generics are mostly the same as Java's generics - type erasure and boxing. There are conveniences, like implicit parameters to capture class tokens. But they're fundamentally not a code generation mechanism, as C++ templates are.#2017-12-0515:13mfikes@bytecrafter Cool. I vaguely (perhaps mis-) recall something in Scala generating code covering the possible permutations of primitives, but that was perhaps 5 years ago for me.#2017-12-0515:14mfikesAhh, "specializing" is what I recall. For example http://www.scala-notes.org/2011/04/specializing-for-primitive-types/#2017-12-0515:15bhauman@mfikes are you guys using the same set of inputs for benchmarking?#2017-12-0515:15mfikesNo, we realized that this causes a problem @bhauman#2017-12-0515:16mfikesAt least, we caught one instance recently were we forgot the data changes. 🙂#2017-12-0515:16bhaumanthe final solution should determine the complexity#2017-12-0515:16bhaumanmine is in the 28 million#2017-12-0515:16bhaumanrange#2017-12-0515:16mfikesI haven't been too involved in the perf game, until some fun stuff this morning#2017-12-0515:17bhaumanwell my fastest is 5 seconds! where as yours is in the ms#2017-12-0515:17mfikesMy day 5 result was 24,315,397#2017-12-0515:17bhaumanok so same complexity
#2017-12-0515:17bhaumandarn it son#2017-12-0515:18mfikesMy reduced-based solution using persistent data structures takes about 5 seconds#2017-12-0515:18mfikesThat benchmark repo is banging on primitive arrays#2017-12-0515:18mfikesIt is Java in disguise 🙂#2017-12-0515:19bhaumanmy array implementation performs much worse, so I'm going to take this opportunity to learn some things ....#2017-12-0515:20mfikesI optimized for readability, not worrying about perf: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_05.cljc#L14-L19#2017-12-0515:20borkdudeCame up with another perf optimization, but didn’t help: https://github.com/borkdude/aoc2017/blob/master/src/day5.clj#L127 Still 232 ms#2017-12-0515:23borkdude@bhauman Didn’t see your solution, but aset-int are not so good for performance, we found out today#2017-12-0515:23borkdude@bhauman Also:
(set! *warn-on-reflection* true)
(set! *unchecked-math* :warn-on-boxed)
helps
#2017-12-0515:25bhaumanoh dems some tricks#2017-12-0515:25bhaumancool I just posted mine#2017-12-0515:34val_waeselynck@bhauman According to the docs, I think you probably want (int ...) instead of ^int ... https://clojure.org/reference/java_interop#optimization#2017-12-0515:34bhaumanyeah thanks I'm still working on the scratch area#2017-12-0515:34bhaumanjust added that thanks!#2017-12-0515:35bhaumanI never have to optimize stuff like this so this is kind of a blast#2017-12-0515:44val_waeselynck@bhauman I'm currently writing a home-made GraphQL engine, so I'm totally in the performance business right now 🙂#2017-12-0515:45bhaumanoh darn, sounds fun?????#2017-12-0515:48val_waeselynckit is 🙂 actually not exactly a GraphQL engine, since it's an alternative to GraphQL with some added features.#2017-12-0515:49val_waeselynckHowever, I guess the core server-side algorithm could be reused to implement both GraphQL engines and Om Next routers#2017-12-0515:34chrisblom@borkdude mine is similar, but i'm not passing the mutable array via recur, runs in 130ms on my machine: https://github.com/ChrisBlom/advent-of- @code/blob/master/src/adventofcode/2017/day05.clj#L16-L33#2017-12-0515:34borkdudeMaybe try the same input for comparison?#2017-12-0515:35borkdudeI tried without passing the array in the loop, but it did not matter I think#2017-12-0515:35borkdudeit’s just a reference right#2017-12-0515:35mfikes@borkdude What kind of black magic is involved in annotating a local as a primitive ^int but treating it as a Boolean?#2017-12-0515:35mfikesHmm. Something to learn there...#2017-12-0515:36mfikesI'm referring to the annotation on this line https://github.com/mfikes/advent-day-5/blob/master/src/advent_day_5/core.cljc#L17#2017-12-0515:36borkdude@mfikes The bound value is an int, because and returns the int. But if it’s non-true, it won’t be bound at all#2017-12-0515:36mfikesAhh. Thank you. I need to macroexpand to see that.#2017-12-0515:36mfikesHah!#2017-12-0515:40borkdude
(set! *warn-on-reflection* true)
(set! *unchecked-math* :warn-on-boxed)
(if-let [^int x (and true 1)] (inc x) :else) ;; good
(if-let [x (and true 1)] (inc x) :else) ;; bad, boxed
(macroexpand ’(if-let [^int x (and true 1)] (inc x) :else))
(let* [temp__4655__auto__ (and true 1)] (if temp__4655__auto__ (clojure.core/let [x temp__4655__auto__] (inc x)) :else))
#2017-12-0515:41borkdudeit seems macroexpand doesn’t show the type hints?#2017-12-0515:47borkdudeit will if you (set! *print-meta* true)#2017-12-0515:49dyankowsky@mfikes Interesting, I didn't know about that in Scala. Thanks!#2017-12-0515:49mfikesIs [1 -3] a legitimate input? (In other words, can it exit by going negative?)#2017-12-0515:49borkdude@mfikes I thought about that, but since I got the answer, I didn’t worry about it anymore 😉#2017-12-0515:50mfikesOK. Cool.#2017-12-0515:52borkdudeThis is just awesome. Advent of Code in pure Postgres… https://github.com/xocolatl/advent-of-code-2017/blob/master/Day05/script.sql#2017-12-0515:55mfikes@borkdude I got yours to run in 80 ms. I'll put the intersting change in a branch#2017-12-0515:55borkdudewowie#2017-12-0515:55borkdudethat is very close to the C++ version#2017-12-0515:56mfikesI was trying to eliminate a checked if in what ClojureScript produces, and got it to run faster, but it also made the Clojure faster (if everything pans out)#2017-12-0515:57borkdudeif this works, we have world domination#2017-12-0516:00mfikesHere is the change https://github.com/mfikes/advent-day-5/commit/45aa111e8df606884f5af4ffd886aa2a8af393eb?w=1#2017-12-0516:01mfikesIt is actually around 87 ms#2017-12-0516:02borkdudeveeery nice, let’s see if I understand#2017-12-0516:02mfikesWow. Same speed in Node#2017-12-0516:02borkdudestill the correct answer?#2017-12-0516:02mfikes24315397#2017-12-0516:02mfikeshttps://clojurians.slack.com/archives/C0GLTDB2T/p1512487050000252#2017-12-0516:04borkdude@mfikes I don’t understand why you need the if-some at all there#2017-12-0516:05borkdude(aget maze cur-pos) should always return something when (< cur-pos length)#2017-12-0516:05mfikesOK. Let me address that 🙂#2017-12-0516:08bhaumanOK I got it in the ball park#2017-12-0516:08bhaumanby switching to aget#2017-12-0516:08borkdude@mfikes turned it to a let, seems to help a bit#2017-12-0516:08borkdudeso, if-let made it slower.. hmm#2017-12-0516:08mfikesPerhaps crappy expansion?#2017-12-0516:09mfikesHmm#2017-12-0516:13mfikesIt is surprising that ternary < in Clojure botches the perf by an order of magnitude, but not so in ClojureScript. Specificially, trying to do the right thing and testing (< -1 cur-pos length) instead of just (< cur-pos length) makes it run in 900 ms instead of 87 ms.#2017-12-0516:15mfikesAnyway, I put the 87 ms-version on master https://github.com/mfikes/advent-day-5/blob/master/src/advent_day_5/core.cljc#L8-L27#2017-12-0516:15borkdudeWell, I could in fact shave of a couple of ms with this trick: https://github.com/borkdude/aoc2017/blob/master/src/day5.clj#L115#2017-12-0516:16mfikesOh, so check for zero and then optimize for that case?#2017-12-0516:17borkdude@mfikes with your data input 78 ms#2017-12-0516:17borkdudeyes#2017-12-0516:17mfikesWow. I'll apply that one! We must dominate.#2017-12-0516:18mfikesOr, if you want I can add you as a committer and you can push your change in.#2017-12-0516:18borkdudeok, add me 🙂#2017-12-0516:19bhaumanyou could check for negative as well right?#2017-12-0516:21mfikesI'm not seeing why it replaces 0 with 2. Should it be 1 instead?#2017-12-0516:21borkdudenope#2017-12-0516:21borkdudebut maybe this is no good, I don’t see a real change when applied to your benchmark with dotimes#2017-12-0516:22mfikesok#2017-12-0516:22borkdude
Run 58 of 60.
“Elapsed time: 102.893639 msecs”
24315397
Run 59 of 60.
“Elapsed time: 90.53835 msecs”
24315397
Run 60 of 60.
“Elapsed time: 100.259889 msecs”
24315397
---
Run 1 of 60.
“Elapsed time: 129.65845 msecs”
24315397
Run 2 of 60.
“Elapsed time: 104.405081 msecs”
24315397
Run 3 of 60.
“Elapsed time: 96.121724 msecs”
#2017-12-0516:22mfikesOh, I see why 2. You are trying to skip a loop cycle?#2017-12-0516:23mfikesClever#2017-12-0516:23mfikesHence the (+ steps 2)#2017-12-0516:24borkdudewith criterium I do see a difference of about 4-5 ms#2017-12-0516:24borkdudewhich may not be significant#2017-12-0516:24borkdude@bhauman negatives?#2017-12-0516:33borkdude@mfikes we have world domination now… congrats.#2017-12-0516:33borkdudePosted it under the C++ solution: https://www.reddit.com/r/adventofcode/comments/7hngbn/2017_day_5_solutions/dqt0s5v/ 😎#2017-12-0516:34mfikesIn Node, my reduce-based "normal" solution takes 8 seconds, while the optimized version takes 80 ms in Node.#2017-12-0516:38mfikesI should post this as an 80-ms JavaScript based solution: https://gist.github.com/mfikes/4ef3d2c3efc8f72a848e9149e1229e84#2017-12-0516:46borkdudeis that the output of the compiler?#2017-12-0516:47mfikesYeah! 🙂#2017-12-0516:49borkdudecool!#2017-12-0516:50borkdude74ms now#2017-12-0516:50borkdude@chrisblom Removed the maze from the loop arguments, another 4 ms 🙂#2017-12-0517:05borkdude@mfikes Could you try this commit? It seems to be 30 ms faster on Node on my machine than the original: https://github.com/mfikes/advent-day-5/commit/3fdda4ba34d144fb795674f51ba81927c9125d1c#2017-12-0517:06chrisblomhas any tried unrolling the loop yet?#2017-12-0517:08borkdude@mfikes also pushed a cljc fix, but it worked nonetheless#2017-12-0517:09dpsuttonto unroll a loop you need to know in advance how many times you will loop, no? and that isn't known until you get there#2017-12-0517:09dpsuttonunless you mean make the loop include several iterations with escape hatches in each?#2017-12-0517:10dpsuttonbut i thought loop unrolling was a strategy to evade the loop test which we cannot escape so we always pay the branch penalty#2017-12-0517:18mfikes@borkdude Yes, Node is faster for me with your commit#2017-12-0517:18borkdudeHow fast now?#2017-12-0517:20mfikesOh wait. It actually went for an original speed of 86 ms to slower at around 93 ms#2017-12-0517:22borkdudeOn my machine, branch master:
24315397
Run 57 of 60.
“Elapsed time: 122.000000 msecs”
24315397
Run 58 of 60.
“Elapsed time: 136.000000 msecs”
24315397
Run 59 of 60.
“Elapsed time: 125.000000 msecs”
24315397
Run 60 of 60.
“Elapsed time: 128.000000 msecs”
24315397
#2017-12-0517:22borkdudeBranch faster:
“Elapsed time: 114.000000 msecs”
24315397
Run 58 of 60.
“Elapsed time: 109.000000 msecs”
24315397
Run 59 of 60.
“Elapsed time: 106.000000 msecs”
24315397
Run 60 of 60.
“Elapsed time: 109.000000 msecs”
24315397
#2017-12-0517:22borkdude(Node)#2017-12-0517:22mfikesRight, something was messed up with the squashed commit I put on master. It was causing an inexplicable regression.#2017-12-0517:23mfikesI've since removed it.#2017-12-0517:25borkdudeI noticed when compiling some code on the background, severely impacted the performance, so these times also depend on what your machine is doing. For some real benchmarking criterium or something is needed.#2017-12-0517:25borkdudeIn my repo I used criterium, which gives better time for this commit#2017-12-0517:27borkdudeMaybe node also has something like this#2017-12-0517:28mfikesFWIW, I fixed the master branch so it now has the better perf number#2017-12-0517:29mfikes(At least better under Node)#2017-12-0517:29borkdude@mfikes do you mean this commit is the newest now? https://github.com/mfikes/advent-day-5/commit/45aa111e8df606884f5af4ffd886aa2a8af393eb#2017-12-0517:30mfikesYeah, on my instance of Node that one runs faster#2017-12-0517:31borkdudethat’s weird, because the if-some is not needed… 🙂#2017-12-0517:32borkdudeon my machine it’s faster too#2017-12-0517:33mfikesRight... the if-some should be cleaned up. It is unnecessary, but AFAICT it doesn't hurt perf.#2017-12-0517:33borkdudewhen I change the if-some to let it becomes slower#2017-12-0517:33borkdudeWAT#2017-12-0517:34mfikesI was referring to perf on Node. Let me make the change as well to be sure.#2017-12-0517:34borkdude@mfikes I was also talking about that#2017-12-0517:36borkdudeWith let:
"Elapsed time: 132.000000 msecs"
24315397
Run 59 of 60.
"Elapsed time: 129.000000 msecs"
24315397
Run 60 of 60.
"Elapsed time: 138.000000 msecs"
24315397
With if-some:
Run 57 of 60.
"Elapsed time: 111.000000 msecs"
24315397
Run 58 of 60.
"Elapsed time: 106.000000 msecs"
24315397
Run 59 of 60.
"Elapsed time: 111.000000 msecs"
24315397
Run 60 of 60.
"Elapsed time: 106.000000 msecs"
24315397
(Node)
#2017-12-0517:36mfikesAhh... indeed, converting it to a let and dropping the else branch makes it slower for me on node than having an if-some... going to look at the generate JavaScript#2017-12-0517:37borkdudeSo far we have learned: if-let slows down, but if-some speeds up 😛#2017-12-0517:38grzm@bhauman thanks 🙂 I'm amazed at all of the different ways people approach this, and I'm sure what seems obvious to one seems clever to someone else. I'm learning a lot by reading. Trying to figure out a way to make it all stick as efficiently as possible.#2017-12-0518:51spfeifferSo AoC leads to the discovery of obscure perf regressions…great!#2017-12-0518:52borkdude@spfeiffer We discovered that Node gets speedup from adding obsolete code…#2017-12-0518:55spfeiffer@borkdude I think that is a very nice metaphor for the Node ecosystem ☺️#2017-12-0519:13mfikes@borkdude I did a bunch of tests. It seems to boil down to the fact that an extra nil-check, while not free, pays off because it lets the Node optimizer know that it is doing arithmetic on non-`null` values. (We as humans know that it the values pulled out of the array are not nil, but the optimizer doesn't.) In fact, I saw one test run with Lumo where it started off slow, and then "figured it out" on its own, and started running at the faster speed, while in a loop, without me doing anything. I also found that you can get a lesser speedup by changing (aget maze cur-pos) to (int (aget maze cur-pos)). This gets compiled down to JavaScript that involves | 0, which is evidently a ostensibly useless appendage added to JavaScript arithmetic code to "hint" to the optimizer that it is doing integer arithmetic. So, when-some or even a more straightforward (when-not (nil? ...)) ..., while not changing the functionality, ends up acting like a hint, or an assertion that the optimizer can use to its advantage.#2017-12-0519:14borkdudeInteresting and at the same time frightening#2017-12-0519:18mfikesOne interesting question in my mind: In the early days, types were used for performance. Will we reach a point where types are inferred at runtime sufficiently well so that the performance of such code behaves just as well as statically typed code. Or, to put it another way, with enough money being dumped into JavaScript VMs, will ClojureScript end up running faster than Clojure one day. It can already do this at times for unhinted Clojure, but I'm wondering if it will all get to be so good where you can just write your dynamic unhinted Lispy code and it will run extremely fast.#2017-12-0519:21borkdudeThat would be nice, but nothing beats full type inference for this I think?#2017-12-0519:22borkdudeI mean, if you have all type info, what else is there to guess?#2017-12-0519:28borkdudePureScript probably won’t have much benefit from typing to performance because of its target?#2017-12-0519:35mfikesAn analogy: I used to find it odd that you didn't pass flags like -O3 to the javac compiler. It was difficult to just "let go" of the idea optimizing at compile time, and defer it all to runtime. One argument is that if you let the runtime do the optimization, it can leverage the call and memory access patterns in your program, and perhaps do a better job than a static analyzer could do. If static type info is available, then, sure, it can be useful. I'm just wondering if we as human developers will be in the low-level business of type hinting a decade or two from now.#2017-12-0519:38borkdudeMaybe there will be a more fuzzy type of static type inference based on ML?#2017-12-0519:38borkdudeThat could also assist in IDEs and for performance, without getting in the way#2017-12-0519:43borkdudeI think Steve Yegge once wrote about this#2017-12-0519:43borkdudehttps://steve-yegge.blogspot.nl/2008/05/dynamic-languages-strike-back.html#2017-12-0519:43borkdudeThat’s 10 years ago… he’s now fond of Kotlin 😉#2017-12-0520:11tbaldridge@mfikes I'd argue we're already there with pypy#2017-12-0520:13dpsuttoni don't follow why types hints allow for anything more than asserted types#2017-12-0520:13tbaldridgeI've seen entire transducer pipelines compile down to half a dozen assembly instructions.#2017-12-0520:14dpsuttonif a jit finally believes you that they are ints, wouldn't it believe you if you said they were ints in the first place?#2017-12-0520:14tbaldridge@mfikes what you describe is pretty much the premise of tracing JITs. https://en.wikipedia.org/wiki/Tracing_just-in-time_compilation#2017-12-0520:15tbaldridge@dpsutton hints can also be used for storage optimization. In that case they're a bit stronger than assertions.#2017-12-0520:15tbaldridgeBut yeah, hints are a way of papering over the inability of a JIT to deoptimize.#2017-12-0520:16tbaldridgeJS and PyPy do deoptimization. Put only ints in a list and the JIT will create a typed array of ints. Once you try to put an object in the array it will convert the list into an list of objects and then add the object to it.#2017-12-0520:18tbaldridgeSo the question becomes, why should you ever have to hint at all? In Clojure it's because the JVM doesn't allow user-level deoptimization.#2017-12-0520:18tbaldridgeAnd it's a method jit, and that doesn't help either#2017-12-0520:18dpsuttoni'm not sure i follow. deoptimization sounds like recognizing a bad assumption?#2017-12-0520:18dpsuttonand that wouldn't happen with types? or does it#2017-12-0520:18dpsuttonI thought these were ints but there's a map so now they're all objects#2017-12-0520:18dpsuttonis what i'm imagining the JIT is doing#2017-12-0520:20tbaldridgeWell with types and something like C# or C++ deoptimization can never occur, since all the types are known at compile time.#2017-12-0520:20tbaldridgeOn the JVM it's a bit strange, but it will deoptimize a callsite. So as you implement IFoo on more and more types the JVM may recompile every method that calls IFoo.foo.#2017-12-0520:21tbaldridgeThat's why adding stuff like tuples to Clojure doesn't work since the perf improvement is a wash compared to the de-optimized callsites.#2017-12-0520:21dpsuttoninteresting. thanks for explaining. my jvm knowledge is very slim#2017-12-0520:22tbaldridgeWhat tracing jits like PyPy do, is look at the context for a loop. Within a single loop they inline all methods and reduce all types to their lowest level parts. So as long as you never call a method with a map within that single loop, the code for handling that map will never exist in the loop.#2017-12-0520:33mfikesHmm. So, transducers are a little more friendly to tracing JITs, it sounds…#2017-12-0520:40tbaldridgeRight, on the JVM transducers are always boxed. On JS the JIT is a bit more tracing-like, so you get primitive math loops.#2017-12-0520:40tbaldridgeDo a transduce over an array in CLJ and CLJS and the CLJS version will be much faster if all you're doing is math.#2017-12-0520:58bhaumanso that wasn't a good idea? you starting to get hungry?#2017-12-0520:59borkdude@bhauman did you comment on my deleted blob?#2017-12-0520:59bhaumanyeah 🙂#2017-12-0521:00borkdudeah - yeah, it wasn’t a feasible idea#2017-12-0521:01mfikesFor the day 5 problem, it seems that it reads and writes rapidly to lots of parts of a big array. I wonder if memory bandwidth is affecting things more than any of the math / logic.#2017-12-0521:02tbaldridge@mfikes in what language? and what access pattern?#2017-12-0521:03tbaldridgeI've seen 4x perf improvement from making sure I scanned an array from 0 to X instead of walking it randomly.#2017-12-0521:03borkdudePretty satisfied that we got it down to 75 ms, the same number the C++ and Rust guys are mentioning on Reddit 🙂#2017-12-0521:03bhaumanand thats for CLJS? right?#2017-12-0521:04borkdudein my case Clojure JVM#2017-12-0521:04bhaumanoh dang#2017-12-0521:04borkdudeI can’t reliably benchmark node, I use criterium in Clojure#2017-12-0521:05tbaldridgeI wonder how much using unchecked math would improve that?#2017-12-0521:05bhaumanoh thats been tried#2017-12-0521:05bhaumanor has it?#2017-12-0521:05borkdude@tbaldridge https://github.com/borkdude/aoc2017/blob/master/src/day5.clj ?#2017-12-0521:06tbaldridgeah, cool, I missed that post#2017-12-0521:06bhaumanusing :warn-on-boxed#2017-12-0521:07borkdude@tbaldridge Mike discovered that if-let generates less performant code than just if and let…#2017-12-0521:07borkdudethis and a couple of other tweaks shaved off some ms here and there#2017-12-0521:07mfikesThe array is only about 1000 integers. We read from a spot which tells us where to jump to next, and we write to the spot we just read from with a new offset derived from the old one. Repeat until we hop out of the array.#2017-12-0521:08mfikesOh, I'd summarize it this way: By guarding a block of code with a nil check, that code runs faster under Node, even though we know (as humans) that none of the values are nil.#2017-12-0521:09borkdudeyeah, but on JVM Clojure the code ran also faster without if-let#2017-12-0521:09mfikesOh. OK.#2017-12-0521:09bhaumanyeah if and then let is faster than if let#2017-12-0521:09borkdudewe went from if-let to if-some and then to let… if-some turned out to be beneficial on Node… it’s hard to optimize for both worlds#2017-12-0521:10bhaumanwow it's a lot faster#2017-12-0521:10tbaldridgeyeah, I doubt memory perf is the issue then. As 1000 integers at 8 bytes that should easily fit in the cache.#2017-12-0521:10mfikesYeah. I mistakenly assumed it was a much larger array.#2017-12-0521:11bhaumanusing if and then let cut my time in half#2017-12-0521:11borkdudewhile the if-some was an obsolete check, the Node runtime still benefited from that, crazy#2017-12-0521:11mfikesDon't we already have a solution that is around the same as one of the C++ ones out there?#2017-12-0521:12borkdude@mfikes Yes, I posted it 5 minutes ago: (quick-bench (part-2-array-faster?)) ;; 74 ms, or did you mean something else?#2017-12-0521:12borkdude(on a Macbook Pro 2015)#2017-12-0521:13mfikesWe are running through 20 million steps in 70 ms. Around a few nanoseconds per loop?#2017-12-0521:15mfikesIf that's around 10 machine cycles, it might be hard to improve upon :thinking_face:#2017-12-0521:16borkdudeThe assembly is probably straightforward, but I only did that in university…#2017-12-0521:16tbaldridgehey @mfikes you had a twitter thing about emitting machine code form JS right?#2017-12-0521:16tbaldridgegot the machine code for this?#2017-12-0521:17mfikesYes, you can enable JavaScriptCore's logging of compilation. But it is very hard to actually catch the code you'd like. (It spews stuff faster than you can consume it.) I'll try and see 🙂#2017-12-0521:17borkdudemaybe writing a C program is easier#2017-12-0521:18mfikesYeah, this is probably a few lines of C#2017-12-0521:19mfikesHere is the tweet @tbaldridge referred to https://twitter.com/mfikes/status/935527618274873344#2017-12-0521:21mfikesIn short if you
JSC_dumpDisassembly=true planck src/advent_day_5/core.cljc
in https://github.com/mfikes/advent-day-5, you will see lots of disassembly
#2017-12-0521:48mfikesPerhaps this is some of the assembly JavaScriptCore is creating for our loop, but it is hard for me to tell: https://gist.github.com/mfikes/5c68510b6ab2207b85cc92697a005a3e#2017-12-0521:56borkdudeI’m trying a C program now, about 195 ms on my machine#2017-12-0521:57mfikes@borkdude Did you compile it with optimizations enabled?#2017-12-0521:59borkdudeNo, I just did gcc -o day05 day05.c && ./day05, what optimizations do you suggest?#2017-12-0522:00borkdudeah 57 ms with -O3#2017-12-0522:00mfikes🙂#2017-12-0522:00borkdudethat’s probably all the speed you’re gonna get#2017-12-0522:01mfikesIt's remarkable we are able to produce pretty much the same result with some carefully crafted Clojure.#2017-12-0522:01borkdudeFWIW I tried this one: https://github.com/vesche/adventofcode-2017/blob/master/day05.c#2017-12-0522:08dpsuttonthis has got to be the best channel on slack right now#2017-12-0522:17mfikesI can reproduce the 57 ms. I also tried inlining the input data array (instead of having the program read it from disk), but it still runs at the same speed—dominated by the loop.#2017-12-0522:29borkdudeI also applied the zero checking trick to the C program, but it didn’t help there#2017-12-0522:36borkdudean extra branch (simple boolean/int check in C) is more costly on the lower level than just doing the same loop all the time?#2017-12-0522:38borkdudeTalking about this one:
while (current <= 1036 && current >= 0) {
    move = numbers[current];
    /* if (move == 0) { */
    /*   numbers[current] = 2; */
    /*   steps += 2; */
    /*   current += 1; */
    /* }   */
    /* else */
    {
      if (move >= 3)
        numbers[current] -= 1;
      else
        numbers[current] += 1;
      current += move;
      steps += 1;
    }
  }
With code uncommented, it becomes slower, not faster.
#2017-12-0522:39borkdudeI also tried to move the >= 3 branch to the first place, but that becomes even slower#2017-12-0522:42borkdudeCalling it a night. Tomorrow is another puzzle…#2017-12-0522:44tbaldridgebranch prediction at work most likely#2017-12-0522:44tbaldridgeeasier to to calculate something than do a conditional#2017-12-0605:38minikomiTIL.. max-key Also, TIL: max-key gives the last instance for which (k x) is greatest#2017-12-0608:32borkdudeSolved it, but no real insights for today#2017-12-0608:33borkdudeAnd it’s fast enough, so no optimizing today 😉#2017-12-0608:34val_waeselynck@borkdude same thing, a bit disappointed 🙂#2017-12-0608:38borkdudeI almost never use loop in Clojure, but for Advent of Code I used it a couple of times now#2017-12-0608:43orestisI got to use transient for the first time today. I like it how you can do that inside a tight loop so you don’t have to do the whole functional way for something that you know is never leaving that function.#2017-12-0608:46orestisI just love this:
(nth (iterate next-cycle [0 2 7 0]) 5)
;; => [2 4 1 2]
#2017-12-0608:49minikomiah, that's nice#2017-12-0608:51val_waeselynckI did use quot and rem for better performance, wondering if that's wasted#2017-12-0608:52minikomiAlso, I learned you can use :as when destructuring vectors#2017-12-0608:52orestisIt’s only ~13k steps for me…#2017-12-0608:52borkdudeyeah, that’s nice, but could you apply iterate to find the solution, as you had to compare the previous ones#2017-12-0608:53orestisNope. But it’s ok, because detect-loop is only 7 lines of code and uses next-cycle.#2017-12-0608:54borkdudeit’s what I thought too, iterate is nice, but I can’t use it. I also have a next-state fn#2017-12-0608:54orestisI solved part 2 directly in the REPL; I love this.#2017-12-0608:56orestisOf course, this only is possible because we have a small problem today — couldn’t do it with yesterday’s 20 million operations.#2017-12-0608:56minikomitrying to think of a clever way to use take-while & iterate..#2017-12-0608:57borkdudeIf you would only have to compare the last two solutions (as I initially thought) you could maybe do it like lazy fibonacci: https://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci#2017-12-0608:58borkdudebut now you have to be able to look back at all solutions and it breaks down#2017-12-0608:59orestisI don’t think you can do it without a reduction over sequence…#2017-12-0609:00minikomi
(count
 (let [seen (volatile! #{})]
   (take-while #(and (not (@seen %))
                     (vswap! seen conj %))
               (iterate step [0 2 7 0]))))
#2017-12-0609:00minikomilol#2017-12-0609:01minikomishipit#2017-12-0609:04minikomiwait, need to clip the head until the first repeat too#2017-12-0609:08orestisWhy volatile and not a transient?#2017-12-0609:10orestisHah! Now I got the and bit :)#2017-12-0609:11minikomitransient also works.. not sure when to use which to be honest!#2017-12-0609:14orestishttps://stackoverflow.com/questions/31288608/what-is-clojure-volatile#2017-12-0609:14orestisA nice discussion there ^#2017-12-0609:17minikomiyeah i did find that, but seems a bit unclear in the end. My takeaway was: if the value has IEditableCollection, go for transient unless you want to co-ordinate between multiple threads, in which case use volatile! for speed and atom if you need what atom brings.. sound accurate?#2017-12-0609:20chrisblomi'd be careful with volatile! in a multithreaded context, as vswap! is not atomic, concurrent vswaps will give unreliable results#2017-12-0609:21minikomiAh, I misread: > Volatiles are faster than atoms but give up atomicity guarantees so should only be used with thread isolation.#2017-12-0609:24chrisblomi think there was a check on volatiles to detect concurrent swaps, but they removed it to use it in transducers#2017-12-0609:26minikomiah, seems like: atoms - mutable, can be updated from multiple threads, guaranteed atomic volatiles - mutable, can be updated from multiple threads, but not atomic so be careful transients - mutable, require thread isolation#2017-12-0609:27chrisblomyeah that sounds right, maybe the check was on transients, i don't remember#2017-12-0609:30val_waeselynckI would rephrase this as: - atoms: slowest, no caution required - volatiles: faster, but avoid concurrent updates - transients (or any non-synchronized data structure such as java.util.HashMap): fastest, but don't update after sharing to other threads#2017-12-0609:31minikomiif each thread is only, for example, updating a specific index on an array I think it's safe.. but you'd best know what you're doing#2017-12-0609:54minikomihttps://gist.github.com/minikomi/0bf7bedb64767a832be172c5b0767d1e Trying some things out, only the atom gives [1000 1000 1000 1000 1000] every time.#2017-12-0609:57minikomiwow, atoms are cool.#2017-12-0610:00chrisblomthats a good way to test it, but the transient example is incorrect#2017-12-0610:01chrisblomyou need to pass the result of transient operation around (for assoc!, dissoc! etc), like how you would use normal assoc#2017-12-0610:14theeternalpulseI just sat down with pen and paper for day 3 and I think I have a breakthrough lol. Love the aha moments of an interesting problem.#2017-12-0610:21minikomiSo it's not really equivalent to atom/volatile, in that you have to reassign it or use it in, say, a reduction where it's explicitly the updated version which is being passed around?
(let [t (transient {})]
  (assoc! t :test 3)
  (assoc! t :banana 4)
  (persistent! t))
seems to work fine, but in some cases it might fail?
#2017-12-0610:38chrisblomyes, try this with like 1000 assoc! with different keys and see what happens#2017-12-0610:33minikomihttps://clojuredocs.org/clojure.core/assoc! ooh, the docs explain well. thanks for the tip!#2017-12-0610:40chrisblom@minikomi this shows how it fails:
(let [t (transient {})]
  (dotimes [i 1000]
    (assoc! t i :test))
  (persistent! t))
#2017-12-0610:42minikominice! that's what i was looking for, yeah#2017-12-0610:44chrisblomits because for small maps a (transient) array-map is used#2017-12-0610:44chrisblomand for larger maps (> 10) it switches to a hash-map, so then assoc! returns a different object#2017-12-0610:45minikomiright#2017-12-0610:45minikomithanks, learned something tonight 🙂 and now i go home#2017-12-0612:24borkdudeI thought I had a nicer solution with mapv for next-state but that doesn’t pan out#2017-12-0612:29borkdudee.g. (next-state [0 1 2 3 6 4 5 0]) => [1 2 3 3 0 5 6 1] is hard to do with mapv, where you don’t have some state in the function#2017-12-0612:54noogayeah#2017-12-0612:55noogamapv doesn’t cut the cases where your number is smaller than count-1#2017-12-0612:55noogalooks like the redistribution has to be sequential#2017-12-0612:55noogaI just found out 😄#2017-12-0612:57borkdudePart 1 finishes in 63 ms on my machine#2017-12-0612:58borkdude(without using transients or mutable arrays)#2017-12-0613:23noogacompletely instant on my machine in planck, so cljs#2017-12-0613:24mfikesI'm at 260 ms (Planck, optimized code for elegance, readability over speed)#2017-12-0613:25borkdude@mfikes I would if I could find a more elegant solution, but mapv didn’t work… curious about other solutions.#2017-12-0613:25borkdudeI find this a creative way of finding part 2: https://github.com/EsthervdS/AdventOfCode/blob/master/day6/Reallocation.java#L52#2017-12-0613:26mfikesI'm cleaning up my code before committing, and then I'll dig into the backlog here 🙂#2017-12-0613:40noogahow do I profile in planck?#2017-12-0613:42mfikes@nooga I haven't hooked in any profiling tools, but ClojureScript has a simple-benchmark core fn. See, for example http://blog.fikesfarm.com/posts/2017-11-18-clojurescript-performance-measurement.html#2017-12-0613:43noogahm#2017-12-0613:43nooganot too shabby#2017-12-0613:51borkdudeThe a in advent stands for array#2017-12-0613:51borkdude@nooga Cool! Without transients/mutable?#2017-12-0613:57nooga@borkdude no tricks, plain and simple#2017-12-0613:58borkdude@nooga Can you try my input for comparison? https://github.com/borkdude/aoc2017/blob/master/resources/day6.txt#2017-12-0613:58noogasure#2017-12-0613:59noogadefinately in the ballpark#2017-12-0614:01borkdudenice#2017-12-0614:02mfikesMy solutions committed https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_06.cljc#2017-12-0614:02noogaI’m running this in planck because I’m too lazy to lein new for this#2017-12-0614:02nooga@mfikes could you share your input? for performance comparison?#2017-12-0614:03mfikeshttps://github.com/mfikes/advent-of-code/blob/master/resources/advent_2017/day_06/input#2017-12-0614:03mfikesMy perf is around half a second#2017-12-0614:04mfikes@borkdude I think I ended up with the same approach as Esther's
#2017-12-0614:05nooganow that’s peculiar: solve1: 157.606489msecs, solve2: 157.029896msecs#2017-12-0614:05noogaSo you’ve got harder input than me and @borkdude#2017-12-0614:09mfikes@minikomi Yes, the behavior of max-key is crucial if you happen to use it in this problem. Documented in Clojure and pending for ClojureScript https://dev.clojure.org/jira/browse/CLJS-2403#2017-12-0614:11mfikesI haven't use loop / recur yet in this year's solutions. (Probably to the detriment of ouright perf.)#2017-12-0614:11minikomiRight, which is why I ended up rolling my own indexed-max#2017-12-0614:14Miķelis Vindavsnot sure if you’ve incorporated this into your optimized solutions, but
(defn max-ndx [banks] (.indexOf banks (apply max banks)))
seems to be quite a bit faster than
(defn max-ndx [v]
  (- (dec (count v))
     (apply max-key (vec (rseq v)) (range (count v)))))
#2017-12-0614:14borkdude@minikomi me too: https://github.com/borkdude/aoc2017/blob/master/src/day6.clj#L14#2017-12-0614:17minikominice. same concept, but neater than mine#2017-12-0614:17minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day6.clj#L9-L17#2017-12-0614:22Miķelis Vindavsfirst-max-pos can be optimized using reduce-kv#2017-12-0614:22Miķelis Vindavs
(defn first-max-pos'
  [nums]
  (reduce-kv (fn [[_ max-val :as m]
                  k cur-val]
               (if (> cur-val max-val)
                 [k cur-val] m))
             [0 0]
             nums))
#2017-12-0614:22Miķelis Vindavsruns 4-5x faster for me#2017-12-0614:22minikomifaster than mine too?#2017-12-0614:23bhaumanjust commited mine https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day06.clj#2017-12-0614:23Miķelis Vindavssorry didn’t see yours, I’ll check#2017-12-0614:23bhaumannow to look at all the great stuff you guys have wrought#2017-12-0614:23Miķelis Vindavs@minikomi yes#2017-12-0614:23minikomi(.indexOf block max-val) is probably fastest! ahh#2017-12-0614:24minikomigood one#2017-12-0614:25Miķelis Vindavs
cljs.user=> (time (dotimes [_ 10000] (first-max-pos [1 2 3 4 6 1])))
"Elapsed time: 146.985052 msecs"

; with reduce-kv
cljs.user=> (time (dotimes [_ 10000] (first-max-pos' [1 2 3 4 6 1])))
"Elapsed time: 33.089442 msecs"

cljs.user=> (time (dotimes [_ 10000] (get-indexed-max [1 2 3 4 6 1])))
"Elapsed time: 68.978079 msecs"

; using .indexOf
cljs.user=> (time (dotimes [_ 10000] (max-i-and-val [1 2 3 4 6 1])))
"Elapsed time: 42.277618 msecs"

#2017-12-0614:26Miķelis Vindavsso reduce-kv is fastest#2017-12-0614:26minikomiinteresting#2017-12-0614:26Miķelis Vindavsthe indexOf solution has to go through the list twice#2017-12-0614:27minikomi
(defn get-indexed-max [memory-state]
  (loop [idx 0
         current-max [nil -1]] ;; no values below 0
    (if-let [v (get memory-state idx)]
      (recur (inc idx)
             (if (< (second current-max) v)
               [idx v]
               current-max))
      current-max)))
here was my first attempt
#2017-12-0614:30Miķelis Vindavsmaybe if you get rid of the tuple allocations#2017-12-0614:30mfikes@mikelis.vindavs TIL. I suppose it is meant to be a stable / public part of the API: https://github.com/clojure/clojurescript/blob/3b3db232711266f9f41c94c777084664d6d0b71b/src/test/cljs/cljs/seqs_test.cljs#L131-L147#2017-12-0614:30minikomimax-idx, max-val?#2017-12-0614:31bhaumanmy straightforward solutions run in the 100 - 200ms range without perf optimizations#2017-12-0614:31bhaumanwithout#2017-12-0614:33bhauman@nooga which repo is yours?? or have you posted your answer?#2017-12-0614:34noogaNah, I type them into planck repl as I go so I have nothing to post on gh#2017-12-0614:34nooga😄#2017-12-0614:34noogahm, one sec#2017-12-0614:34bhaumanthats cool, you could gist them out!#2017-12-0614:34minikomi
console.time()
var max_idx, max_val=-1;
for (i = 0; i < 10000; i++) {
arr.forEach(function(i,v) {
  if(v > max_val) {
    max_idx = i; max_val = v;
  }
})
}
console.timeEnd()
VM750:10 default: 22.593017578125ms
#2017-12-0614:35minikomimake of that what you will 😜#2017-12-0614:35noogahttps://repl.it/repls/AwareOutgoingWolverine but really, it’s nothing special imo#2017-12-0614:36bhaumanyeah but its still good to see 🙂 thanks for posting it#2017-12-0614:36bhaumanI think we could make an entire clojure workshop based around this type of stuff#2017-12-0614:36noogaI don’t put much energy into this 😄#2017-12-0614:37noogaYeah, a friend of mine is learning clojure at the moment and I got him to solve AoC#2017-12-0614:37bhaumanI like it because I get to do something that is simply for enjoyment#2017-12-0614:37bhaumanperfect!#2017-12-0614:37noogamuch better than hackerrank problems IMO#2017-12-0614:38Miķelis Vindavs
(defn loop-nth [xs]
  (let [size (count xs)]
    (loop [i 0
           maxi 0
           m 0]
      (if (< i size)
        (let [v (nth xs i)]
          (if (> v m)
            (recur (inc i) i v)
            (recur (inc i) maxi m)))
        [maxi m]))))
is some 10% faster than reduce-kv
#2017-12-0614:39mfikesNice solutions @bhauman. Thanks for sharing!#2017-12-0614:43mfikesAFAICT .indexOf and .lastIndexOf are so useful, that they were made to work in ClojureScript#2017-12-0614:44bhaumanoh cool! i didn't know this#2017-12-0614:45mfikesEven crazy construct like (.indexOf (sequence (map inc) '(0 1 2 3 4)) 5) work in Clojure and ClojureScript#2017-12-0614:46bhaumanvery very cool and good to know#2017-12-0614:46mfikesI wonder if these test imply that they are stable / public https://github.com/clojure/clojurescript/blob/3b3db232711266f9f41c94c777084664d6d0b71b/src/test/cljs/cljs/seqs_test.cljs#L131-L168#2017-12-0614:48mfikesIf that's true, index-of and last-index-of could be things. :thinking_face:#2017-12-0614:52bhaumanwell I can't wait for the next episode of AOC#2017-12-0614:52noogacould be#2017-12-0614:53noogaI was suprized when .indexOf worked both in clj and cljs#2017-12-0614:54mfikesThanks for the tip @mikelis.vindavs, I've incorporated it https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_06.cljc#2017-12-0614:57mfikesI was surprised that (merge-with + [0 1] {0 7 1 2}) produced a vector. I used it without thinking but then checked afterwards that this is true.#2017-12-0614:57mfikesPerhaps I'm violating the expectations of merge-with, TBH, looking at its docstring.#2017-12-0615:04borkdude@mikelis.vindavs I looked at reduce-kv but this won’t work: (first-max-pos' [-1 -2 -5]), so I stayed with the current#2017-12-0615:05Miķelis Vindavsthe inputs are always positive#2017-12-0615:05borkdude@mikelis.vindavs oh. well, then it works, but only for this puzzle 😉#2017-12-0615:05Miķelis Vindavsbut it could be made to work with negative ones by providing a different initial value#2017-12-0615:12borkdude@bhauman I didn’t think of perf optimizations when I wrote mine, but ended up at 63 ms (on JVM that is). Now let’s see if I understand yours.#2017-12-0615:14borkdudeah, so it’s incrementing one by one#2017-12-0615:18mfikesHah, I could see another variation on this, where all solutions are submitted to a server which benchmarks and ranks them.#2017-12-0615:20mfikesIt seems you can optimize roughly for 3 things: 1. Get it done ASAP so you can get points 2. Write it elegantly so it is mantainable 3. Optimize the crap out of it#2017-12-0615:21borkdudeAdded some printlns to @bhauman’s solution because I had trouble seeing what was going on, but now I get it:
start: [0 2 7 0]

acc i [0 2 0 0] 3
acc i [0 2 0 1] 0
acc i [1 2 0 1] 1
acc i [1 3 0 1] 2
acc i [1 3 1 1] 3
acc i [1 3 1 2] 0
acc i [2 3 1 2] 1
Clever, so it will loop 7 times updating each index by one, starting from the index after the max value
#2017-12-0615:22borkdudeIn my solution I maintained the invariant that the sum of elements should always remain constant, because I had a bug in it that increased the sum#2017-12-0615:23bhaumanthat merge-with behavior is unexpected#2017-12-0615:25bhauman@borkdude my redistribute version just duplicates the process specified#2017-12-0615:26bhaumannot much different than a loop, oh and I got it down to 93ms with transients but I don't see that as worth it#2017-12-0615:28borkdude@bhauman Just for fun, I moved the (count …) to a let bound name, but it becomes slower, not faster … 🙂#2017-12-0615:29bhaumanyeah didn't expect much from that as count is a constant time look up#2017-12-0615:29borkdudeProbably it’s a neglectable thing and just co-incidence#2017-12-0615:30bhaumanyeah thats likely#2017-12-0615:31bhaumanalthough, moving the count to a let probably makes the alg more clear#2017-12-0615:31borkdudecool, with find-max-pos the bhauman solution is even faster than mine: 56 ms#2017-12-0615:32mfikes@bhauman Yeah, I've concluded it only accidentally works:
(merge-with (fn [_ x] x) [0 3] {0 7 1 2} {0 3 2 32})
and
(merge [0 3] {0 7 1 2} {0 3 2 32})
don't produce the same result.
#2017-12-0615:33Miķelis Vindavscan someone explain this to me? I don’t really get it#2017-12-0615:34bhauman@mfikes is this because merge-with is exploiting a more general interface like get and assoc on the first collection?#2017-12-0615:34bhaumanyeah thats probably why#2017-12-0615:35mfikesYeah, but it is an abuse to rely on it.#2017-12-0615:35mfikesI'm going to see if I can fix my solution.#2017-12-0615:35Miķelis Vindavsah it’s just treating it as an associative collection, just like (assoc [:a :b :c] 1 :x) works#2017-12-0615:37Miķelis Vindavsinteresting that (merge-with + [10 11 12 13] [100 101 102 103]) doesn’t work but (merge-with + [10 11 12 13] {0 100 1 101 2 102 3 103}) does#2017-12-0615:38Miķelis Vindavswhen dynamic typing and implementation details meet#2017-12-0615:50mfikesWell, since I want to treat the memory banks as associative and have it work with merge-with, I'm going to use maps instead of vectors.#2017-12-0616:01bhaumanthat'll do it#2017-12-0621:00borkdudeFound a slight variation on bhauman’s next-state:
(defn redistribute [block]
  (let [[position max-val] (first-max-pos block)
        length (count block)]
    (reduce (fn [block [p v]]
              (update block p
                      + v))
            (assoc block position 0)
            (->> (range (inc position)
                        (+ (inc position) max-val))
                 (map #(mod % length))
                 frequencies))))
#2017-12-0622:43mfikesHah, I recognize this approach 🙂#2017-12-0622:47mfikesThis was where the desire to use (merge-with + on a vector came from. (To avoid an explicit reduce.)#2017-12-0621:06borkdudeThe original bhauman version is twice as fast though! Provided that you use first-max-pos.. 40 ms now on my machine#2017-12-0621:17borkdudeAh, I see mfikes’ solution now, also used frequencies.#2017-12-0621:25Miķelis VindavsIt’s an interesting solution with frequencies, but if focusing on perf, isn’t generating a whole sequence just to squash it down kinda slow vs just adding (quot n-to-distribute num-banks) and then figuring out where to put the rest ?#2017-12-0621:26Miķelis Vindavsit’s rather elegant though#2017-12-0621:39grzmwow. @bhauman’s is really nice and terse, and a good example of using reduce to avoid a loop.#2017-12-0622:12borkdude@grzm I agree#2017-12-0622:52mfikesYeah, his solution is close to what I would consider "art" 🙂#2017-12-0622:54bhaumangeez guys#2017-12-0622:54bhaumanthanks#2017-12-0702:42minikomiNever really used reduced before.. useful!#2017-12-0703:40minikomihow about (drop max-idx (take (+ max-val max-idx) (cycle (range memory-length))))#2017-12-0703:45mfikesCool. Nice way to avoid mod 🙂#2017-12-0703:59cjmurphy@minikomi Yes (cycle (range num-memory-banks)) is better than (mapcat identity (repeat (range num-memory-banks))). Now that I know about cycle I won't have to coerce it from other functions. Thanks @mfikes 🙂#2017-12-0704:05mfikescycle can also be useful in the day 1 problem, where the problem definition indicates "The list is circular"#2017-12-0704:38minikomiGot a banana and my cup of tea. Ready.#2017-12-0705:10grzmdone yet?#2017-12-0705:10minikominope lol#2017-12-0705:11grzmI'm about to start#2017-12-0705:11grzmno pressure 🙂#2017-12-0705:16minikomioops.. emacs locked up when i pasted in the input lol#2017-12-0705:17minikomiI think all the parenthesis messed with it#2017-12-0705:55minikomistuck on part 2 😕#2017-12-0706:01minikomiGetting the "right" answer for the test input, but being denied on my actual input#2017-12-0706:32grzmcrikey#2017-12-0706:34dyankowskyit's a good one#2017-12-0706:35grzmyeah, I need practice with trees 🙂#2017-12-0706:36dyankowskyI managed to get the correct solution partially "by hand", now I'm going back to finish the code#2017-12-0706:36dyankowskyto part2 that is#2017-12-0706:39minikomigot it but ... but what a mess lol#2017-12-0706:46minikomi"Elapsed time: 3.052496 msecs" ... quick though#2017-12-0706:53dyankowskyheh, mine's about 3x slower#2017-12-0706:53dyankowskybut I'm OK with that#2017-12-0706:53minikomiah, input probably different haha#2017-12-0706:53dyankowskygood point#2017-12-0706:53minikomican you send me your input private message?#2017-12-0706:53minikomii'll give it a whirl#2017-12-0706:54dyankowskyhttps://bitbucket.org/balefrost/adventofcode2017/src/b2cef87b589ce1c94998afc5aeefe9b95da164a3/resources/day7_input.txt?at=master&amp;fileviewer=file-view-default#2017-12-0706:54minikomialso works 😜#2017-12-0707:28grzmokay. I think I'm going for the most baroque solution#2017-12-0708:29val_waeselynckToday's problem with DataScript + ex-info: https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day07.clj#2017-12-0708:36minikomiooh nice!#2017-12-0708:38borkdudeSolved the problem, but have to clean up the code. Also used ex-info 🙂#2017-12-0708:38minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day7.clj here's my loop-de-loop solution#2017-12-0708:57minikomiI bet there's a good way to use some kind of walk here#2017-12-0709:23minikomiah -- tree-seq was what i wanted#2017-12-0710:25borkdudeFWIW, my code for day 7: https://github.com/borkdude/aoc2017/blob/master/src/day7.clj#2017-12-0710:25minikomiI discovered tree-seq and went crazy with it on my refactor hahaha#2017-12-0710:27borkdudeTo keep it sustainable, I’ll try not to think about this puzzle and to tweak things all day 😉#2017-12-0710:28minikomiyeah, you know how it is when you find a new tool though 😉#2017-12-0710:29borkduderight 😉#2017-12-0711:46orestisI had a very bad night sleep so I solved part 2 almost by hand.#2017-12-0711:47orestisThis is one I would like to go back to and see how trees work in clojure!#2017-12-0711:56noogathis is mine: https://repl.it/repls/KaleidoscopicOrangeTragopan#2017-12-0711:57noogait’s ugly and I forgot about tree-seq existence#2017-12-0711:57noogabut it seems to work 😄#2017-12-0713:03noogamy goal with these is to arrive at the solution asap, without too much tinkering with performance and algorithmic elegance#2017-12-0713:23thegeezWell that was the first actual challenge of this years calendar for me#2017-12-0713:24val_waeselynckGetting to try some libs that make it easy to solve the problems can be a good value add too. Working on last year's problems, I've been able to use Clara Rules for example#2017-12-0713:27thegeezLooking through your datascript solution now, never applied datascript or datomic to any advent problems yet#2017-12-0713:29val_waeselynckFrankly, for this problem, DataScript turned out to be more overkill than I hoped.#2017-12-0713:29val_waeselynckstill, quite comfortable for representing graphs.#2017-12-0714:18borkdudeI thought I would need a delay construction like with 2015's day 7, but this problem didn’t require it because of the regularity in the graph#2017-12-0714:26borkdudenice viz of today: http://raevnos.pennmush.org/images/day07.svg#2017-12-0714:39borkdudeFun useless fact: both part 1 and 2 run at about 6.8 ms (using criterium)#2017-12-0802:18minikomiGetting under 2ms for part 2 with your input on my loop/recur solution.. tree-seq solution turns out to be slower at ~14ms.. guess we can stop early once an unbalanced branch has a balanced set of children.#2017-12-0714:43borkdudeAll you needed to parse this one was clojure.edn/read-string and destructuring (SPOILER in thread) 🙂#2017-12-0714:45borkdude
[[name [weight]
    & [arrow & names]]]
#2017-12-0714:46borkdudeI like what thegeez did with the underscore for the arrow, to emphasize this is just a separator#2017-12-0714:57mfikesMy day 7 solutions are up https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_07.cljc#2017-12-0715:00mfikesNice parsing approach @borkdude I like it!#2017-12-0715:01borkdude@mfikes Ah, set/mapinvert and oh yes, .indexOf#2017-12-0715:02borkdude@mfikes Nice solution again!#2017-12-0715:03mfikesI too had difficulty with part 2, trying perhaps 3 incorrect solutions until I figured out what was needed. And I did that part by hand, and backfilled the code 🙂#2017-12-0715:04borkdudeThis year my extra challenge is to finish before coffee, so I wasn’t too concerned of making it the most beautiful#2017-12-0715:05Miķelis Vindavshas anyone tried an approach with inverting the whole tree?#2017-12-0715:05borkdudeI don’t know about inverting the whole tree, but I keep a map of name -> ancestors and I’ve inverted that one in the second part#2017-12-0715:05Miķelis Vindavsin part 1 i iteratively pruned off all leaves and references to them until only the root is left#2017-12-0715:06Miķelis Vindavsright, well that’s essentially inverting it i guess#2017-12-0715:06borkdudein part 1 I simply found the name without any ancestors#2017-12-0715:06Miķelis Vindavsthat’s simpler#2017-12-0715:06borkdudeset/difference as mfikes did#2017-12-0715:06Miķelis Vindavsdidn’t think of that#2017-12-0715:07Miķelis Vindavsthe puzzles publish at 7am local time 😅#2017-12-0715:07borkdudelocal time, really?#2017-12-0715:07Miķelis Vindavsfor me part 2 is an ugly solution with println which kinda works like throw in some of the other solutions#2017-12-0715:07Miķelis Vindavsi rewrote it to use reduced but it’s uglier than the throw variant#2017-12-0715:07borkdudeyeah, exceptions really helped me too 😉#2017-12-0715:07borkdudeex-data ftw#2017-12-0715:08Miķelis Vindavssometimes that’s really nice for an early return#2017-12-0715:08mfikesFor me, I started with reduced for early return, and then went with some#2017-12-0715:08Miķelis Vindavsi’m hoping to try a solution with walk#2017-12-0715:09Miķelis Vindavscan you explain more?#2017-12-0715:09Miķelis Vindavsdid you get rid of the reduced and replaced it with some, or used both?#2017-12-0715:10Miķelis Vindavs
(let [[w tops] (get tower root)
        top-res (group-by #(find-unbalanced tower %) tops)]
    (or (some (comp #(when (reduced? %) %) first) top-res)
the problem that prevented me from an elegant solution is the fact that I need frequencies or group-by and only one of the values is reduced?
#2017-12-0715:10Miķelis Vindavsbut I haven’t spent much time trying to make it prettier#2017-12-0715:10Miķelis Vindavssince in the morning I wasted around 20 minutes because my parsing regex was using (....) for the name part since in the test input all names were 4 chars long#2017-12-0715:11Miķelis Vindavsand I thought I had an error in the solution itself which I couldn’t find… until i fixed the regex to be ([^ ]+)#2017-12-0715:12mfikesI started by reduceing over the data, but I had a nil (and ignored) accumulator, and had it stop with reduced when it found the unbalanced bit. I then took this reduce, and took the accumulator out of the reducing function, and essentially turned it into a predicate for some. Example:
(reduce (fn [_ x] (when (odd? x) (reduced x))) nil [2 4 2 7 2])
can be simplified to
(some (fn [x] (when (odd? x) x)) [2 4 2 7 2])
#2017-12-0715:16mfikesI'm curious about people using Spec to parse this one. Digging through the solutions now...#2017-12-0715:17borkdudeI found spec a bit overkill for this one#2017-12-0715:17mfikesYes, I like your destructuring#2017-12-0715:18borkdudehaha, even using the mapping from "(20)" to 20 by first 😉#2017-12-0715:18borkdudeor (nth 0) is what destructuring is using#2017-12-0715:18mfikesYes. I couldn't figure out how to get Spec to do that for me.#2017-12-0715:19borkdudeSometimes things just map co-incidentally well to edn#2017-12-0715:20mfikesHmm. A lot of silver stars right now. I wonder if that is normal for this time of day.#2017-12-0715:20borkdudeIf you have kids and have to start early at work, I can imagine this is not something you do on the bus#2017-12-0715:21mfikesYeah. Perhaps part 2 is challenging. I found the spiral more challenging.#2017-12-0715:23borkdudeI found this one more challenging, but when I found out about the squares at the bottom right, I felt really dumb#2017-12-0715:23mfikesYeah, I'm not like Gauss. I would have started adding 1, 2, 3...#2017-12-0715:26borkdudeUlam’s spiral, it’s a thing#2017-12-0715:26mfikesYep, Ulam is what immediately came to mind for me as well 🙂#2017-12-0715:27borkdudeNever heard of it before. These are not typical problems you run into in day to day coding#2017-12-0715:28borkdudeBut now I love it. Will never forget Ulam again 😛.#2017-12-0715:29mfikesDo the AoC problems get progressively more difficult over the month?#2017-12-0715:29mfikes(Like 4Clojure?)#2017-12-0715:30borkdudeI hope not. 😛#2017-12-0715:32val_waeselynck@mfikes @borkdude From what I saw in AoC 2016, they do get more difficult 😛#2017-12-0715:32mfikesI recall some of the 4Clojure problems getting into the 4-hour range near the end#2017-12-0715:32val_waeselynck(only did a subset of AoC 2016)#2017-12-0715:49mfikesInterestingly, if you look at tentamen's part 2 solution (https://github.com/tentamen/adventofcode/blob/master/src/adventofcode2017/day7.clj), you can see that the input resulted in the unbalanced node being at the root of the tree, and if you are lucky with such a data set, you can skip some coding. (If I try that code on my input, it exhausts the stack somewhere in it)#2017-12-0715:52val_waeselynckSince we've been talking a lot about performance lately: I've been working on problem 23 of AoC 2016, in which performance ends up being rather critical. (The problem is to implement an interpreter about a very basic assembly that self-modifies code: https://adventofcode.com/2016/day/23) I first did a "Clojure-idiomatic" solution, with immutable state and multimethods (https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2016/day23.clj#L44). Then I saw it tooks at least 30min to run on part 2, and did a second version that uses more primitive Java stuff (arrays, primitive, enums): See https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2016/day23.clj#L165 and https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/java/aoc2016/Day23.java The second version turned out to be about 100 times faster (16 seconds instead of 20 minutes).#2017-12-0715:52val_waeselynckThought people might find this interesting#2017-12-0715:55mfikesYeah, @val_waeselynck it seems like this assertion might be true: "If you solve any problem with Clojure, you can come up with a succinct, maintainable, readable solution. If you need perf, there is often an order of magnitude or more available by switching to lower level constructs, and you can often get away with going down that path for the perf-critical portion of your code."#2017-12-0715:57mfikesOne a large project I was on recently (where overall perf was critical), it felt like 80–90% of the code could be Clojure, and the rest could still be "Clojure", but really Java in disguise.#2017-12-0715:58mfikesI think this assertion is true for the ClojureScript compiler, in a sense. Most of it is normal code, but the hot spots have been optimized in ways that deviate from "normal"#2017-12-0715:59val_waeselynckHowever, I saw Martin Odersky say in a talk that a compiler typically has no hot spots - but that may be more true of compilers that have to do a fair amount of static inference#2017-12-0716:01mfikesHmm. Very odd. The ClojureScript compiler seems like any other program to me. It has bits that are very hot compared to others. Martin is a genius so perhaps I'll dig up that talk.#2017-12-0716:03val_waeselynckI think it was this one https://www.youtube.com/watch?v=WxyyJyB_Ssc#2017-12-0715:58val_waeselynck@mfikes Totally agree with that. It should also be noted that even if I had started with the Java thing, it would have taken me more time overall to debug it and run it, given the time it took me to debug it 🙂 (granted, that may be because my Java is a little rusty)#2017-12-0715:59mfikesAlso, lots of the highly-performant and desirable algorithms that were invented in the 60s and 70s heavily rely on mutation. Perhaps that caused a lot of what I saw when working on the large project.#2017-12-0715:59mfikes(Literature is thin on functional algorithms.)#2017-12-0716:01val_waeselynck@mfikes I would argue SQL query engines are examples of highly-performant functional algorithms - i.e they yields highly performant programs that manipulate only immutable values#2017-12-0716:01mfikesGood point. I wonder if they are functional on the outside but inside it is like "transient city"#2017-12-0716:02val_waeselynckI believe they totally are transient inside - but it's a good testimony that being declarative makes a lot of room for global optimizations#2017-12-0716:02val_waeselynckThe virtual DOM is another such example#2017-12-0716:02mfikesThis entire subject is, of course, important. If it weren't for the availability of these tradeoffs, you really couldn't use Clojure for a large class of problems.#2017-12-0716:04mfikesIn other words, if you buy into using Clojure, I think you have to accept that for parts of your program, you can't insist on the ideal Clojure approach. (Unless your problem has no perf aspects, of course.)#2017-12-0716:04borkdude@mfikes about the input, I checked if I wasn’t just lucky with my input so I took yours: https://github.com/borkdude/aoc2017/blob/master/src/day7.clj#L111#2017-12-0716:05mfikesYeah, for tentamen you can see that part of the code has a comment showing that the root is where the unbalanced node is. Then the remainder of the code leverages that fact. Fair.#2017-12-0716:05val_waeselynck@mfikes I even find that Clojure can be a more elegant solution to some problems in the high-performance space, what with macros and the runtime compiler as zero-cost abstractions#2017-12-0716:06borkdudeyeah, or take Om vs React being faster due to immutable state#2017-12-0716:06mfikesDefinitely: Here is another effect I've seen. Since it is so damned easy to change Clojure code to do something in a different way, it is often feasible to explore different approaches and end up with a faster solution than if you were working in Java.#2017-12-0716:06mfikesIf you were in Java, you get calcified in an approach quickly.#2017-12-0716:07mfikesTime is money. If you can't explore alternatives you often have to accept the perf you have.#2017-12-0716:08val_waeselynck@mfikes Funnily, you could say that Clojure programmers are to Java Programmers what JITs interpreters are to AOT compilers: the first start very quickly and spend a little time optimizing the critical parts based on experience, the other ones start slowly and spend a lot of time speculating on what is going to be critical (and being pessimistic about it)#2017-12-0716:08mfikesThink about the extreme of programming in machine code. Once you've solved a problem, you are pretty challenged to try a different approach, no matter how fasts your machine code runs.#2017-12-0716:10mfikesThis has led to a philosophy: Develop in the highest-level programming paradigm you can find that also affords you the opportunity to delve lower when needed.#2017-12-0716:10borkdudeBreadth first#2017-12-0716:11borkdudeAlso, when correctness isn’t an issue (you want to research solutions first, handling all edge cases is not a problem) then types can get in the way a bit, where you have to be explicit when you don’t want to be#2017-12-0716:12mfikes@val_waeselynck I like your JIT to AOT analogy#2017-12-0716:12borkdudeAlso, the REPL helps a lot in this#2017-12-0716:13mfikesExactly. The fact that ClojureScript can be thought of as a compiler is the wrong way of thinking of it, IMHO. The best way to think of ClojureScript is just as a Lisp, but with a mode that can be AOT'd to produce a small artifact when you really need it.#2017-12-0716:14val_waeselynck@borkdude totally. Being able to use Criterium and Tufte on the fly helps a lot when optimizing stuff#2017-12-0716:15borkdudetufte… hmm, never used it before. @mfikes I see it’s crossplatform…#2017-12-0716:40thegeez@mikelis.vindavs I use walk for today's problem: https://github.com/thegeez/clj-advent-of-code-2017/blob/master/src/advent/day7.clj#L81#2017-12-0802:07minikomiAh, was looking for a walk/postwalk based answer 😄#2017-12-0716:58grzmThat was like slogging through mud. I posted it, only because I want to be able to look back in the future and say "Oh, my! I have improved!"#2017-12-0716:58grzmI don't even want to look at the other solutions yet. I feel like I need to keep pounding on it.#2017-12-0717:12grzmAnd speaking of datomic and databases, Vik Fearing has been solving them using postgres: https://github.com/xocolatl/advent-of-code-2017#2017-12-0718:34Miķelis VindavsI’m surprised.. for few (3) elements, maps seem faster than vectors#2017-12-0718:36Miķelis Vindavsthat is, mapping to
{:id     name
     :weight   (parse-int weight)
     :children (some-> top (str/split #", "))}))
and then indexing on :id is some 5-10% faster than doing the same with a 3-tuple and first
#2017-12-0718:43grzmAny different when using (get x 0)?#2017-12-0718:44Miķelis VindavsI’m using destructuring for both, didn’t try get or nth#2017-12-0718:44borkdude@grzm how are you profiling?#2017-12-0718:44grzmI'm not, for the most part.#2017-12-0718:45grzmI'm trying to focus on habit at a time. And in this case it's been transducers and cljc. It's too easy for me to yak shave.#2017-12-0718:45borkdude@grzm I’d be happy to throw it against criterium if you have the full snippet#2017-12-0718:47grzmIs this in reference to my "mud" comment? Or perhaps you mean @mikelis.vindavs? The performance of mine was pretty good: 78ms iirc.#2017-12-0718:47borkdudeAh sorry. I meant @mikelis.vindavs 🙂 about the 3-tuples#2017-12-0718:48Miķelis Vindavsjust (time (dotimes [_ 1000] (solve)))#2017-12-0718:48borkdudeThat may not render realistic results#2017-12-0718:49borkdudeTry with criterium and then quick-bench#2017-12-0718:49borkdudehttps://github.com/borkdude/aoc2017/blob/master/src/day7.clj#L111#2017-12-0718:48grzmAnd when I did a bit of refactoring, the mud cleaned up a bit. I don't like throwing to get a result, but that's what I ended up doing.#2017-12-0718:49borkdude@grzm Me too. I don’t see that as a problem. Could easily refactor it, but I find it a creative way of solving the problem 🙂#2017-12-0718:50Miķelis Vindavshttps://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day7.clj#2017-12-0718:50grzman application of creative destruction 😉 shows my bias with respect to throwing: I'm inclined to view it as something negative, rather than the tool it actually is.#2017-12-0718:50Miķelis VindavsI’ll try your suggestions , thanks#2017-12-0718:51borkdudeDetecting an error is fine with throw/catch and that was what the puzzle was about 😉#2017-12-0718:52grzmTrue!#2017-12-0718:52grzmAlso think I applied destructuring as deeply as I ever have: https://github.com/grzm/advent-of-cljc/blob/master/src/main/com/grzm/advent_of_code/advent_2017/day_07/part_2.cljc#L17#2017-12-0718:54borkdudeHow do you know the common-weight is in the first spot there?#2017-12-0718:55grzmI'm grouping by the tree weight, so the keys are the weights. Given the constraints of the problem, I know there's only going to be one that's an odd tree weight, so everything else is going to have the same tree weight. Then the sort-by transforms the map into a sequence of two vectors, odd-tree-weight first.#2017-12-0718:58grzmIt's kind of obscured by the destructuring, but that let only has a single binding in it.#2017-12-0718:59borkdudeah, missed that, I thought it was the argument to the function… getting tired 😉#2017-12-0718:59grzmWhere are you at?#2017-12-0719:00grzmI'm in the US midwest.#2017-12-0719:00borkdudeEurope, Netherlands#2017-12-0719:01grzmI've been staying up and starting AoC at 11PM my time. Not the best to start working on a puzzle, especially ones like this one. Lots of little mistakes getting in the way of getting to the solution.#2017-12-0719:02grzmAnyway, thanks for your evangelism wrt AoC! It's made it more enjoyable for me.#2017-12-0719:02borkdude🙂#2017-12-0718:54grzmThree levels deep. Once you're there it's revealing a pretty specific solution, but it's cool that destructuring works so robustly.#2017-12-0718:58mfikes@mikelis.vindavs I was a little surprised as well when I changed my solution for yesterday to represent banks of memory as integer-indexed maps instead of vectors, and it ran slightly faster. I did not make this change for perf reasons, but so that the code would be correct when using (merge-with + ,,,) Here is the revision I'm talking about if curious : https://github.com/mfikes/advent-of-code/commit/9a178036eeb2c39b168712fed3388007217933ea#2017-12-0718:59Miķelis Vindavsbenchmarked with criterium, same thing — the difference is small, but still there#2017-12-0719:00Miķelis Vindavsbut what’s even more interesting that maps vs vectors is the fact that for the 1st part of the problem#2017-12-0719:00Miķelis Vindavsa set difference approach is slower than an iterative pruning one#2017-12-0719:01Miķelis Vindavsthat is, https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day7.clj#L25-L48 is faster than https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day7.clj#L77-L82#2017-12-0719:01Miķelis VindavsI can’t wrap my head around why that would be true. Is set/difference slow?#2017-12-0719:02mfikesWe may actually be seeing completely different effects, since mine is in ClojureScript. (I don't know JavaScript that well, but it seems like arrays are integer-indexed maps in a sense anyway, at least until the optimizer does something about them.)#2017-12-0719:03mfikesI've never heard anyone suggesting that set/difference should be avoided for perf reasons.#2017-12-0719:05Miķelis Vindavsthe difference is pretty small, but in the other approach, I’m iteratively - removing nodes that have no children (`filter + into {}`) - removing references to those nodes (`map + filter + into {}`) until there’s only 1 entry left which seems like a ton more work than 2 map + set difference#2017-12-0719:06Miķelis Vindavsis there a way to load a leiningen project in cljs? i have planck installed but am not very familiar with it#2017-12-0719:06Miķelis Vindavsalso I suppose io/resource isn’t implemented in cljs#2017-12-0719:07mfikes@mikelis.vindavs You can run lein classpath to spit out a classpath, and Planck -c to take a classpath#2017-12-0719:08mfikesPlanck has a namespace that defines resource. I've been using it: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_05.cljc#L7#2017-12-0719:10mfikesTo be honest lein classpath dumps out a lot of stuff you may not need, so I often manually specify the classpath, and there is -D sugar that Planck and Lumo have to expand to existing deps in your local Maven repo: http://planck-repl.org/dependencies.html#2017-12-0719:10Miķelis Vindavsthanks, I’ll try that#2017-12-0719:11mfikesYeah, just take a peek at my repo https://github.com/mfikes/advent-of-code to see how I have it set up to run both Planck and Clojure with one source tree.
#2017-12-0719:27borkdudePureScript solution: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day7.purs#2017-12-0719:27mfikesWow. Hefty import list. Wonder if that is normal in PureScript.#2017-12-0719:28mfikesMost of my Clojure solution namespaces are about the same size as that import list#2017-12-0719:28borkdude
_total = _Newtype <<< prop (SProxy :: SProxy "total")
 let childrensTotals = split.right ^.. traversed <<< _total
lenses…
#2017-12-0719:32mfikesI Like how Kris came to the same spot where the last bit of code wasn't necessary (you could do the last bit by hand faster than writing the code for it)#2017-12-0719:33borkdudeYeah, but I want my part-2 function to always give the answer.. it’s part of my implicit contract#2017-12-0719:33borkdudeMaybe I have to write a protocol for it 😉#2017-12-0719:41borkdudeWhat’s a better way for this:
(defn find-by-val
  [m v]
  (ffirst
   (filter (fn [[k v’]]
             (= v v’))
           m)))
#2017-12-0719:41borkdudeCould have used map-invert, but you’re never sure if the map has duplicate values#2017-12-0720:00mfikes@borkdude If you want early termination and nil is not a concern, this seems to read nicely
(defn find-by-val
  [m v]
  (some (fn [[k v']]
          (when (= v v')
            k))
    m))
#2017-12-0720:03Miķelis VindavsI’m using
(defn find-where [pred coll]
  (some #(when (pred %) %) coll))
#2017-12-0720:03mfikesHmm. Maybe they both produce the same result, even with nil in the map as key or value#2017-12-0720:04Miķelis Vindavsahh but that’s sequences not maps#2017-12-0720:29borkdudefirst + filter is also early termination, but yeah, some is also nice#2017-12-0720:30Miķelis Vindavsit’s unfortunate this isn’t in core#2017-12-0720:40borkdudeI tried .indexOf but this time it didn’t work 😜#2017-12-0720:55borkdudeNope, lein findfn "{:a 1}" 1 :a, nothing 😉#2017-12-0721:08mfikesAhh, right yeah ffirst / filter is indeed lazy#2017-12-0721:08grzm@mfikes I was there, too (with you and Kris). I had a prn stuck in my recursive search function which printed out the unbalanced nodes. Did that by hand, then went back and finished the code.#2017-12-0721:09grzmMakes me think there's something getting in the way of me using the machine to explore the problem space. Either practice, or tooling.#2017-12-0721:10grzmOr technique (which is coupled with practice)#2017-12-0721:10bhaumanbusy day finally got my pushed: https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day07.clj#2017-12-0721:11bhaumannow to read the chat log and see whats up ...#2017-12-0721:13borkdude@bhauman Creative, rand-nth, just start at some random node in the tree: https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day07.clj#L30#2017-12-0721:14borkdude(time (part-2 data)) 1864, is that milliseconds — or probably the solution 🙂#2017-12-0721:15bhaumanyeah the solution#2017-12-0721:16bhauman@borkdude our data setup is spooky similar#2017-12-0721:20chrisblomok, enough yak shaving for today: https://github.com/ChrisBlom/advent-of-code/blob/master/src/adventofcode/2017/day07.clj#L54-L84#2017-12-0721:35mfikes@chrisblom Ahh, you got away with calling set/difference with a non-set smaller 2nd argument. For example this works (set/difference #{:a :b :c} [:a :b]) while this doesn't (set/difference #{:a :b :c} [:a :b :c :d :e])#2017-12-0721:38chrisblomow, thats nasty#2017-12-0721:40chrisblompretend you did not see that#2017-12-0721:40mfikesHah. I can't unsee it.#2017-12-0721:43chrisblomi forgot how wonky clojure.set functions are for a moment#2017-12-0721:47borkdude@bhauman indeed, great minds alike 😜#2017-12-0721:48Miķelis Vindavsthat’s a beautiful solution!#2017-12-0721:49Miķelis Vindavsbut does it assume that the weight will always need to be adjusted up?#2017-12-0722:04chrisblomfixed it: https://github.com/ChrisBlom/advent-of-code/commit/88bfa7a17e674ddeb3eeeeec84889c3a0c8b30b0#2017-12-0806:29Miķelis Vindavsstill pretty nice & readable#2017-12-0721:51chrisblomhmm, yeah, thought that was ok, but on second thought its probably not#2017-12-0721:52chrisblomjust got lucky with my input#2017-12-0721:54Miķelis VindavsI found that getting the “odd one out” was surprisingly complicated#2017-12-0721:55borkdudeYeah. This is mine, but I’m sure there are other solutions:
(defn unbalanced-balanced
  [vals]
  (->> (frequencies vals)
       (group-by val)
       sort
       (map #(second %))
       (map #(ffirst %))))
#2017-12-0721:59mfikesI went with a construct like
((set/map-invert (frequencies [2 2 17 2])) 1)
#2017-12-0721:59borkdudeI wanted both numbers in fixed order#2017-12-0722:01mfikesYeah, I needed both as well, went with (.indexOf [2 2 17 2] 17) for the second bit#2017-12-0722:03grzm.indexOf is something I don't often reach for. I take it it's available in cljs?#2017-12-0722:04mfikes@grzm Yes, but attempting to formally address that with this proposed page https://github.com/mfikes/clojurescript-site/blob/c552daa145ce7005446fa315f042d82ddc4d51f8/content/reference/javascript-api.adoc#2017-12-0722:04borkdudeActually this works too:
(defn unbalanced-balanced
  [[a b c]]
  (if (= a b)
        [c a]
        [a b]))
#2017-12-0722:04borkdudemuch simpler 🙂#2017-12-0722:05grzmThat is nice#2017-12-0722:05mfikesBut what if you call it like (unbalanced-balanced [2 2 2 2 17 2])#2017-12-0722:06borkdudeah crap#2017-12-0722:07mfikesI think we do know there are at least 3 items, because if there were 2 it would violate the constraint that "exactly one program is the wrong weight."#2017-12-0722:08borkdudeyeah, that was my thought too#2017-12-0722:08mfikesMaybe something like the triplet comparison can yield an answer though.#2017-12-0722:08mfikesMaybe a recursive version of that somehow?#2017-12-0722:08borkdudeMaybe partition and then moving over those#2017-12-0722:15mfikesThis might be correct
(let [[a b :as all] (sort [2 2 17 2])]
  (if (= a b)
    (last all)
    a))
#2017-12-0722:17mfikes^ Inspired by @borkdude’s comparison#2017-12-0722:18borkdudeSomewhat ugly but fast:
(defn unbalanced-balanced
  [[a b c & nums]]
  (let [[balanced maybe-unbalanced]
        (cond (= a b) [a c]
              (= a c) [a b]
              (= b c) [b a])]
    [(some #(when (not= balanced %) %)
           (cons maybe-unbalanced nums))
     balanced]))
#2017-12-0722:18mfikesNice#2017-12-0722:20borkdudeIn fact, in the third condition, we know for sure that a is the unbalanced one, but I didn’t want to write a special case for that#2017-12-0722:23mfikesThe computational complexity of this game https://www.youtube.com/watch?v=Sm-zWDaoCtI#2017-12-0722:28borkdudeAnother version, more optimized:
(defn unbalanced-balanced
  [[a b c & nums]]
  (let [find-other (fn [v nums]
                     (some #(when (not= v %) %)
                           nums))]
    (cond (= a b) [a (find-other a (cons c nums))]
          (= a c) [a (find-other a (cons b nums))]
          (= b c) [b a])))
#2017-12-0722:29borkdudeSomething is wrong maybe, because I don’t get the right output#2017-12-0722:31borkdudeoh yes, wrong order of returned numbers, but apart from that it should work#2017-12-0722:33borkdudeanyway, in theory this should be faster, but in reality, I get 7 ms instead of 6 ms… this is BS 🙂#2017-12-0722:34borkdudemoving the function to its own defn works#2017-12-0722:42borkdudeFinal call for “the odd one out”:
(defn unbalanced-balanced
  [[a b c & nums]]
  (cond (= a b) [(some
                  #(when (not= a %) %)
                  (conj nums c))
                 a]
        (= a c) [b a]
        :else   [a b]))
#2017-12-0801:50fellshardI should've done part B more by hand, yeah. Automating it is a bit clumsy.#2017-12-0801:55minikomiwow, so much to unpack#2017-12-0801:57minikomimy strategy for finding the relevant node in part b was: * (ab)use tree-seq recursively to get a list of every nodes "tallied" weight - the weight it holds * group-by parent * filter for unbalanced groupings * get the one with the lowest tally (will be deepest in the tree)#2017-12-0802:00minikomipart 1 was simply "the node which supports, but isn't supported" -- i.e. (first (filter set-of-supportees supporters))#2017-12-0802:18minikomihmm tokyo timezone is good for getting the new questions when they come out, but not so great for discussion 😕#2017-12-0802:20bhaumandarn I forgot about tree-seq#2017-12-0802:22minikomiit's such a good swiss-army-knife of a function#2017-12-0803:06minikomiI was inspired to write my first macro.. it's a let which you can drop *stop* into and it will throw an exception with the bindings up until that point as data https://gist.github.com/minikomi/b6e5a097970513934faf46f01f194725 when solving these problems I often have a long let within a function which somehow goes wrong..#2017-12-0804:57fellshardknuckle-crack Places, everyone! REPLs at the ready!#2017-12-0805:24fellshardMan. I love reductions#2017-12-0805:26dyankowskyyep#2017-12-0805:26fellshardAlso, seems I'll need to dredge up my interpreter macros from last year...#2017-12-0805:26dyankowskywhat kinds of stuff did you have?#2017-12-0805:26fellshardNot sure if I ever finished them tbh xD#2017-12-0805:27fellshardIt was basically a way to write functions that could be partially applied at fixed points#2017-12-0805:28fellshardhttps://github.com/armstnp/advent-of-code-2016/blob/master/src/advent_of_code_2016/day8.clj#L45-L49#2017-12-0805:28dyankowskyah, I see#2017-12-0805:28fellshardSo I can bind the parts of the operation I know at read-time, and then hand it the remaining context at execute-time#2017-12-0805:28fellshardSince that's a recurring pattern for these assembly-read type problems#2017-12-0805:29dyankowskythis is both the blessing and curse of Lisps#2017-12-0805:29dyankowskyyou can make your own syntax!#2017-12-0805:29fellshard😅#2017-12-0805:29dyankowskyyou can make your own syntax...#2017-12-0805:29dyankowsky(well, not syntax per se)#2017-12-0805:29fellshardConstructs#2017-12-0805:29dyankowskysure#2017-12-0805:30fellshardIn these cases, I found it easier than having to let-bind around an anonymous function#2017-12-0805:30dyankowskyoh sure#2017-12-0805:32dyankowskyone problem that I have is that, since I don't use clojure that much, I'm not savvy to all the clever things that I could do with builtins, so I worry that I sometimes rebuild things that already exist#2017-12-0805:33dyankowskyfor example, I don't know if Clojure has any partial application support short of reader function literals#2017-12-0805:33fellshardDef. poke around the solutions here, you'll learn a lot of new functions that way, and how they're commonly (and sometimes uncommonly) leveraged. 4clojure used to be great for that, but I think it's down nowadays...#2017-12-0805:33fellshardhttps://clojuredocs.org/clojure.core/partial#2017-12-0805:35fellshardIt's not common, I think, from what I've seen...#2017-12-0805:36fellshardPartly because for small arities, it's just quicker to use #(f bound-param %1 %2), or something like#2017-12-0805:37dyankowskyI'll stick that one in my toolbox#2017-12-0805:37dyankowskybut now I think it's bed time#2017-12-0805:37dyankowskytake care#2017-12-0805:37minikomigoodnight 🙂#2017-12-0805:41minikomiah reductions is amazing haha#2017-12-0805:46minikominot so remarkable today#2017-12-0805:51fellshardIt may be repetitive, but I really do end up getting into these micro-interpreter type problems >_>#2017-12-0805:51fellshardMaybe partially because Lisps are just so snappy at handling them#2017-12-0805:57Miķelis Vindavshah, I had heard in passing about reductions but didn’t know it’s called that. I searched for scan, didn’t find it so wrote my own#2017-12-0805:59fellshard😄#2017-12-0805:59fellshardWhen a lot of these problems move from 'find the answer' to 'tell me something about the state along the way', reductions usually shows up#2017-12-0806:00fellshardSo it also usually pays to build your solution as a reduction when feasible#2017-12-0806:00Miķelis Vindavsnot a fan of the first element behavior though
(reductions str [1 2 3])
=> (1 "12" "123")
#2017-12-0806:00fellshardSame as reduce, really#2017-12-0806:00fellshardoh wait#2017-12-0806:01fellshardNo, yeah. Reduce always takes the first element as it stands if you don't provide a default#2017-12-0806:01Miķelis Vindavswell, there’s always (drop 1)#2017-12-0806:02fellshardd'oh#2017-12-0806:02fellshardThat was delayed, probably a lambda spinning up#2017-12-0806:05Miķelis Vindavslazy evaluation#2017-12-0806:08grzm@mikelis.vindavs that's maybe a little much only an hour after it dropped#2017-12-0806:08Miķelis Vindavsgood point#2017-12-0806:08grzmthanks 🙂#2017-12-0806:08Miķelis Vindavssorry#2017-12-0806:08Miķelis VindavsI kind of assumed this is a spoiler-alert zone#2017-12-0806:09grzmYeah, I know what you mean. I'd give it at least another couple of hours. Or perhaps just point people to your repo. Then they know what they're in for.#2017-12-0806:10Miķelis Vindavsit’s just general bikeshedding, I should probably get to work instead 😅#2017-12-0806:11grzmhttps://github.com/grzm/advent-of-cljc/blob/master/src/main/com/grzm/advent_of_code/advent_2017/day_08/core.cljc#L6#2017-12-0806:11grzmFWIW, I chose a third way 🙂#2017-12-0806:12Miķelis VindavsI was trying to save lines by trusting input https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day8.clj#L15-L24#2017-12-0806:15grzmNice. I like how you documented the lines. I've been getting lazier as the days have been getting on. I'll clean it up in the morning. Time for sleep for me.#2017-12-0806:18grzmoh, and how you reversed threading directions. That's one I'll have to keep in mind.#2017-12-0806:20Miķelis Vindavsyou mean with ->> inside of ->?#2017-12-0806:21Miķelis Vindavsit’s neat, I only wish it worked the other way. the workaround there is to create a lambda
(->> {}
     (#(assoc % :x :y)))
#2017-12-0806:21minikomior use as->#2017-12-0806:21Miķelis VindavsI never know what to use for the name#2017-12-0806:21minikomilove me some as->#2017-12-0806:22minikomiI tend to go with $#2017-12-0806:22Miķelis Vindavsthat’s a good choice, stands out.#2017-12-0806:23Miķelis VindavsI’m loving this channel and the community so far!#2017-12-0806:23minikomicould go with an emoji 😆#2017-12-0807:39fellshardas-> is new to me! Much nicer to pick up than the magic wand / swiss arrows for most things, I bet#2017-12-0807:58borkdudeToday was ok. I found the answer for part 2 while trying to find part 1 it turned out 😉. 5 ms performance.#2017-12-0808:15borkdudeI have a security breach in there though 🙂#2017-12-0808:44borkdude(fixed the security breach)#2017-12-0808:44val_waeselynckPosted my solutions to day 8. Highlights: cond->, case, reductions. https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day08.clj#2017-12-0808:45borkdudeHere’s mine: https://github.com/borkdude/aoc2017/blob/master/src/day8.clj#2017-12-0808:47val_waeselynck@borkdude I find it intriguing that you used clojure.core/== instead of clojure.core/=, what's the rationale?#2017-12-0808:48borkdudeNot needed, just to confuse new people 😉#2017-12-0808:45minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day8.clj#2017-12-0808:47minikomijust using resolve 👐#2017-12-0808:49borkdude@minikomi I had that too, but figured that when I would run someone elses input, bad things may happen on my machine: https://github.com/borkdude/aoc2017/commit/113de2ba459997544a6376a9944db41472d75bd6#2017-12-0808:49minikomiyeah, i live on the edge#2017-12-0808:51borkdudea dec -511 if fs/wipe-harddisk-if-odd >= -4#2017-12-0808:51minikomiheh#2017-12-0808:52minikomi@val_waeselynck mapcat vals - good one#2017-12-0808:52minikomii need to use mapcat more, always miss it#2017-12-0809:04val_waeselynckI noticed most people don't initialize the registers to 0, but this could lead to subtle bugs if all the registers that were updated end up being negative, and some of them are untouched you may end up with the wrong result (the right result being 0).#2017-12-0809:07minikomiooh interesting edge case.#2017-12-0809:19borkdudetrue: lucky by input 🙂#2017-12-0809:20minikomi(update registers reg-loc (fnil identity 0)) interesting line to write 😆#2017-12-0811:16karlismine for today: https://github.com/skazhy/advent/blob/master/src/advent/2017/day8.clj Curious to see if anyone tried the creative approach of transforming the whole input to s-expressions & then evaling it.#2017-12-0813:43mfikesYes, I used eval @karlis. It even works in self-hosted ClojureScript 🙂 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_08.cljc#L22#2017-12-0813:45mfikesI didn't generate an entire namespace from the source input, if that's what you mean. 😀#2017-12-0813:49karlisthis is a pretty neat approach nevertheless!#2017-12-0811:24borkdude@karlis very similar to mine#2017-12-0811:56borkdudeSolution in PostgreSQL: https://twitter.com/pg_xocolatl/status/939099677026340864#2017-12-0812:02borkdude@karlis Someone seems to have done this in Python: https://www.reddit.com/r/adventofcode/comments/7icnff/2017_day_8_solutions/dqxuwrz/#2017-12-0812:03karlisoh my 😄#2017-12-0812:08bhaumanwell that was easy 🙂#2017-12-0812:08bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day08.clj#2017-12-0812:12bhaumandarn why didn't I use max?#2017-12-0812:13bhaumanI guess its still early#2017-12-0812:13borkdude@bhauman for fn-map I had: (defn op [sym] (get {’!= not= ’inc + ’dec -} sym (resolve sym)))#2017-12-0812:14borkdudebut I changed it because I considered it a security hole - your version is safe#2017-12-0812:16borkdudeanyway, this was an easy one for clojure at least#2017-12-0812:18bhaumanYeah, I saw that you did that, good call#2017-12-0812:19bhaumaneval is temping here but ...#2017-12-0812:25bhaumanyeah resolve is a better call as well#2017-12-0812:38bhaumanI just started playing TIS-100, and I'm digging it, I'm super surpised by this.#2017-12-0813:23mfikesMy solutions are up. I used eval FWIW: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_08.cljc#2017-12-0813:35mfikes@minikomi You can let == resolve to == FWIW#2017-12-0813:41noogahttps://repl.it/repls/ThoroughDarkgreenIndianrhinoceros#2017-12-0813:41noogaat first, i wanted to use syntax quote and eval#2017-12-0813:42noogabut then decided to go with an interpreter#2017-12-0813:48orestisHere’s mine - I had failed to cope with eval in the past due to the lack of access to the lexical context, so I just went with a plain reduce. https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day8.clj#2017-12-0813:48mfikesNice @nooga Fairly compact result.#2017-12-0813:50noogaI could definately golf it some more, avoid repeating solve1 code in solve2 and replace the loops with reduce 😄#2017-12-0813:50noogathanks @mfikes#2017-12-0813:53orestisIt seems a lot of people are using read-string for these, then destructuring the resulting vector… You wouldn’t usually do that, would you? Given the docs’ warning that read-string can eval code?#2017-12-0813:54mfikes@orestis If I'm reading your code correctly, you can write
(update context target #(op (or % 0) am))
as
(update context target (fnil op 0) am)
#2017-12-0813:54noogafnil is little known but really useful#2017-12-0813:55orestisYep, I saw fnil in @nooga’s code and thought the same — I’ve yet to finish my 3rd read-through of clojure.core 😉#2017-12-0813:55mfikes@orestis Yeah, in real code I would parse things and not use read or eval. But this is AoC, one of the few places you can 🙂#2017-12-0813:56orestis@mfikes Ah, update can take extra args, no need to close over them. Thanks!#2017-12-0813:57mfikes@orestis Hey, even using (or x y) to deal with falsey x is a non-intuitive idiom that you learn to use after starting the journey 🙂#2017-12-0813:57orestisIt’s a bummer that get offers a default value but update doesn’t. Breaks the symmetry.#2017-12-0813:57mfikesI failed to point that out in an early interview for code that was like (if x x y)#2017-12-0813:58orestisundefined || 0 is idiomatic JS though.#2017-12-0813:58orestis(I think! Who knows if there really is a concept of idiomatic JS these days)#2017-12-0814:00mfikesTo be honest, I think the most profitable way I learned things is by reading other's code#2017-12-0814:01orestisYep, that’s the value of AoC!#2017-12-0814:02noogamy dirty secret is that despite writing almost exclusively clj and cljs for the past 3 years, I still look at ClojureDocs every 5 minutes#2017-12-0814:02nooga😄#2017-12-0814:03mfikesI think Rich Hickey also looks at those docs#2017-12-0814:03mfikesI'm proud to have what I suspect is the slowest solution for day 8, coming in at 5 seconds#2017-12-0814:04mfikesGoing for 3 orders of magnitude slower than the fastest#2017-12-0814:04noogaI think it’s because I don’t pay close attention to simple things like argument lists when focusing at the problem I’m currently solving#2017-12-0814:05noogayeah, I got that in emacs as well#2017-12-0814:06mfikesCool!#2017-12-0814:06noogabut often you will be thinking “huh, does re in clojure.string/split have to be re or can it be a string”#2017-12-0814:06noogaor something#2017-12-0814:06noogabtw. my solution clocks at 5-6ms#2017-12-0814:06mfikesI always look that up, every time#2017-12-0814:10orestisI would love if Dash could look up clojuredocs. I wonder if there’s a plugin for that.#2017-12-0814:11orestisRe speeds, part 1 5ms, part 2 15ms…#2017-12-0814:12noogahm, as we figured out, it’s impossible to compare the performance unless we run each other’s code#2017-12-0814:13noogabut hey, if it’s 5ms it’s very decent#2017-12-0814:13orestisToday should be roughly comparable for everyone, assuming everyone has 1000 ops to run, there’s no loops or any other funky stuff going on there.#2017-12-0814:14orestisI have to clarify; 5ms is what time prints when running within CIDER. Not sure if the JVM is hot/cold/lukewarm/whatever.#2017-12-0814:16borkdudeBoth parts run in 5 ms for me (with criterium), but that’s because the first run already contained the solution for part 2#2017-12-0814:17noogasame#2017-12-0814:17noogaI mean, solve1 and solve2 are basically the same#2017-12-0814:17noogain my code#2017-12-0814:33orestis@mfikes I like the use of spec to parse the values. I should start using that instead of regexes.#2017-12-0814:33mfikesYeah, I wouldn't argue it is the right way. But the only way to find out is to try.#2017-12-0814:54borkdudefor now read-string + destructuring is my favorite way, although spec sounds more interesting 🙂#2017-12-0814:58bhaumanyou can use edn/read-string for a safer version of read-string#2017-12-0814:59bhaumanbut really no need here#2017-12-0815:01borkdudeedn/read-string is my default read-string 🙂#2017-12-0815:56borkdudeI haven’t encountered a nil pointer with max… I think the behavior of (max) is undefined, like 1 / 0#2017-12-0815:56cjmurphy(max nil 0) gives a NPE for me#2017-12-0815:57borkdude@cjmurphy what about (maximum nil 10 11 nil)?#2017-12-0815:59mfikesfnil is only good out to 3 args as well#2017-12-0816:00bhaumanits better to use keep to filter out nils#2017-12-0816:00cjmurphyRight 🙂#2017-12-0816:00bhaumanor filter some?#2017-12-0816:01mfikesIf you do that, then perhaps define a variant of max that can cope with no args#2017-12-0816:01borkdudebut then you would maybe get (max) which is undefined#2017-12-0816:01borkdudeit’s probably an x y problem#2017-12-0816:02bhaumanbasically a nil punning version of max is what we are talking about#2017-12-0816:02mfikes@cjmurphy Did you encounter this via (vals {}) returning nil?#2017-12-0816:02cjmurphyMaybe I'll make a max that works with a sequence and deals with nil that way...#2017-12-0816:02mfikesCurious what context it arises in#2017-12-0816:03bhauman`(defn maximum [& args] (when-let [args (not-empty (filter some? args))] (apply max args))) `#2017-12-0816:03cjmurphy@mfikes (apply maximum (vals new-memory)) yes#2017-12-0816:04mfikesIn that case you should get an arity exception from max not a nil arg#2017-12-0816:04cjmurphyYes I got that exception too.#2017-12-0816:04mfikes(apply max (vals {})) -> arity issue#2017-12-0816:05orestisI used (mapcat vals <seq>) and it took care of null values.#2017-12-0816:05borkdudeI wonder how you got nils in the first place, I didn’t have this problem#2017-12-0816:06orestisIf you use reductions in the second part, and you don’t use a pre-populated map, the first few steps will give you an empty map until the first successful operation.#2017-12-0816:07mfikesCool mapcat solution. Perhaps (concat [1 2] nil [3 4])’s nil-punning should be in its docstring#2017-12-0816:07borkdudeah ok — I got my answer in the first part already#2017-12-0816:07cjmurphy@borkdude I got the NPE here: new-kept-highest (maximum kept-highest new-highest)#2017-12-0816:08borkdude@cjmurphy you could initialize kept-highest to 0, because this was the initial value of all registers#2017-12-0816:08orestis@mfikes I discovered it by accident.#2017-12-0816:09cjmurphykept-highest is the 'running maximum' for part two, so not actually a register value.#2017-12-0816:09mfikesI ended up with this unsavory hack: (apply max (or (vals {}) [0]))#2017-12-0816:10borkdude@cjmurphy yeah, that’s why you could seed the running max with 0, because that’s the initial max#2017-12-0816:11borkdude(@cjmurphy assuming your doing something like reduce)#2017-12-0816:11cjmurphyYes sure, I'll do that and see if any more NPEs#2017-12-0816:11cjmurphyI'm doing iterate.#2017-12-0816:11borkdudesame idea#2017-12-0816:11mfikes@orestis Right. I also discovered (merge-with + [1] {0 2}) accidentally works, but I suspect the concat behavior is intended. Hrm.#2017-12-0816:13cjmurphyI'm thinking to initialize kept-highest to lowest possible value rather than 0.#2017-12-0816:14borkdude@cjmurphy I did it this way: https://github.com/borkdude/aoc2017/blob/master/src/day8.clj#L54#2017-12-0816:14borkdudeso 0 is the initial value of cur-max (or kept-highest)#2017-12-0816:18cjmurphyI intitialized kept-highest/cur-max to Long/MIN_VALUE and now no more nil problems with max. So good point that there should not be problems with nil with max in the first place.#2017-12-0816:19cjmurphyThere would be a problem with 0 if all the register values were negative, and were always being set to negative.#2017-12-0816:20borkdude@cjmurphy The problem description states: > The registers all start at 0.#2017-12-0816:22cjmurphySure so no problem using either 🙂 I just like using the min possible value as the default for finding the maximum.#2017-12-0816:25cjmurphy(If you have to use a default - if there really were none then nil would be better of course).#2017-12-0818:00cjmurphyIf there really is no input you want the running maximum to end up at nil. So I settled with @bhauman's function that avoids both the arity exception and the NPE, with no default (i.e. nil default) for the running maximum in my code. Repeating his useful function here:#2017-12-0818:00cjmurphy
(defn maximum [& args]
  (when-let [args (not-empty (filter some? args))]
    (apply max args)))
#2017-12-0818:45cjmurphyIf however you did use a default value, and you interpreted 'the highest value held in any register during this process' to exclude registers that are only ever read from, and also to exclude the from value of registers that are set, then it would be possible for the 'running maximum' to end up as negative, in which case Long/MIN_VALUE will result in a correct outcome as long as there are a positive number of registers set.#2017-12-0915:55cjmurphyIf you attach any likelihood to the definition of 'held' requiring write then zero is not a good default. If you attach any likelihood to there being zero length input then it is better not to have a default at all. Good to be liberal with what you accept.#2017-12-0915:56cjmurphy@borkdude @mfikes ^ Sorry to still be banging on about yesterday's thing 🙂#2017-12-0915:58borkdude@cjmurphy the invariant is that held is the maximum of the previous state. 0 is exactly that.#2017-12-0915:59cjmurphyI just thought that it was possible that held means read and write. Very woolly word 'held'.#2017-12-0816:26mfikesActually, I don’t really see a good solution to this whole mess given what Val pointed out. It seems you really need to initialize all your registers to 0. (Unless there is a way to accommodate not doing that.)#2017-12-0816:29mfikeshttps://clojurians.slack.com/archives/C0GLTDB2T/p1512723886000290#2017-12-0816:32bhaumanI'm not so sure about that#2017-12-0816:33bhaumanas registers aren't really defined before hand, the only case is where you have a register for a predicate value that isn't ever used#2017-12-0816:33mfikesMaybe you are right. To define a register, you have to touch it.#2017-12-0816:34mfikesHmm. I guess you could read from a register but never write to it.#2017-12-0816:34bhaumanyeah thats the off case but#2017-12-0816:35bhaumanbut it seems as if they are defining them dynamically#2017-12-0816:35bhaumanspecifications, specifications#2017-12-0816:35mfikesThat register wound’t appear in your lazily-produced map, but has a theoretical value of 0#2017-12-0816:35bhaumanalthough you could populate it when you check it fairly easily#2017-12-0816:35mfikesYep#2017-12-0816:36mfikesb dec 5 if a < 1 would have been a good nasty input#2017-12-0816:51borkdudeWe have to generate inputs with spec and exercise the hell out of this#2017-12-0816:55mfikesFinally, a reason to have used Spec to parse!
(s/exercise ::instr 4)
([() []] [() []] [() []] [(?? MN -2 if *o -t/LR 1) [{:tgt ??, :upd MN, :val -2, :if if, :lhs *o, :cmp -t/LR, :rhs 1}]])
#2017-12-0816:56mfikesOne immediate bug this would ferret out for me is I have no function named MN. I would need to revise my s/def or do something.#2017-12-0816:58borkdudesymbol? should be a set with the symbols you expect
#2017-12-0816:59borkdudeFor generating register names: https://github.com/borkdude/aoc2015_day7/blob/master/day7.clj#L11#2017-12-0817:04mfikesYes. This is perhaps another argument to use Spec over hand-rolled regex’s: You can more succinctly define valid input: https://github.com/mfikes/advent-of-code/commit/84774e390f5ea82568cf1c87308b125692611a0e#diff-ae7d8fc250d870104fa0c68af9f2e19a#2017-12-0817:06borkdudeIn PureScript I’m expecting an ADT for these things, although you could also just do it with a set there#2017-12-0818:49chrisblomeval is not evil: https://github.com/ChrisBlom/advent-of-code/blob/master/src/adventofcode/2017/day08.clj#L20-L32#2017-12-0819:33mfikes@chrisblom Bravo! That's an extremely consumable solution, IMHO. By the way, I used eval as well. I also checked your solution and it works in Planck.#2017-12-0820:01chrisblomthanks!#2017-12-0820:38spfeifferWow…so elegant!#2017-12-0820:41bhaumanNice!#2017-12-0821:50noogaI was thinking about exactly this#2017-12-0900:50grzma little more than 4 hours…#2017-12-0907:37fellshardYak-shaved today's. (Spoiler alert, obv) Initial solution https://github.com/armstnp/advent-of-code-2017/blob/f013cff13592e2cbffff0cd6fa9aee8662d1cb1c/day-9.clj Refactored solution https://github.com/armstnp/advent-of-code-2017/blob/ff41b881cf016148e927ff01ac44ed65ec445a08/day-9.clj#2017-12-0908:20borkdudeMy day 9 is up. Fairly straightforward.#2017-12-0908:28fellshardI do love my iterate, but now that you say something reduce is probably more appropriate.#2017-12-0908:30fellshardEh, never mind. Might have worked if I'd kept the stream separate from the accumulated state, but part of the problem is that one of the 'instructions' modifies the stream itself, which makes function outputs weirder.#2017-12-0908:31borkdudehttps://github.com/borkdude/aoc2017/blob/master/src/day9.clj#2017-12-0908:34fellshardHmm. Not sure if you're just lucky or not, but ! only ignores the next character while inside a garbage block, according to the problem statement#2017-12-0908:36jmbDay 9 solved! yeeeeeeeee#2017-12-0908:37borkdude@fellshard I read the problem statement as the futile ! were only inserted inside garbage, so I could just strip it away, as I don’t expect ! outside < >#2017-12-0908:39fellshardI'm seeing them outside in my input, at least#2017-12-0908:40fellshardSearching for >! will show cases where the ! must be outside garbage, in fact#2017-12-0908:40borkdude@fellshard ok, if you have a link to your input + your expected answers I can give it a ty#2017-12-0908:41fellshardhttps://github.com/armstnp/advent-of-code-2017/blob/master/day-9.clj Score: 17390 Garbage: 7825#2017-12-0908:43borkdudeSame answer for score, different for garbage. Guess I got lucky by input.#2017-12-0908:43borkdudeMaybe I’ll fix later today. Thanks.#2017-12-0908:44fellshardLucky! But hey, turned out nice and tidy. 🙂#2017-12-0913:13borkdudeHey, are you sure your garbage output is 7825? just asking#2017-12-0913:16borkdude@fellshard my program works for my input + the examples#2017-12-0913:16borkdudebut I get a different number#2017-12-0916:22borkdudeTurned out my first solution was correct after all. I just copied the quoted input to a file, which yielded a different answer. DOH.#2017-12-0918:25fellshardIck. My bad. I should really get a repl on my personal machine so I can use resource files instead, like you do. Easier to wrangle and share.#2017-12-0908:41borkdude>! doesn’t necessarily mean you’re outside garbage#2017-12-0908:41fellshardTrue#2017-12-0908:42fellshardWait, yes it does. > will exit a garbage block if you're in one, or have no effect if you're not.#2017-12-0911:20bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day09.clj#2017-12-0911:21bhaumantake out the trash#2017-12-0913:20borkdude@bhauman @fellshard pointed out my program was incorrect for his input. I tried yours and get same numbers as you now (not pushed yet). Could you try his input? I get a different number for the garbage. https://github.com/armstnp/advent-of-code-2017/blob/master/day-9.clj Score: 17390 Garbage: 7825#2017-12-0913:35borkdudeVery nice PureScript solution: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day9.purs#2017-12-0913:35borkdudeI wonder if anyone used InstaParse for this one#2017-12-0914:01noogahttps://repl.it/repls/BurlyBlackIchthyosaurs#2017-12-0914:10borkdudeI’m going to try spec#2017-12-0914:12noogaI went with straightforward automaton to count and filter garbage “in parallel”#2017-12-0914:20bhauman@borkdude I tried his input and got the correct results#2017-12-0914:23bhauman@nooga mine is similar but I reduced the states of the automaton by handling the score separately#2017-12-0914:25bhaumanand looking at yours I'm wondering why i didn't just use a vector for state#2017-12-0914:25nooga@bhauman nice, reading it right now#2017-12-0914:25nooga@bhauman no reason, I just typed this in one go 😄#2017-12-0914:26noogaI could use a vector and change loop to reduce or something#2017-12-0914:26noogaoh, sorry, misread that#2017-12-0914:26bhaumanno worries, easy to do#2017-12-0914:36bhauman@borkdude string/replace takes a function arg that should do it#2017-12-0914:37bhaumancoming up with a much shorter solution now#2017-12-0914:40mfikesMy day 9: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_09.cljc#2017-12-0914:46bhaumanso I'm thinking I can clean the garbage up with string/replace now that I know it takes a fn arg#2017-12-0914:47bhaumanincluding counting it I'm pretty sure#2017-12-0914:48mfikes@grzm I think you can convert (condp = c \a (foo) \b (bar) :else (baz)) to (case c \a (foo) \b (bar) (baz)) and in addition to the simplification, you get a perf improvement with constant-time dispatch.#2017-12-0914:51nooganice @mfikes#2017-12-0914:53noogaI did basically the same but in even more condensed form#2017-12-0914:54mfikes@borkdude Hah, your solution is practically isomorphic to mine. 🙂#2017-12-0914:59mfikesNice @nooga. I tried yours on my input, and as you'd expect your version runs more quickly (it shaves off 25–50% or so)#2017-12-0915:04nooganice#2017-12-0915:04noogaso not only is it short, it’s also fast ;d#2017-12-0915:20bhaumanOK much more concise and simple#2017-12-0915:20bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day09.clj#2017-12-0915:20bhaumanand fast#2017-12-0915:20borkdudeWhy is this so sloooooow?
(s/def ::garbage (s/cat :lab #{lab}
                        :content (s/* char?)
                        :rab #{rab}))

(s/def ::group (s/cat :lcb #{lcb}
                      :children
                      (s/* (s/cat :child (s/alt :group ::group
                                                :garbage ::garbage)
                                  :comma (s/? #{\,})))
                      :rcb #{rcb}))

(s/conform ::group (seq "{{},{<x>}}"))

(defn parse-string [s]
  (s/conform ::group (seq s)))

(comment 
         (def p (parse-string (data))))
Heap space exception
#2017-12-0915:21bhaumanare you generating test input?#2017-12-0915:21borkdudenope, just conforming#2017-12-0915:21grzm@mfikes nice. I'll give that a shot. It's working at sub 10ms already.#2017-12-0915:21bhaumanit can't find a match so its continuing to search?#2017-12-0915:22mfikes@grzm Yeah, for this problem, case is only better than condp = for readability IMHO#2017-12-0915:22borkdudeI noticed case doesn’t work when you’re aliasing stuff…#2017-12-0915:23borkdude@mfikes Oh cool (isomorphic), but mine is incorrect for one out of three inputs I tried#2017-12-0915:25grzmI was also thinking of rewriting it to dispatch on both args to move all dispatch logic into the multimethod.#2017-12-0915:26borkdude@mfikes I noticed yours failed too for @fellshard’s input (returns 8373 for garbage count instead of 7825)#2017-12-0915:27mfikes😵#2017-12-0915:27bhaumanlol#2017-12-0915:27mfikesSo, some part of the problem definition seemed underspecified to me, and I ended up assuming.#2017-12-0915:29bhauman@borkdude mine now uses regexes like yours did and it works for @fellshard's input#2017-12-0915:32borkdude@bhauman wow, I didn’t know str/replace took a function!#2017-12-0915:32bhaumanI sent you a message above stating just that!! 🙂#2017-12-0915:33borkdude@bhauman > string/replace takes a function arg that should do it it being?#2017-12-0915:34bhaumanyeah 🙂#2017-12-0915:34borkdudeI meant: what do you mean with "it"?#2017-12-0915:35borkdudeI get it now, but I didn’t understand that message in the context of the thread 🙂#2017-12-0915:35bhaumanyeah not clear at all#2017-12-0915:36borkdude@bhauman you’re replacing the exclamation marks regardless of whether they occur out or inside the question marks… but it seems they don’t ever occur outside#2017-12-0915:37borkdudeso I guess that’s fine#2017-12-0915:37bhaumanyes we have to assume there isn't stray chars#2017-12-0915:38borkdudeif I had a better up front understanding of the structure, e.g. {aaaxx!xxx{<x>}} doesn’t occur, I would have written a better solution… but to eager too find the answer 🙂#2017-12-0915:40bhaumanthats the cool thing about str/replace taking a function, is you can call str/replace again inside that fn#2017-12-0915:41mfikesWait, that's exactly the part that I thought was underspecified in the problem definition @borkdude#2017-12-0915:41borkdude@bhauman that’s so good to know — thanks!#2017-12-0915:41nooga> In a futile attempt to clean up the garbage, some program has canceled some of the characters within it using !: inside garbage, any character that comes after ! should be ignored, including <, >, and even another !.#2017-12-0915:42bhaumanso one way of reading that, is that ! only occurs inside garbage#2017-12-0915:43borkdudeyeah you could also deduce it from the examples#2017-12-0915:43grzmUsing case dropped part 1 from sub 10ms to sub 7ms#2017-12-0915:44bhaumanit seems like a fair assumption#2017-12-0915:44mfikesYes, my reading is that ! only has meaning inside garbage.#2017-12-0915:44borkdudethat’s what our solutions are doing too I believe mfikes#2017-12-0915:44borkdudethere has to be some edge case only occurring in fellshard’s input#2017-12-0915:45mfikes@borkdude Is the problem that {aaa{foo}xxx} can occur?#2017-12-0915:45borkdude@mfikes my code should interpret that too#2017-12-0915:45mfikesMy code would interpret that as a single group.#2017-12-0915:45mfikesOr at least I didn't code for that case.#2017-12-0915:46borkdudeI get a score of 3 for that one#2017-12-0915:46borkdudebut it’s not likely that our code should handle it#2017-12-0915:47mfikesYeah, my code does that as well, but I would claim my code is undefined for that kind of input.#2017-12-0915:47grzmThat's invalid, per the spec#2017-12-0915:47borkdudeI shouldn’t affect the outcome though#2017-12-0915:48grzmDepends on your stance on Postel's law 🙂#2017-12-0915:48borkdudetl;dr?#2017-12-0915:48mfikesAccept bad input? Accept bad AoC problem definitions?#2017-12-0915:48grzmBe liberal in what you accept, conservative in what you emit.#2017-12-0915:48borkdudeI subscribe to that law#2017-12-0915:49grzmFor me, it depends on whether or not I've had breakfast.#2017-12-0915:50borkdudeFor nutrition, I subscribe to the reverse#2017-12-0915:52borkdude@mfikes What should the garbage count for this one be?
(solve “{{<!!!>}}“)
#2017-12-0915:52mfikesI'm leading towards {aaa{foo}xxx} being a single group, because "things" are separated by commas#2017-12-0915:53borkdude@mfikes I ignored commas too, I treat all things like whitespace if it’s not a group / garbage separator#2017-12-0915:53mfikesThere is no closing of the garbage in your example @borkdude#2017-12-0915:53borkdudeyes, of course..#2017-12-0915:55bhaumanthe presense of non garbage garbage, doesn't affect the final score or the garbage count#2017-12-0915:56borkdudeI wonder what’s up with the garbage count in our code mfikes…. — yes, you’re right bhauman, I think we’re doing that#2017-12-0915:56bhauman@borkdude i'd suspect its an odd even escape code thing#2017-12-0915:57bhaumanas thats the only thing that can mess up the count#2017-12-0915:58mfikes@borkdude My code and fellshard's code produce the same 8373 for garbage cound#2017-12-0915:58borkdudereally?#2017-12-0915:58mfikesYeah, perhaps there is no bug#2017-12-0915:58bhauman@mfikes on fellshards input?#2017-12-0915:58borkdudebut he told me he got 7825 and bhauman + Vik got that too: https://twitter.com/pg_xocolatl/status/939517141606457344#2017-12-0915:59bhaumanboth yours and his would probably be the same for your input#2017-12-0915:59mfikesFor fellshards input my code produces 17390 and 8373 and fellshard's produces {:score 17390, :garbage-count 8373}#2017-12-0915:59bhaumanthat doesn't sound right#2017-12-0915:59bhaumanat all#2017-12-0916:00borkdude@mfikes Is your REPL state fresh?#2017-12-0916:00borkdudeJust checking 😄#2017-12-0916:00mfikesI resarted it. Still getting {:score 17390, :garbage-count 8373}#2017-12-0916:01bhaumanwell i get 7825#2017-12-0916:01borkdudewith /his/ code?#2017-12-0916:01bhaumanon fellshards input#2017-12-0916:01mfikesIndeed.#2017-12-0916:01borkdude@mfikes Did you also upgrade to clojure 1.9.0? maybe it’s a bug 😄#2017-12-0916:02bhauman👏#2017-12-0916:04mfikes@borkdude I think the problem is this: In fellshard's code his input is defined in the code. I copied your input file in your repo, but the file is a direct copy, and the file has the quotes escaped in it#2017-12-0916:04mfikesSo, I'm getting the incorrect answer for the file, but the correct one from the literal code#2017-12-0916:05mfikesIn other words, the problem is here https://github.com/borkdude/aoc2017/blob/master/resources/day9-fellshard.txt at the first escaped quote#2017-12-0916:05bhaumanmakes sense#2017-12-0916:06borkdudeaaaaaaaaaargh#2017-12-0916:06borkdudethanks.#2017-12-0916:06borkdudeso maybe my solution was correct to being with… let’s test#2017-12-0916:17borkdudeok, so my first solution this morning was correct…#2017-12-0916:20bhauman@borkdude @mfikes I mentioned this yesterday but have either of you tried TIS-100?#2017-12-0916:20bhaumanhttp://www.zachtronics.com/tis-100/#2017-12-0916:24mfikesNo. That looks interesting!#2017-12-0916:34bhaumanits way more fun than I expected#2017-12-0916:37borkdudeSorry, not enough time for that right now 🙂#2017-12-0916:37noogaI tried TIS-100#2017-12-0916:37noogait’s harder than it looks#2017-12-0916:37nooganever finished it, requires lots of free time#2017-12-0916:49bhauman@nooga yeah its not easy but I hurt my back the other day so i'm kinda stuck on the couch#2017-12-0916:50bhaumanand I was watching "Halt and Catch Fire" so I was a bit nostalgia driven#2017-12-0916:52borkdudeI think my spec is correct now, but it’s still slow: https://github.com/borkdude/aoc2017/blob/master/src/day9_spec.clj#L56#2017-12-0916:52grzmSurprisingly when I replaced the defmulti with one big multi-tiered case statement, it's slower. https://github.com/grzm/advent-of-cljc/blob/899b18e6e72ce2157d63f9b3b7280b1c35a0f106/src/main/com/grzm/advent_of_code/advent_2017/day_09/part_1.cljc#2017-12-0916:52grzmThey're all pretty close, though. Within 2 ms.#2017-12-0916:53borkdudeMaybe I should try instaparse#2017-12-0916:54grzmIt's pretty impressive how flexible spec is.#2017-12-0916:55grzmWhat kind of speeds are you seeing with your spec solution?#2017-12-0916:55borkdudeyeah, but I think the data it’s generating for this thing becomes too big maybe?#2017-12-0916:55borkdude@grzm Nothing yet. I can’t parse the whole input#2017-12-0916:55borkdudeHalting problem#2017-12-0916:56grzmThat makes sense. It's building up some sort of structure to be able to explain failures.#2017-12-0916:56borkdudeI love how you can just eval your boot file and it will pick up on new deps#2017-12-0917:04thegeez@borkdude I think your specs are slow because the :content and :rab branches are not mutually exclusive because char? will also match rab. So it "blabla>yadayadayada" will parse as the whole string into :content first and then will need to backtrack#2017-12-0917:05borkdudehmm yeah, how to improve that#2017-12-0917:12thegeezreplace char? with a more specific predicate, same for :children and :comma#2017-12-0917:17orestisHi all! I had to solve this in a real hurry today, here is my solution: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day9.clj#2017-12-0917:27orestisSeems like similar to @nooga but with two functions for each state. #2017-12-0917:36grzm@borkdude I've been eyeing your resource-reducible. I've been focusing on using more tranducers. Is that something you worked out yourself?#2017-12-0917:37borkdude@grzm No, I stole it from a blog post, but you can see the idea here: https://stackoverflow.com/questions/47333668/split-lines-in-clojure-while-reading-from-file/47354316#47354316#2017-12-0917:38borkdudeThe link to the full blog post is at the bottom#2017-12-0917:38grzmAh! That post came up in my search for IReduceInit.#2017-12-0917:39grzmOne more piece to have in my back pocket. AoC, or rather, this community in AoC, has been really helpful for me. Thanks, all of you!#2017-12-0917:40grzmAnd it's only Day 9 🙂#2017-12-0917:40borkdudeTo be honest I didn’t really need it, line-seq or slurp is sufficient#2017-12-0917:42grzmThat may very well be the case, but if you didn't have it there, I wouldn't have been exposed to it. So regardless of whether you needed it, it served a purpose.#2017-12-0918:09orestisAh, I should have used letfn for my mutually recursive functions instead of pre-declaring them. #2017-12-0918:18borkdudeInstaparse! https://github.com/borkdude/aoc2017/blob/master/src/day9_instaparse.clj#2017-12-0918:22fellshardD'oh. Yeah, I should've considered the escaped quotes in my input 😞#2017-12-0918:23fellshardI was wondering if someone would make a grammar for this, it's perfectly suited 😄#2017-12-0918:24fellshardInstaparse looks really neat, should pick that up for one of these.#2017-12-0919:34noogafunny, I’m writing a ghetto parser combinator lib atm#2017-12-0919:49borkdudeInlined the grammar now, so you see the entire solution one file. See above link. Really happy with it 🙂#2017-12-0919:50borkdudeI think you could do the same with spec in hindsight as @thegeez said, more restricted rules/predicates. The nice thing with Instaparse is that you can hide tags and output. Not sure if that’s possible with spec. That would be nice in fact.#2017-12-0919:53borkdudeHere’s a screenshot of the parsetree: https://twitter.com/borkdude/status/939583561568604160#2017-12-0920:26nooga😮#2017-12-0921:21thegeez@grzm for resource-reducible there's also https://github.com/cgrand/xforms/blob/master/src/net/cgrand/xforms/io.clj#L14#2017-12-0921:21borkdudeyes, I think it’s more or less the same thing (unless I’m missing something)#2017-12-0921:25gnejsHowdy all 🙂. So.. day 9. I ended up with a couple of weirds constructs for dropping cancelled chars (and to drop garbage): https://github.com/metamorph/advent-of-code-2017/blob/master/adv2017/src/adv2017/day9.clj#L1 (`make-drop-!-xf`) where I use an atom to keep state in a filter. I'm thinking that there must be a better way of doing that (and still being "lazy"). Any suggestions?#2017-12-0921:26borkdude@gnejs There is a possible solution with a single pass using a couple of values in a state with reduce#2017-12-0921:27borkdudee.g. https://github.com/borkdude/aoc2017/blob/master/src/day9_single_pass.clj#2017-12-0921:27borkdude@mfikes also has one#2017-12-0921:29mfikesFor reference here is my solution https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_09.cljc#2017-12-0921:29gnejs@borkdude that's cool. 🙂 I was trying to split apart the concerns of "cancelling" and "dropping garbage" into separate transducers to avoid one big reducing function with all aspects mixed.#2017-12-0921:31gnejsSo my question is really - how do you implement a stateful filter (transducer-like) without resorting to using mutable state as I did?#2017-12-0921:33mfikes@gnejs I think it is normal to keep state (usually using volatiles instead of atoms). See (source distinct)#2017-12-0921:34gnejs@mfikes ah, cool. So it's not really an anti-pattern then :thumbsup:#2017-12-0921:35mfikesI honestly don't know too much about it other than "stateful transducers have mutable state in them using volatiles"#2017-12-0921:37gnejsDidn't know about volatile! before. Thanks for the pointer :thumbsup: This seems to be pretty exhaustive explanation: https://stackoverflow.com/questions/31288608/what-is-clojure-volatile/31319731#31319731#2017-12-0921:38mfikesPerhaps the reason is that there is no good way to thread a non-mutable state through. Like the step function inside the non-transducer version of distinct can do.)#2017-12-0921:57grzm@thegeez yeah, it looks like there's a lot of goodness in xforms#2017-12-1006:03theeternalpulseYikes, half way through day 3 and I'm sure I'll find a simpler intuitive solution in the other ones.#2017-12-1006:08theeternalpulsehttps://github.com/deepee0086-clj/adventofcode-clojurians/blob/master/src/day_03.clj#2017-12-1006:20fellshardHmm. My soln. for today's part two matches the example inputs, but not my own.#2017-12-1006:23fellshardOoooh. Bad hex formatting, I think.#2017-12-1006:24fellshardpicard-facepalm#2017-12-1006:34grzmI'm glad my solution worked, because I don't know how I would have debugged that.#2017-12-1006:37fellshardIt's... definitely a 'walk through by hand' deal. Best I could do was run through their small example step-by-step.#2017-12-1006:37grzmThat pretty much describes my code. Amazingly enough, I had the algorithms right the first time. Spent a good deal of time wondering what was wrong before I realized I was using the wrong hash length.#2017-12-1006:39grzmNow trying to port it to cljs#2017-12-1006:59grzmPushed. Now to sleep!#2017-12-1007:46fellshardMoar yak shaving for the 'twist' logic, I feel a lot better about it now. Found the right abstraction for the job.#2017-12-1010:35orestisToday was fun! I managed to reuse my functions from part 1 without having to rewrite them at all. https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day10.clj#2017-12-1010:38orestis@fellshard Nice solution! I like your twist logic; I went with a transient vector instead.#2017-12-1012:10borkdudehttps://github.com/borkdude/aoc2017/blob/master/src/day10.clj#2017-12-1012:20borkdude1.3 ms for part 1, 224ms for part 2#2017-12-1013:29noogahttps://repl.it/repls/LeadingOrchidArkshell#2017-12-1013:29noogahere’s mine#2017-12-1013:33nooga3.9ms / 224,8ms#2017-12-1015:15grzm@orestis nice mix of code, tests, and description#2017-12-1015:26orestisThanks @grzm — I picked it up somewhere. These days I don’t even read the puzzle on the browser any more, I just copy paste directly in the editor. I love how cider enables me to write tiny functions one by one. #2017-12-1015:27orestisI’m sure there is a way of doing this better, literate programming? Perhaps some kind of jupyter notebook?#2017-12-1015:27grzmI'm much more pragmatic about it: you've got a solution that works really well.#2017-12-1015:29orestisI would like to look into devcards to make the whole thing interactive and shareable. #2017-12-1015:29grzmLooks like there's a smaller set of inputs for Day 10. @borkdude and I have the same one.#2017-12-1015:30orestisAFAIK, there’s only 10-20 inputs per puzzle, as the have to all be validated beforehand. #2017-12-1015:30orestisAFAIK, there’s only 10-20 inputs per puzzle, as they have to all be validated beforehand.#2017-12-1015:30grzmmakes sense#2017-12-1015:31borkdude@orestis devcards isn’t that more for showing UI components? you could also try klipse, so anyone could play with it in the browser#2017-12-1015:33grzm@borkdude: how does yours work with using "%x" for formatting? I needed to use "%02x"#2017-12-1015:34grzmI've run yours locally and confirmed it works.#2017-12-1015:34orestisAh, yes, I haven’t used either so got them mixed up. #2017-12-1015:34borkdude@grzm don’t know, haven’t thought about it deeply#2017-12-1015:38grzmOkay: the test examples they give require "%02x" as some of the xor'd values are less than 16. That's not the case for the actual input.#2017-12-1015:40borkdudethanks, I’ll enhance#2017-12-1016:11bhauman60ms on part 2 🙂#2017-12-1016:11bhaumanbut it wasn't easy#2017-12-1016:13bhaumanfound some weird things: like apply is faster than arg destructuring#2017-12-1016:13bhaumanin my first version, part 2 never finished as I got tired of waiting after 5 minutes#2017-12-1016:15bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day10.clj#2017-12-1016:17bhauman@orestis our answers are so similar 🙂#2017-12-1016:18bhauman@orestis I found a big optimization if you mod the drop pos here: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day10.clj#L44#2017-12-1016:19orestisIs (let [[head & tail] s]) the idiomatic way to do (let [head (first s) tail (rest s)]) when you know you deal with vectors?#2017-12-1016:20bhaumanI wouldn't say so#2017-12-1016:20orestis@bhauman You mean by skipping the cycle?#2017-12-1016:21bhaumanyou keep the cycle#2017-12-1016:21bhaumanbut pos could be larger than your vector so you can mod it by the length to get the same value#2017-12-1016:21bhaumanso less iterating through the array#2017-12-1016:23bhauman(= (drop (mod pos (count x)) (cycle x)) (drop pos (cycle x)))#2017-12-1016:24orestisHm - I think I mod the pos anyway at every step so it should be equivalent?#2017-12-1016:25bhaumanoh ok missed that 🙂#2017-12-1016:25bhaumanwell that makes much more sense#2017-12-1016:27bhaumani should have done that#2017-12-1016:29bhauman@orestis btw I'm pretty sure [head & tail] compiles into first rest so they should be equivalent and its pretty idiomatic to use [head & tail] when iterating#2017-12-1016:29bhaumanover any collection#2017-12-1016:32orestisGood to know; coming from Elixir where there is some nice syntactic sugar to work with linked lists, I’ve missed that a bit.#2017-12-1016:33borkdudeI first had a solution with cycle, drop and take, but then decided I could do better with one pass#2017-12-1016:33borkdudeI could probably make it faster with transients, but I haven’t used any today#2017-12-1016:35bhauman@borkdude your solution gets a 👍 for clarity and simplicity#2017-12-1016:36bhaumanand its way fast enough to get the job done#2017-12-1016:37borkdudethanks 🙂#2017-12-1016:38bhauman@nooga your hurting my brain 🙂 trying to follow it ... trying ...#2017-12-1016:38noogasorry 😄#2017-12-1016:38borkdudelink?#2017-12-1016:39noogahttps://repl.it/repls/LeadingOrchidArkshell#2017-12-1016:39noogadefinately not a production code 😄#2017-12-1016:40bhauman(c-splice a p (reverse (c-slice a p l))) for the win#2017-12-1016:40borkdudeit looks like C written in Clojure 🙂#2017-12-1016:41bhaumanI see a p l and I see APL#2017-12-1016:41noogaI get into this mode sometimes 😄#2017-12-1016:41borkdudep0, ah, of course, a pointer#2017-12-1016:41borkdudeand then some bit shifting going on#2017-12-1016:42noogaI wrote this while reading the puzzle, not after#2017-12-1016:43noogathere’s not much conscious thought into this 😄#2017-12-1017:29mfikesMy day 10: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_10.cljc#2017-12-1017:31mfikesWhat's up with that strange length sequence 3, 4, 1, 5, 17, 31, 73, 47, 23 and skip size 4 in the running example? That tripped me up for a long time.#2017-12-1017:31bhaumanoh you can mod the skip size!!#2017-12-1017:31bhaumanwell damn#2017-12-1017:42borkdude@mfikes nice concise solution#2017-12-1018:42fellshardGood thinking on just mapping the indices instead of mapping the values in-place, @borkdude#2017-12-1018:43fellshardLess list-shifting shenanigans that way#2017-12-1018:44fellshard@orestis - Maybe you'd enjoy poking https://gdeer81.github.io/marginalia/#2017-12-1019:17orestisOhh that seems nice! I’ll give it a proper look.#2017-12-1019:24nooga@mfikes I think it’s bascially what I did but mine is less clear#2017-12-1022:15jmbJust solved Day 10. I think it's interesting how my solutions per day all look so similar. Maybe it's just me#2017-12-1023:05mfikesI'm still curious. Was this just me missing something fundamental, or did others find this a problem. If you know why it is correct, please share. https://clojurians.slack.com/archives/C0GLTDB2T/p1512927092000137#2017-12-1023:17grzmThis is my understanding, thinking out loud: the 3, 4, 1, 5 are from the initial lengths in Part 1. The 17, 31, 73, 47, 23 is the "coda" as /cdn-cgi/l/email-protection (edited from @fellshard) named it, which is added in Part 2. A the end of the first part, skip was 4 and position is 4. They're picking up where that left off. Am I following you so far?#2017-12-1023:19mfikes@grzm Thank-you. That helps! (WTF!)#2017-12-1023:25mfikesThat makes complete sense. Wow, them hopping back to part 1, after having started a new example involving 49,44,50,44,51,17,31,73,47,23 really threw me off. Attempting to understand that sequence was an order of magnitude harder than just solving the problem. (Or infinitely harder for me, since it escaped my ability to comprehend it.)#2017-12-1023:26grzmYeah, I'm not sure why they didn't just continue with the ascii-values they already had in part 2.#2017-12-1023:26mfikesI was trying desperately to derive 3, 4, 1, 5 from something in part 2.
#2017-12-1023:26grzmActually, they didn't want to redo the whole thing: they wanted to show an example of maintaining state across rounds.#2017-12-1023:27grzmWell, part of the real world is interpreting requirements, right? 😉#2017-12-1023:27mfikesCool. Thanks. "Mike, look at part 1," was all I needed 🙂#2017-12-1023:27mfikesIndeed, that is part of problem solving. Requirements interpretation.#2017-12-1023:29grzmWell, the rest of it was me making sure I understood the question#2017-12-1023:31fellshard'coda' was someone else's name, but I like it better than 'suffix', which the problem statement used. The problem writing was a bit disorganized and verbose today; perhaps intentionally, perhaps not. Easy to miss the piece about the suffix, as it's not highlighted or mentioned elsewhere. #2017-12-1023:32grzmRight, it was /cdn-cgi/l/email-protection#2017-12-1023:34mfikesYeah, generally the problems are very high quality, and day 10 was also a high quality problem. Perhaps the description wasn't as clearly written as some of the previous ones. That's cool—it adds to the challenge.#2017-12-1023:37fellshardIt's why l like AoC - it mimics real world problems a bit better, both with the explanation sometimes being unclear, yet testable with examples; and with two-part solutions, that force you to refactor or remodeling your solution in many cases. A much more interesting learning experience. #2017-12-1102:00minikomiNice weekend everyone? 😄#2017-12-1102:24minikomigot day9.. should have used a map and not vars for the loop/recur#2017-12-1102:27grzmtoo bad you can't change it 🙂 (git records all of our sins)#2017-12-1102:39dpsuttonforce push to the rescue#2017-12-1102:39minikomilol. i like having the history of my refinements for AoC#2017-12-1102:44mfikes@minikomi Nice solution! Your throw may make things more robust, but if the input is valid, I think you should be able to take the three cases \, \newline, and \! and eliminate them, if you take the result-expr for \, and use it instead of the (throw ...).#2017-12-1102:45minikomiyeah, i just had it there to refine my solution.. catch (ha!) the times it went awry.#2017-12-1102:45mfikesInstead of trying to say it in words, this variation on your solution works for me: https://gist.github.com/mfikes/57c1b666c30bb5fd98b235df87b5c189#2017-12-1102:46minikomioh, is cancel guaranteed to only be in garbage? that's good then!#2017-12-1102:47mfikesRight, I think you can interpret the problem definition that way. And it seems to be borne out by the input data.#2017-12-1102:47minikomicool#2017-12-1102:52minikomithere 🙂 credited you in the commit heh#2017-12-1104:32minikomiman this wording for day 10 part 2 is confusing.#2017-12-1104:33minikomiIf the suffix is added, there's 8 3, 4, 1, 5, 17, 31, 73, 47, 23 as the steps.. but the skip sequence carried over is 4 ?#2017-12-1104:33minikomirather than 9, since 9 steps have occured..?#2017-12-1104:49minikomioh, ok i got it.#2017-12-1105:30minikomireductions 💌#2017-12-1105:37fellshardI've gotta search for the number of times part 2 has been reduce -> reductions#2017-12-1105:40dyankowskyI've used Clojure for all three years, and I feel like some of the earlier problems are easier to solve in a procedural style, but I feel like functional languages really start to shine after a few days.#2017-12-1105:41dyankowskyThough the hash cracking one from... last year?... was a bit tough... I had to learn more about Java interop to make it fast#2017-12-1105:42fellshardI'd love to go through and solve these with different paradigms, hone a sense for what gets easier and what gets harder#2017-12-1105:44fellshardAlso had Proto Repl finally set up on my laptop for this round 😄#2017-12-1106:28Miķelis Vindavs@fellshard same here, but right now trying to decide between “pretty” with reduce/`reductions` vs 30x faster with apply#2017-12-1106:38minikomi(apply str (map #(format "%02x" %) xored)) Was pretty happy wit that hexidecimal-string-conversion 😄#2017-12-1106:38minikomiformat is such a beast#2017-12-1109:33orestisHi all! @fellshard Indeed, “coda” is a musical term; It literally means “tail” in Italian. It refers to the bars that come after a repeating part. I don’t know how it popped into my mind, but I like it better than “tail” which can be confusing when destructuring linked lists.#2017-12-1109:33orestisDay 11: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day11.clj#2017-12-1109:34orestisToday I didn’t have much time to arrive to the solution from first principles; I had to lookup hex grids and how they work.#2017-12-1109:36orestisI’ve included a link to a nice article in my solution code.#2017-12-1110:01borkdudeDay 11 is a bit difficult for me#2017-12-1110:01borkdudeI’ll peek at @orestis's link#2017-12-1110:53borkdudeAnyone who wants a SPOILER or hint, peek in this thread#2017-12-1110:53borkdudehttps://twitter.com/EsthervdSHU/status/940160750303268864/photo/1#2017-12-1112:06karlismy solution for today: https://github.com/skazhy/advent/blob/master/src/advent/2017/day11.clj with a handy ascii art on how the coordinates are handled.#2017-12-1112:11Miķelis VindavsIn my opinion, today’s challenge lent itself well to one of the most elegant & concise solutions this year so far https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day11.clj#2017-12-1112:38orestis@mikelis.vindavs That is indeed very nice.#2017-12-1113:05borkdudeDid anyone else get emotional while reading > “It’s my child process,” she says, “he’s gotten lost in an infinite grid!”#2017-12-1113:07noogahttps://repl.it/repls/BoldAzureCuscus here’s mine#2017-12-1113:08mfikesDay 11: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_11.cljc#2017-12-1113:09noogacube coordinates everywhere 😄#2017-12-1113:09borkdude@mfikes isomorphic once again#2017-12-1113:10borkdudeI have to admit without the hint about cube coordinates I would still be thinking right now#2017-12-1113:10mfikesMe too. I did some quick research and chose that coordinate system because it makes calculating distance trivial.#2017-12-1113:11borkdudeThe photo in the spoiler thread above did it for me#2017-12-1113:12noogaI’m wrote a game on hex grid once so it was a no-brainer#2017-12-1113:24erwinI solved it without cube coordinates, by using the simplified versions of de diagonals for north and south. So NE + NW = (1,1) + (1,-1) = (2,0). Calculation is simple after that, similar to using a Z-axis. #2017-12-1113:25borkdude@erwin link?#2017-12-1113:25erwinhttps://github.com/ekroon/adventofcode2017/blob/master/src/adventofcode/day11.clj#2017-12-1113:27Miķelis Vindavsnice approach with the input resolving directly to coordinate tuples 👍:skin-tone-2:#2017-12-1113:29borkdude@erwin nice!#2017-12-1113:30borkdudeit seems so simple once you see it#2017-12-1113:32erwintoday was fast to compensate for yesterday, which was very slow for me 😁 #2017-12-1113:35noogainput/input#2017-12-1113:35nooga?#2017-12-1113:36noogawoo, i forgot that reductions exists#2017-12-1113:37erwinoow, still a defect? wrote the solution in a repl / nightcode at work and pasted it in github in one file. Let me fix that. #2017-12-1113:39mfikesThere is an interesting perf anomaly with @erwin's solve-2 where it runs in 124 ms for me in Clojure vs. 15 ms in self-hosted ClojureScript. Hrm.#2017-12-1113:40borkdude@mfikes sanity check: do they yield the same outcome?#2017-12-1113:42mfikesYes, 1493#2017-12-1113:49mfikesThis was the page I hit for the research I did. It has incredible visualizations of the coordinate systems. https://www.redblobgames.com/grids/hexagons/#2017-12-1113:50borkdudeI hit that one too and then I tried the q layouts, but had problems calculating the distance#2017-12-1113:51mfikesI scrolled down to the Distances section and saw that Cube coordinates has a nice formula.#2017-12-1113:57borkdudeyeah, that’s the same system as on the photograph, but I was nearly awake then 😉#2017-12-1114:00bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day11.clj#2017-12-1114:00bhaumanok just finished, I spent some time on paper trying to devine the properties of the system first#2017-12-1114:01bhaumannow to see what others did#2017-12-1114:02borkdude+1 for the Christmas ascii art @bhauman#2017-12-1114:03bhauman@borkdude thats from the first advent of code#2017-12-1114:05bhaumanoh I see others did this as well, congrats @mikelis.vindavs!!#2017-12-1114:06bhaumanand @erwin#2017-12-1114:07bhaumanoh wait yours is different but I think logically equivalent#2017-12-1114:08mfikesInteresting. @bhauman's also exhibits that odd perf anomaly where part 2 is much faster in Planck.#2017-12-1114:09mfikes90 ms vs. 30 ms#2017-12-1114:09bhaumanwell its the same work, so maybe its warmed up#2017-12-1114:12mfikesPlanck starts off at 90 ms but then drops down to 30 ms. My guess (based on some stuff Timothy Baldridge was saying): JavaScriptCore uses a tracing JIT, so after it sees execution, it can compile things to machine code that relies purely on primitives. There is evidently something tracing JITs can do that the Java VM can't do with its current implementation, but I don't fully appreciate what is going on.#2017-12-1114:14mfikesPerhaps the day 11 problem happens to be highly amenable to tracing analysis, involving a tight loop of math at its core.#2017-12-1114:14borkdudeThis sounds like an Advent of Code problem in itself#2017-12-1114:14bhaumanjavascript engines are freaking crazy#2017-12-1114:16borkdudeDay 12: > Part 1: some random array walking > Part 2: perhaps the day 12 problem happens to be highly amenable to tracing analysis, involving a tight loop of math at its core. > Determine the time spent after running the algorithm on the output of part 1.#2017-12-1114:17mfikesFWIW, my solution also exhibits the odd perf anomaly: part-2 is 124 ms in Clojure and 19 ms in Planck / JavaScriptCore.#2017-12-1114:21erwinusing the tips and tricks from day5 i see some boxed math and reflection optimization possibilities, so I would say that it is indeed the tracing jit#2017-12-1114:24mfikesFWIW, nooga's is also exhibiting the same phenomenon#2017-12-1114:24borkdude@mfikes what about your own?#2017-12-1114:25mfikeshttps://clojurians.slack.com/archives/C0GLTDB2T/p1513001852000049#2017-12-1114:25erwinhttps://github.com/ekroon/adventofcode2017/commit/95d397e70fb1485a16a0a9ae30a61a0c80117320 adding ^int ^int ^int ... and it is 10ms and 20 ms#2017-12-1114:25borkdude@mfikes oh sorry 🙂#2017-12-1114:33mfikesYeah, for me the call to Math/max was using reflection. 😱 My solution dropped from 124 ms to 8 ms with https://github.com/mfikes/advent-of-code/commit/8b71e9a87f7e9dee970fc6f5176edf30bb2569db#diff-71207370594c4dd13d58690ffbff0646#2017-12-1114:37Alonoakytry using (defn abs [n] (max n (- n))) instead#2017-12-1114:37mfikesSo, in short, no tracing JIT magic, just plain old reflection being damned slow.#2017-12-1114:38mfikesOK#2017-12-1114:38Alonoakywould probably have same effect#2017-12-1114:38mfikes@alonoaky Yep#2017-12-1114:44borkdudewasn’t this kind of type hint also valid? (defn ^long distance […] …). When I call distance from the REPL it works fine#2017-12-1114:45borkdudeBut when I call it from another form, I get: java.lang.IllegalArgumentException: Unable to resolve classname: /cdn-cgi/l/email-protection#2017-12-1114:47borkdudeShort snippet of what I mean:
(defn ^long d [] 1)
(Math/abs (d))
#2017-12-1114:49mfikes@borkdude I think that's where they go in ClojureScript, but in Clojure
(defn d ^long [] 1)
#2017-12-1114:51mfikesI'm not so sure, TBH.#2017-12-1114:52borkdudecool, 12 ms for both parts now#2017-12-1114:53borkdudewhy can’t I use ^longs here (instead of annotating each element): https://github.com/borkdude/aoc2017/blob/master/src/day11.clj#L28#2017-12-1114:53borkdudehere I could: https://github.com/borkdude/aoc2017/blob/master/src/day11.clj#L19#2017-12-1114:55mfikesHmm. ^longs means a primitive array of ^long right?#2017-12-1114:57borkdude> What about when you have a sequence of values, all of a uniform type? Clojure provides a number of special hints for these cases, namely ^ints, ^floats, ^longs, and ^doubles. https://github.com/clojure-cookbook/clojure-cookbook/blob/master/08_deployment-and-distribution/8-05_type-hinting.asciidoc#2017-12-1114:57borkdudeworks for apply +#2017-12-1114:58borkdudemaybe it’s not supported in a destructuring form#2017-12-1114:58borkdudeI’ll ask in #clojure#2017-12-1115:00borkdudeThis works though:
(defn f [[x y z :as ^longs args]]
    (apply + args))
#2017-12-1115:01borkdudeso I think as long as you’re using the entire sequence, the type hint will work, but not for individually destructured elements#2017-12-1115:19borkdudeTurns out + doesn’t need the type hint, so it’s bogus anyway#2017-12-1115:23borkdudeThis is a bit funny. This give a type hint warning:
(defn f [[x y z]]
  (+ x y z))
but this doesn’t
(defn f [[x y z]]
  (apply + [x y z]))
#2017-12-1115:24borkdudeI guess because a vector cannot contain primitives anyway#2017-12-1115:25mfikesHmm @borkdude I don't get a reflection warning on your first form (in Clojure 1.9.0)#2017-12-1115:26mfikesOr, what do you mean by "type hint warning"?#2017-12-1115:26borkdude@mfikes (set! *unchecked-math* :warn-on-boxed)#2017-12-1115:46mfikesAhh, that's cool. By doing (set! *unchecked-math* :warn-on-boxed) you are essentially saying you want the (+ ...) form to use unchecked math (presumably replacing clojure.core/+ with clojure.core/unchecked-add in some way at compile time), but it is warning that it can't actually employ unchecked math because the values are boxed as Object instances? (Which can be fixed by type hinting them.) But in the second form, + is not being compiled—it is being passed in as a higher-order function to apply, so the result is that you get checked arithmetic regardless.#2017-12-1115:48borkdudeaaah 💡#2017-12-1115:54mfikesI'd like to know why you can't make the second form use unchecked arithmetic by changing it to:
(defn f [[x y z]]
  (reduce unchecked-add [x y z]))
#2017-12-1115:55borkdudevectors can’t contain primitives, but not sure if I understand the problem#2017-12-1115:58mfikesOK, so
(unchecked-add Long/MAX_VALUE Long/MAX_VALUE)
but no
(apply unchecked-add [Long/MAX_VALUE Long/MAX_VALUE])
#2017-12-1115:59mfikesAlso no
(let [ua unchecked-add] (ua Long/MAX_VALUE Long/MAX_VALUE))
Compiler chicanery.
#2017-12-1115:59borkdudesame reason as before, inlining doesn’t work with higher order?#2017-12-1116:01mfikesI think this is why Zach wrote https://github.com/ztellman/primitive-math#2017-12-1116:03mfikesI like Zach's intro here https://groups.google.com/forum/#!msg/clojure/d89gjX_5Om8/KgBcIORMGYYJ#2017-12-1116:05borkdudethe lib is now “archived”?#2017-12-1116:11thegeezI finished an alternate solution for day11 that doesn't use a coordinate system https://github.com/thegeez/clj-advent-of-code-2017/blob/master/src/advent/day11.clj#L166#2017-12-1116:19chrisblomcool, so many different approaches#2017-12-1117:20borkdude@thegeez Care to give us the tl;dr explanation?#2017-12-1117:28thegeezreplacement-moves turns two moves into either zero, one or two moves. For instance [:n :s] is the same as doing nothing, [:n :se] is the same as take a single :se step one by one the steps from moves are added to the shortest path, where the added step might undo a previous step, combine with another step into a single step or the step is added#2017-12-1117:31borkdudevery creative!#2017-12-1117:33thegeezThe first version of that took way too long for part two, but now it works#2017-12-1206:26minikomiThat was a neat problem!#2017-12-1206:38grzmUsed a core function I hadn't before 🙂#2017-12-1206:38minikomiwhich one?#2017-12-1206:39minikomiguessing disj#2017-12-1206:39grzmtree-seq#2017-12-1206:39minikomiooh nice#2017-12-1206:39minikomilink?#2017-12-1206:40grzmSoon. I'm cleaning up my cljs port#2017-12-1206:40minikomihaha no problem#2017-12-1206:43grzmhttps://github.com/grzm/advent-of-cljc/blob/master/src/main/com/grzm/advent_of_code/advent_2017/day_12.cljc#L22-L29#2017-12-1206:44minikominice, similar to mine but I did it manually 😛#2017-12-1206:45minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day12.clj#L27-L34#2017-12-1206:45grzmI'm not too strong at graph work. I took some time to look for something that could do it for me 🙂#2017-12-1206:46spfeifferIts amazing and terrifying at the same time what clojure core has to offer…#2017-12-1206:47grzmI'm working through the Anki deck to try to keep it at hand.#2017-12-1206:48grzmLike peek and pop in @minikomi’s solution: wouldn't use it because they're not something I'm readily aware of.#2017-12-1206:49minikomioh, guess we can just assume that all programs have an entry#2017-12-1206:49minikomino need to join in the right hand side#2017-12-1206:51grzmYeah, that was a double-edged sword, I think. You could end up walking in a circle if you didn't keep track of what you'd already seen.#2017-12-1206:57minikomiI wonder if there's a better idiom for (filter #(not some-set %) items)#2017-12-1206:57grzm(remove some-set items)#2017-12-1206:58minikomioh yeah lol#2017-12-1206:58grzmOnly 22 hours remaining…#2017-12-1207:42borkdudeToday was easy (although mine isn’t as fast as @grzm’s!)#2017-12-1207:48borkdudeI may have killed an elve who was sitting on my CPU today.#2017-12-1208:06fellshardThere is a useful data structure that makes this almost trivial!#2017-12-1208:09fellshardIf you want to dig deeper but don't want full spoilers, I'd recommended reading up on Connected Components in graph theory#2017-12-1208:09fellshardIt's not too rough, thankfully 🙂#2017-12-1208:36borkdudehttp://jgrapht.org/ 😉#2017-12-1209:04fellshardYep, found the exact functions that will answer these questions in seconds flat#2017-12-1210:35borkdudeBtw, @fellshard, did you perhaps mean data-prioritymap?#2017-12-1214:53mfikesI wonder if @fellshard was referring to this one https://en.wikipedia.org/wiki/Disjoint-set_data_structure#2017-12-1208:41orestisI didn’t implement my own graph for this; ubergraph for the rescue. https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day12.clj#2017-12-1208:43orestisI have to implement a hairy layout algorithm for work today; don’t have the time to actually implement a graph algorithm!#2017-12-1208:44borkdude@orestis Cool, didn’t know about ubergraph. Thanks.#2017-12-1208:44orestisI’ll time my solution, just for laughs.#2017-12-1208:46orestis150-200ms to the answer for part 2, which is then a filter away to give the answer to part 1.#2017-12-1208:47borkdudepretty good#2017-12-1208:48orestisTo my shame, I admit I tried various functions of ubergraph.alg until I found something that seemed to a useful result.#2017-12-1209:05minikomi
advent.2017.day12> (c/quick-bench (solve2 input-raw))
Evaluation count : 78 in 6 samples of 13 calls.
             Execution time mean : 8.241557 ms
#2017-12-1209:14minikomihttps://github.com/sciyoshi/advent-of-rust-2017/blob/master/src/day12/mod.rs wow, rust has funky tools to use#2017-12-1209:52fellshardGuh. The documentation for jgrapht is abysmal.#2017-12-1209:52fellshard#2017-12-1210:01fellshardAlways highlight the entrance points to your library in big, bold letters. Same issue I had when I was working with Google Dataflow / Apache Beam for a client.#2017-12-1210:29borkdude@fellshard link to your solution?#2017-12-1211:25thegeezDay 12 with Datascript: https://github.com/thegeez/clj-advent-of-code-2017/blob/master/src/advent/day12.clj#2017-12-1211:32borkdude@thegeez cool! is it fast?#2017-12-1211:37thegeezfast enough, part 1 224ms, part 2 1.4seconds. both including parsing input, but not slurping input#2017-12-1211:59bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day12.clj#2017-12-1212:02bhauman@minikomi (filter (complement myset) stuff)#2017-12-1214:58mfikesThe definition of remove is essentially (filter (complement pred) coll)#2017-12-1212:03bhaumanI find complement set comes in pretty handy, as well#2017-12-1213:50borkdude@bhauman just out of curiosity, how fast is your part 2?#2017-12-1213:51bhaumanoh like 800ms#2017-12-1213:51borkdudeand why did you need disj here? https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day12.clj#L16#2017-12-1213:51bhaumana tiny optimization#2017-12-1213:51borkdudeIt seems the input didn’t have x -> y z x?#2017-12-1213:52bhaumanmy input did#2017-12-1213:52bhaumanx -> x#2017-12-1213:52bhaumanx -> x y z#2017-12-1213:52borkdudeah, it did? hmm I should look into mine then#2017-12-1213:55bhaumanit really doesn't need to be there, as it doesn't have a big affect, it only doubles the leaf step#2017-12-1213:57borkdudeah yes, there are many of them, now I printed them, e.g. 1991 (439 1991)#2017-12-1214:19borkdudeSPOILER in thread#2017-12-1214:19borkdude@bhauman I didn’t know tree-seq could do this, amazing.#2017-12-1214:20borkdude
(tree-seq
   (constantly true)
   {0 #{2 3}
    2 #{4 5}
    3 #{6 7}}
   0)
how does it see this as a tree? I don’t understand it yet.
#2017-12-1214:25minikomiThe second function converts a value to children 0 comes in, you get children 2 and 3 2 and 3 come in, they give 4 and 5; and 6 and 7 respectively.#2017-12-1214:26borkdudeah, so the second arg is also a function, let’s see#2017-12-1214:30borkdudeso normally you pass in a tree, but now only the number 0 is used as the “root” of the tree. then children are looked up in this “tree” by (children 0) which is then the tree which is walked. This is brilliant.#2017-12-1214:34bhaumansorry, was making breakfast but yeah tree-seq is powerful#2017-12-1214:57borkdudeyeah. we are relying on the fact here that branch? can be side-effecting (to do the atom bookkeeping), but it’s probably a safe assumption#2017-12-1214:59borkdudetree-seq really a short/simple function#2017-12-1214:21mfikesMy day 12: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_12.cljc#2017-12-1214:30grzm@borkdude the quick-bench for part-2 was wrong. copy-paste error late at night. I get 25-29ms for part-2.#2017-12-1214:30borkdudevery nice#2017-12-1214:31borkdudeMy mind is blown by @bhauman’s solution. 💡#2017-12-1214:45mfikes@grzm Nice solution! Only suggestion I'd make is to use a volatile instead of atom in prog-group.#2017-12-1214:46grzmThanks! And thanks for the pointer.#2017-12-1214:47grzm@bhauman I like how you pulled seen into the tree-seq branch? function#2017-12-1214:49grzm@mfikes Doesn't seem to do much in terms of performance, at least for this problem.#2017-12-1214:50grzmWould there be another reason to prefer volatile over atom?#2017-12-1214:52bhaumanI used a volatile for a second but then thought that there is no reason that tree-seq couldn't be run in parallel and so preferred atom#2017-12-1214:55grzmMaybe next year I'll focus on reducers/fork instead of transducers 🙂#2017-12-1214:56borkdude@grzm why?#2017-12-1214:56grzmJust to learn/reinforce another area of the library. To be able to choose the right tool for the job I at least need to know what tools are out there. Right now I've got big holes in my knowledge of the core library.#2017-12-1214:59grzmAre these times right? Are people really solving this in less than 3 minutes? https://adventofcode.com/2017/leaderboard/day/12#2017-12-1215:00mfikes@grzm Nah, volatile is only better than atom for perf reasons. So it may become an idiom to use volatiles for local function state and atoms for defs. (Essentially a thing where you don't think about it.)#2017-12-1215:00grzmThat makes sense.#2017-12-1215:09mfikesFor those curious, the algorithm I'm using comes in at 10.6 ms for part 1 and 11.4 ms for part 2 if you exclude the I/O and parsing (and apply the algorithm to parsed data)#2017-12-1215:10mfikes(It is easy to convert that algorithm from a functional one to an imperative one that bashes on a mutable array and I think that works much more quickly.)#2017-12-1215:11mfikesI didn't invent the algorithm. It is a popular one from 1964.#2017-12-1215:33fellshardhttps://github.com/armstnp/advent-of-code-2017/blob/master/src/advent_of_code_2017/day-12.clj https://github.com/armstnp/advent-of-code-2017/blob/master/src/advent_of_code_2017/day-12-union-find.clj https://github.com/armstnp/advent-of-code-2017/blob/master/src/advent_of_code_2017/day-12-jgrapht.clj#2017-12-1215:38borkdude@fellshard Is jgrapht any faster than the others?#2017-12-1215:40fellshardI haven't benched anything yet 😅#2017-12-1215:41fellshardI'd expect union-find to be fastest, if only by dint of skipping the graph entirely. Union-find has inverse-Ackermann amortized performance.#2017-12-1215:41fellshardAKA 'effectively constant'#2017-12-1215:59mfikesIf you do a mutable union-find, part 1 comes in at 539 µs for me and part 2 at 1.12 ms.#2017-12-1215:59mfikesHere is the code that I benchmarked to produce those numbers: https://gist.github.com/mfikes/fc2e94db229b53d68f243cd7b8c253b5#2017-12-1216:01mfikesAs above, this excludes the I/O and parsing#2017-12-1216:06fellshardYeah, that's one thing I noted - the union-find library I picked up has no capacity to leverage the bind-to-root optimization you'd normally use. So I suppose that makes its perf more like log(n).#2017-12-1216:19mfikesUnion-find seems like a good example of an imperative algorithm from the 60s-70s which is difficult to efficiently express in a functional way.#2017-12-1216:19mfikes(I haven't found a way to write it in "normal" Clojure that runs as fast as bashing on arrays.)#2017-12-1216:26fellshardYou could always pass the tree back with every operation. Perhaps hiding it behind an atom would allow you to make modifications that are 'effectively immutable'?#2017-12-1216:26fellshardTrust the contract to hold properties, I guess, with a dash of testing for certainty#2017-12-1216:47mfikes@fellshard I am passing the tree back. Perhaps it is the case that I have a functional version that has the same computational complexity and I’m just seeing a constant overhead associated with working with persistent data structures. I’m going to scrutinize it a bit more. Here it is for reference https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_12.cljc#L19-L37#2017-12-1216:52mfikesI’m going to see if that can be written with transients instead.#2017-12-1218:03mfikesWell, the good news is that it is possible to get part from 10.6 ms down to 1.35 ms by using transients, which compares well to the imperative version that runs in 539 µs. https://gist.github.com/mfikes/c4cf04d10bbfc8c2862fe15a58642501#2017-12-1218:40grzmcrikey, @mfikes. (Or should I say fikey?) That's impressive.#2017-12-1219:03borkdudehttps://xkcd.com/356/#2017-12-1219:51borkdude@mfikes what is the name of the 1964 algorithm?#2017-12-1219:52mfikesI call it union-find, but it has other names https://en.wikipedia.org/wiki/Disjoint-set_data_structure#2017-12-1219:57borkdudecool, thanks. you learn a lot from these nerd snipes 🙂#2017-12-1302:00grzmhttps://twitter.com/ericwastl/status/940754075011960832#2017-12-1302:54minikomiNice.. I went from 10ms to 3ms using (and working around) a transient set in the hot loop#2017-12-1305:44Miķelis VindavsI wonder if there’s a nice O(n) solution to part2#2017-12-1306:05grzmI suspect there is. I think I need to sleep before I finish part 2 😕#2017-12-1307:03minikomiyeah there's a better way to do this I think.. it's taking a loooong time otherwise#2017-12-1308:10minikomiooh, came up with a relatively quick answer using not-any? and some#2017-12-1308:10minikomiI bet there's a way you can just generate the answer using LCD's#2017-12-1308:11fellshardI was thinking the same thing, except I'm not sure that gets you the right answer still#2017-12-1308:12fellshardIt could certainly help you find one point in time at which all the scanners would be at zero at the time your packet arrives, but I'm not sure that would be useful information, nor would it be guaranteed to be the minimum possible result#2017-12-1308:25minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day13.clj#L39-L48 here's mine anyway!#2017-12-1308:42orestisOK, this is the first time in AoC 2017 that my fans are spin-spin-spinning and I get no response from second part.#2017-12-1308:42orestisTime to do the simplest optimizations.#2017-12-1308:55orestisI’m sure there’s an algebraic way to solve this with no code whatsoever…#2017-12-1308:57orestisUsing cycle was probably not a good idea 🙂#2017-12-1309:43orestis“Elapsed time: 536598.496201 msecs”#2017-12-1310:17minikomiExecution time mean : 1.755792 sec#2017-12-1310:18orestisI dropped it to 8500msec and I need to get to real work 🙂#2017-12-1310:18orestisYou can see all my progress in the same file: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day13.clj#2017-12-1310:19orestis…but I do have to look at @minikomi’s code first 🙂#2017-12-1310:21orestis@minikomi I think we arrived at the same logic but your version is a bit more “unrolled” than mine.#2017-12-1310:22minikomiyeah, not-any? was the key thing i did to speed it up#2017-12-1310:30orestisWhat’s your answer? Mine is close to 4 million…#2017-12-1311:37minikomi3875838#2017-12-1310:22minikomiAs soon as there's a zero-case. you can go onto the next one.#2017-12-1310:32orestisI think that some should be equivalent in terms of performance with not-any? though.#2017-12-1310:36karlisIt Should be: https://github.com/clojure/clojure/blob/clojure-1.9.0-alpha14/src/clj/clojure/core.clj#L2682#2017-12-1310:36orestisNice 🙂#2017-12-1313:59mfikesDay 13: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_13.cljc#2017-12-1314:05mfikesI wonder if there is an efficient solution to part 2 using some variation of the Chinese remainder theorem.#2017-12-1315:26bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day13.clj#2017-12-1315:26bhauman6673ms for part 2#2017-12-1315:28bhauman@mfikes very nice solution for day13!#2017-12-1315:28mfikesThanks! It luckily seems to perform well (around 800 ms for my data)#2017-12-1315:33bhauman@mfikes yeah you really don't have any intermediate data structures#2017-12-1315:33bhaumanexcept for the last call to some#2017-12-1315:40mfikesInteresting. I didn't even think about that aspect. I just wrote it for readability / concision.#2017-12-1315:42bhaumanour solutions are similar, you moved the logic a step deeper which eliminated the need to pass data around#2017-12-1315:50bhaumanoh and I'm wasting cycles iterating through the count of the structure#2017-12-1317:33grzm\mutters read the instructions. read the instructions. read the instructions#2017-12-1317:46mfikesDon’t get caught ignoring the instructions.#2017-12-1317:48grzmWell played, sir. Well played.#2017-12-1318:50grzmWell, down from 21 seconds to 900ms for part 2. Now to see what solutions you guys came up with.#2017-12-1318:51grzmhttps://github.com/grzm/advent-of-cljc/blob/master/src/main/com/grzm/advent_of_code/advent_2017/day_13.cljc#2017-12-1319:17orestisWhere does some-fn come from?#2017-12-1319:18orestisOh dear, it’s a core function…#2017-12-1319:26orestisI got thrown by the home-fn naming 🙂#2017-12-1318:56grzm@mfikes is there a way you're preventing the github banner thing from displaying when you paste a link? That's really nice and tidy.#2017-12-1318:59grzmWow, that's a nice, concise solution.#2017-12-1320:17borkdudeok, finally done…#2017-12-1320:17borkdudehttps://github.com/borkdude/aoc2017/blob/master/src/day13.clj
#2017-12-1320:17borkdude2s for part 2#2017-12-1320:25mfikes@grzm After pasting a link, you’ll see a little delete button next to the GitHub banner.#2017-12-1320:31grzm@mfikes cheers.#2017-12-1320:35grzm@borkdude did your util/find-first function miss the commit?#2017-12-1320:36mfikes(I didn’t see it in there either FWIW.)#2017-12-1320:38grzmI like reading what others find useful to abstract away.#2017-12-1320:52borkdude@mfikes Sorry, fixed. See comment at the bottom why I used it.#2017-12-1321:01borkdudeNo idea why some was slower for me than that custom function#2017-12-1321:24borkdude
(defn find-first
  [pred vals]
  (reduce
   (fn [_ v]
     (when (pred v)
       (reduced v)))
   nil
   vals))
(time (some       identity (repeat 10000000 nil))) ;; 250 ms
(time (find-first identity (repeat 10000000 nil))) ;; 40 ms
#2017-12-1321:28grzmwow#2017-12-1321:37borkdude
(time (some #(when (> ^long % 10000000) %) (range))) ;; 558 ms
(time (find-first #(> ^long % 10000000)    (range))) ;; 95 ms
#2017-12-1321:40bhaumancalls seq on every iteration#2017-12-1321:42bhaumancalls (when (seq coll)) on every iteration to detect the end of the sequence#2017-12-1321:44borkdudeI guess one more reason reduce is faster because many collections know how to reduce themselves#2017-12-1321:44borkdudebut would there be a reason not to rewrite some using reduce so it’s faster?#2017-12-1321:52chadHello! Im using Advent of Code as a way of learning Clojure and have just created a repo of what I have so far. Thought id post it incase anyone was interested 😃 https://github.com/sandemchad/clj-advent-of-code-2017#2017-12-1321:55borkdude@chad Feel free to add yours to this one too: https://github.com/adventofcode-clojurians/adventofcode-clojurians#2017-12-1322:02chadAwesome will do 🙂#2017-12-1321:59borkdude@mfikes holy crap, I just saw yours and it’s so concise#2017-12-1321:59bhauman@borkdude I changed my some implementation to reduce and nothing changed#2017-12-1321:59mfikes@chad Nice solutions, especially given you are learning#2017-12-1322:04chadThank you 🙂 I am really enjoying using Clojure solving these problems have been a really good way of learning.#2017-12-1321:59borkdude@bhauman what if you execute above snippet? same timing?#2017-12-1322:00mfikes@borkdude Honestly, I think I just got lucky. I wrote what seemed straightforward, and by luck of the dice, it was short and fast. Doesn’t happen all the time. 🙂#2017-12-1322:01bhauman@borkdude I get similar results and it makes sense now that I look at your example#2017-12-1322:01bhaumanmore closely#2017-12-1322:05borkdudehttps://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day13.purs#L43#2017-12-1401:47minikomiWay too busy for today’s drop.. good luck folks#2017-12-1405:45fellshardWell, well. This day's uses a couple of old friends.#2017-12-1406:13dyankowskyyeah, I had to go back to my day10 solution to improve its performance#2017-12-1406:14dyankowskytransients!#2017-12-1407:30borkdudeAm I missing something? I think (row "flqrgnkx" 0) should return 11110000 although their example grid shows different?#2017-12-1407:37borkdudeThis works though: (= “10100000110000100000000101110000” (row “a0c2017" 0))#2017-12-1407:41borkdudeoh, wait… https://i.imgur.com/Wyl57tE.jpg#2017-12-1412:36borkdudeHorrible: I guessed the right answer for part 2 by offsetting it to the example and the wrong output for that one…#2017-12-1412:37borkdudebut I still have to fix the code 😛#2017-12-1414:15borkdudeMy day 14 is up: https://github.com/borkdude/aoc2017/blob/master/src/day14.clj#2017-12-1415:31bhaumanmy day 14#2017-12-1415:32bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day14.clj#2017-12-1415:32bhaumanthank goodness for all the perf work done on day 10#2017-12-1415:40borkdude@bhauman Funny, mine is faster for part 2 while I borrowed only your groups function 🙂#2017-12-1415:40borkdudemy part 1 is much slower though#2017-12-1415:41borkdudenot sure if it’s my input or something in my code.. looks about the same#2017-12-1415:41bhaumanyeah get-in is killing me#2017-12-1415:42borkdudeoh day 10 optimizations, sorry I thought day 12#2017-12-1415:42borkdudeyeah, I didn’t optimize day 10#2017-12-1415:42bhaumanalso my neighbors function could be improved for speed#2017-12-1415:43bhaumanI'm pretty sure the fact that you are using .charAt along with a tuned neighbors function is whats making the difference#2017-12-1415:44borkdudeprobably#2017-12-1415:44bhaumanfor part 2#2017-12-1415:44bhaumancl-format is killing you on part 1#2017-12-1415:44bhaumanits a dog yo#2017-12-1415:44borkdudethe type annotations didn’t matter very much though#2017-12-1415:46borkdude@bhauman why is there an 8 here instead of 4? https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day14.clj#L14#2017-12-1415:46bhaumanalso remember your hardware is showing up consistently faster than mine#2017-12-1415:47bhauman16 numbers#2017-12-1415:47borkdude@bhauman I’m on a Macbook Pro 15" 2015#2017-12-1415:47bhaumanwell its faster than mine 🙂#2017-12-1415:47bhaumanmid 2014#2017-12-1415:48borkdudeI bought it just before the new Macbook Pros came out… I wanted to wait, but hell, I just needed one right then#2017-12-1415:48bhauman🙂#2017-12-1415:48bhaumandid you figure out why I use 8 instead of 4?#2017-12-1415:49borkdudeAnyway, thanks you for letting me borrow your groups function. I put the credits in the code 😉#2017-12-1415:49borkdudeIt’s one of the most awesome functions I’ve come across so far#2017-12-1415:49borkdudeno, I’d have to start up a REPL to see what’s going on#2017-12-1415:50bhaumanI'm iterating over the numbers not the hex characters#2017-12-1415:51bhauman1 number = 2 hex chars#2017-12-1415:51borkdudeah I see yeah#2017-12-1415:52bhaumanthat probably speeds it up as well#2017-12-1416:03borkdudewith
(transduce
     (comp
      (map #(Integer/parseInt (str %) 16))
      (map #(Integer/toBinaryString %))
      (map #(format "%4s" %)))
     str
     kh)
I get marginal speedup
#2017-12-1416:04borkdudeI’ll leave the optimization for when it’s really needed today#2017-12-1416:05borkdudemaybe (transduce ... str ..) isn’t that optimal, I don’t know it will still use StringBuilders that way#2017-12-1416:09borkdudeGotcha:
boot.user=> (time (do (reduce str (range 100000)) nil))
“Elapsed time: 14011.548079 msecs”
nil
boot.user=> (time (do (apply str (range 100000)) nil))
“Elapsed time: 6.564031 msecs”
nil
#2017-12-1416:13mfikesDay 14: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_14.cljc#2017-12-1416:14borkdudeActually the string thing is not where the most time is spent in my code. It’s the knot hash itself which should be optimized.#2017-12-1416:15borkdudemfikes: great job. Also revisited two previous days 🙂#2017-12-1416:16borkdudeBut for the future it may be good to know:
boot.user=> (time (do (transduce (map identity) str (range 100000)) nil))
“Elapsed time: 13888.143336 msecs”
nil
boot.user=> (time (do (apply str (range 100000)) nil))
“Elapsed time: 6.55865 msecs”
#2017-12-1416:19mfikesIt looks like @cgrand might be joining the fun. He posted yesterday's https://github.com/cgrand/advent2017/blob/master/src/advent2017/day13.clj#2017-12-1416:25mfikesI was miffed that there is a cljs.core/bit-count but in Clojure you need to do interop.#2017-12-1416:38thegeez@borkdude
(time (do (transduce (map identity) str (range 100000)) nil))
  "Elapsed time: 16865.420273 msecs"

  (time (do (apply str (range 100000)) nil))
  "Elapsed time: 14.711439 msecs"

  (time (do (transduce (map identity) net.cgrand.xforms.rfs/str (range 100000)) nil))
  "Elapsed time: 7.697859 msecs"
#2017-12-1416:38borkdude@thegeez expected that to be in there… I might revert my code to the transducer now! 🙂#2017-12-1418:24bhaumanhmmmmm i wonder if Long/bitCount would fail if you happened to get a negative hash number?#2017-12-1418:24bhauman@mfikes ^#2017-12-1418:25bhaumanand congrats on what looks like a very speedy implementation#2017-12-1418:30mfikes@bhauman I suppose for this particular problem it ended up being OK because you permute (range 256) and I have it doing bit-xor chunks 16 at a time. In other words, things stay positive because they fit in long#2017-12-1418:31mfikesAn example:
user=> (advent-2017.day-10/knot-hash-decimal "adfdf")
[72 206 34 163 109 167 172 101 51 5 47 187 155 72 76 57]
#2017-12-1418:33bhaumanhmmmm#2017-12-1418:33mfikes(I cheated a bit by having my day 10 solution provide the underlying vector of numbers.)#2017-12-1418:35bhaumanas did I good sir, as did I#2017-12-1503:28minikomiI started trying to read this as a solution to day14 and my brain started to hurt lol.. need more morning coffee#2017-12-1504:46minikomianother nice use of tree-seq, @bhauman!#2017-12-1504:46minikomii went the loop/recur route again for my flood#2017-12-1505:04grzmIs it wrong that I as someone who likes coding have an aversion to binary numbers? Two days in a row 😞#2017-12-1505:09minikomiuh oh#2017-12-1505:09minikomi40,000,000.. lol#2017-12-1505:20minikomihmm .. xor for speedup maybe?#2017-12-1505:36minikomiok, not too slow.. I'm sure there's room for improvement though!#2017-12-1505:44grzmWow. I love clojure.#2017-12-1506:08fellshardThe binary isn't too bad here, thankfully.#2017-12-1508:34borkdudetoday was easy, luckily#2017-12-1509:02ihabuneki'm learning that lazy sequences are slow#2017-12-1509:02ihabunekand recursion is preferred for this kind of problem#2017-12-1509:02ihabunekbut not as nice to look at#2017-12-1509:05borkdude@ihabunek what kind of performance are you looking at?#2017-12-1509:05borkdudewith lazy seqs#2017-12-1509:07erwinfor me lazy-seq + count is 20 seconds range#2017-12-1509:07borkdudeI got 11 for part 1, 7 for part 2#2017-12-1509:08borkdudeI’m using loop recur + iterate#2017-12-1509:08erwinfor reference: pypy loop with generators is instantaneous #2017-12-1509:09borkdudelike below 10ms?#2017-12-1509:12erwinno, 0.7 seconds for part-2, with pypy day15.py so including startup time#2017-12-1509:15ihabunekI'm getting around 30s for both parts. Using lazy-seq for generators #2017-12-1509:15minikomiI'm getting 7s for first and 5s for 2nd using lazy; ~1s using recursion for first part#2017-12-1509:16ihabunekHuh. Can I see your code?#2017-12-1509:16ihabunekhttps://github.com/ihabunek/aoc2017/blob/master/src/aoc2017/day15.clj#2017-12-1509:16ihabunekMine ^#2017-12-1509:17minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day15.clj#2017-12-1509:18ihabunekHave not used iterate before. Will look into it#2017-12-1509:18minikomigood one to use for these kinds of "feedback" problems#2017-12-1509:20minikomioh, i like your lower-bits fn, stealing that 😛#2017-12-1509:29erwin@minikomi your implementation is not correct#2017-12-1509:29minikomioh?#2017-12-1509:29erwintry it on A: 512 and B: 191#2017-12-1509:29erwinfor part2#2017-12-1509:30erwinshould be 323, yours gives 301#2017-12-1509:32minikomiweird#2017-12-1509:32minikomiwhat's gone wrong?#2017-12-1509:32minikomifor part 1 - 567?#2017-12-1509:33erwinhttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day15.clj#L28 that drop should be on lines 39 and 40#2017-12-1509:35erwinI had the same problem in my code, took me some time to find the problem 😞 (and some attempts typing the wrong answer 8))#2017-12-1509:37minikomiCan you explain conceptually what the difference is?#2017-12-1509:43erwinfirst: part1 is also not correct but, there it doesn't matter, because there is no filtering involved, and the start values do not have the same 16 lower bits. Your (and my) code generates 277, (* 277 16807) and so on, but the start value should not be in the generated steps (check with example in problem). For part 2, the modulo 8 and 4 checks allows the start value for input 512 and the pairs are of by 1 for the complete range#2017-12-1509:43minikomioh, i see, i want to drop the first generated value - since they're seeds and not generated, but by having the drop where i had it, it drops the first filterted generated value#2017-12-1509:44erwinno it compares the wrong values for the complete range#2017-12-1509:53minikomiAh, because 512 gets grouped with the first generated b value.. right#2017-12-1509:46borkdudeBtw, here’s my code: https://github.com/borkdude/aoc2017/blob/master/src/day15.clj I think it could be optimized if I would loop/recurify the ranges as well#2017-12-1509:48minikomiok, moved the drops inside the filters -- fixes the part2 for the seeds you gave#2017-12-1509:48karlisday 15 from me: https://github.com/skazhy/advent/blob/master/src/advent/2017/day15.clj currently ~ 18 seconds for 1st / 10 for 2nd.#2017-12-1509:48minikomijust got lucky with my seeds i guess 😛#2017-12-1509:50erwinI learned that iterate doesn't give (f x) (f (f x)) but x (f x) 🤓#2017-12-1510:55borkdudeSo… it turns out to be this sequence: https://en.wikipedia.org/wiki/Lehmer_random_number_generator#2017-12-1510:58ihabuneknice find#2017-12-1510:59orestisHi all! I had to skip yesterday because I was travelling, but I’m now all caught up. Day 14: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day14.clj Day 15: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day15.clj#2017-12-1511:02ihabunek@borkdude looking at your implementation of multiple-of, what's wrong with (zero? (mod x y)) ?#2017-12-1511:02borkdude@ihabunek nothing, but this is slightly faster 🙂#2017-12-1511:02ihabunekok, i guessed as much 🙂#2017-12-1511:03borkdudeCould be even faster when you inline 4 and 8#2017-12-1511:03ihabunekhm, quick-bench sounds interesting#2017-12-1511:03ihabunekwould partial application be as fast as inlining?#2017-12-1511:03borkdudeno, it would still do the calculation when you call the partial#2017-12-1511:04orestisMy day14 part 2 (flood fill) is at 7 seconds, using mostly plain sets.#2017-12-1511:05ihabuneki "cheated" on day14... used a transient set, and it's well under 1s 🙂#2017-12-1511:05ihabuneki guess localized mutability is ok though#2017-12-1511:06orestisFor today, 5s and 7s.#2017-12-1511:06borkdude@orestis cool. Wonder why my part 2 is faster than part 1, but it may be the input#2017-12-1511:06orestisAh, iterate was what I should use.#2017-12-1511:07orestisI was googleing “clojure reduce infinite sequence” 🙂#2017-12-1511:07ihabunekiterate is my function of the day as well#2017-12-1511:08borkdude@ihabunek Better example:
boot.user=> (defn inc* [x] (println "inc") (inc x))
#'boot.user/inc*
boot.user=> (defn f [x y] (let [x' (inc* x)] (+ x' y)))
#'boot.user/f
boot.user=> (f 1 1)
inc
3
boot.user=> (def g (partial f 1))
#'boot.user/g
boot.user=> (g 1)
inc
3
In other words: partial does nothing for inlining stuff
#2017-12-1511:08ihabunekyes, i understand#2017-12-1511:09ihabunekmakes sense#2017-12-1511:09ihabunekbasically it only binds one of the inputs#2017-12-1511:10borkdudeI wonder if there is a faster way of comparing the lowest 16 bits than (== (unchecked-short ..) (unchecked-short ..)), maybe something using xor, or maybe it already does that on a lower level#2017-12-1511:11ihabuneki think my code is slow because of the way i use sequences more than comparing bits.#2017-12-1511:12ihabunekdoes this slack have a bot which runs clojure code like the irc channel does?#2017-12-1511:12ihabunekcool 😄#2017-12-1511:14borkdude@ihabunek how does that work again?#2017-12-1511:15ihabunek/clj (println 1)#2017-12-1511:15borkdudethanks#2017-12-1511:16ihabunektakes a little while though#2017-12-1511:17ihabunekand now let's try /clj (range) 🙂#2017-12-1511:18ihabuneki'll be good and not do that 🙂#2017-12-1511:19ihabunekusing unchecked-short instead of (bit-and a 0xffff) does nothing for my performance#2017-12-1511:19ihabunekactually, it's slightly worse 🙂#2017-12-1511:20borkdude@ihabunek it’s probably ok#2017-12-1511:20borkdudeoh no…#2017-12-1511:20ihabunekhah#2017-12-1511:21ihabunek😄#2017-12-1511:21borkdudesorry… I can’t remove it…#2017-12-1511:21ihabuneknow you know how to DOS this slack#2017-12-1511:22borkdudewho is the admin of this channel? 😉 @pvinis can you remove the range…#2017-12-1511:24ihabunek@borkdude what do you get by prefixing things with ^long#2017-12-1511:25ihabunekjust so it doesn't use int?#2017-12-1511:25borkdude@ihabunek evaluate the settings from the comment section at the bottom, then you’ll see warnings about boxing#2017-12-1511:25borkdudeso it’s to prevent boxing#2017-12-1511:25ihabunekah, ok#2017-12-1511:29borkdudeTerribly sorry for the long output by range… didn’t know it would consume that much estate… pinging an admin who can remove it.#2017-12-1511:31ihabuneki disovered parinfer for sublime text and don't know how i ever managed to code clojure before that#2017-12-1511:31ihabuneki'm guessing half people here are on emacs#2017-12-1512:08Miķelis VindavsI’m using Cursive in IntelliJ and it also has parinfer#2017-12-1512:09Miķelis VindavsAlthough not the latest and greatest version 3#2017-12-1512:09Miķelis Vindavsbtw here’s my solution for today https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day15.clj#2017-12-1512:28robert-stuttafordall cleaned up 👼#2017-12-1512:28borkdudethanks rob 🙂#2017-12-1512:28robert-stuttafordy’all have fun now - merry conjmas!#2017-12-1512:28borkdudexmas… x for transducers you know 😉#2017-12-1512:29robert-stuttafordxform-mas? 😎#2017-12-1513:07ihabunekswitching between advent of clojure in the morning and python for my actual job is messing with my brain#2017-12-1513:20borkdudeit’s a nerd snipe#2017-12-1514:20orestisNice solution @mikelis.vindavs #2017-12-1514:59bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day15.clj#2017-12-1514:59bhaumanjust went for the straightforward approach today nothing special#2017-12-1515:02borkdude@bhauman still cool!#2017-12-1517:40mfikeshttps://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_15.cljc#2017-12-1517:42mfikesI messed around with macros to get it down to around 236 ms for part 1 and 675 ms for part 2.#2017-12-1518:31mfikesAhh cool. I forgot about unchecked-math and boxing. Fixing that results in 165 ms for part 1 and 295 ms for part 2.#2017-12-1518:45borkdudeVery cool Mike!#2017-12-1518:46borkdudeGood idea to use macros for inlining.#2017-12-1523:00borkdude@mfikes Am I right that the macro approach only helps for inlining var values, but otherwise doesn’t help very much?#2017-12-1610:38mfikesMy initial motivation was to inline the arguments. I think you had also mentioned that inlining the 4 and 8 resulted in faster performance than if they were passed as arguments. I was seeing a similar effect. But var inlining is probably another effect. One odd thing I never figured out was that if I macroexpanded the solution to part 1, the cleaned up expansion inexplicably ran slower.#2017-12-1609:00borkdudeHmz. My program for part 1 works for the examples but somehow not for my real input. I get an answer, but it’s wrong.#2017-12-1609:05theeternalpulsewhat is the answer?#2017-12-1609:06erwindo you somehow have a regex only parsing single digits?#2017-12-1609:37borkdude
[0 1 2 3 4 5 6 7 8 9101112131415]
[a b c d e f g h i j k l m n o p]
[a b c k e f g h i j d l m n o p] :EXCHANGE (3 10) CORRECT
[a b c k e f l h i j d g m n o p] :PARTNER (l g)   CORRECT
[h i j d g m n o p a b c k e f l] :SPIN (9)        CORRECT
[h i j d g m l o p a b c k e f n] :EXCHANGE (6 15) CORRECT
[l o p a b c k e f n h i j d g m] :SPIN (10)       CORRECT  
#2017-12-1609:38borkdudeMy answer is "bfcjlogemipdnakh"#2017-12-1609:44borkdudeMy input: https://github.com/borkdude/aoc2017/blob/master/resources/day16.txt#2017-12-1609:53borkdudeMy parser seems to be correct: when I coerce the parsed tree back to a string and compare to the input, it’s equal#2017-12-1610:03erwin@borkdude with your input, I get a different answer#2017-12-1610:03borkdudethanks#2017-12-1610:15ihabunekoh dear, first part takes 80ms, which is nowhere fast enough for part 2 😄#2017-12-1610:39orestisif you narrow it down to 1ms, it’s still 45 days 🙂#2017-12-1610:40orestisSorry, 11 days.#2017-12-1610:40orestisSo we have to be a bit more clever…#2017-12-1610:40ihabuneki have some ideas...#2017-12-1610:40ihabunekbut need to go out now, will try later#2017-12-1610:42ihabuneki wish i understood macros better 😄#2017-12-1610:17ihabunekit's time to optimize#2017-12-1610:37orestisYarg. Yes 🙂#2017-12-1610:37orestis34msecs here…#2017-12-1610:44noogahttps://repl.it/repls/UnhealthyBeautifulPrairiedog#2017-12-1610:45noogaUnfortunately, this finds the wrong answer and I’m too lazy to figure out why#2017-12-1610:45orestisFor part 1 or 2?#2017-12-1610:45nooga1#2017-12-1610:46val_waeselynckMy solutions to day 16, including an exploration / explanation of the algebraic properties that make part 2 viable https://github.com/vvvvalvalval/advent-of-code-2017/tree/master/src#2017-12-1701:58fellshardDo you have any links to where I can read up on this? I understand how the cyclic nature would lead you to the right answer, but I'm not sure I see how we can assume the dance itself is idempotent.#2017-12-1702:07fellshardOhh, wait. Because the possible permutations operations are limited, there are far fewer than 1e13 operations that can be performed?#2017-12-1610:47nooga@borkdude same here hehe#2017-12-1610:47borkdudeI found the bug btw#2017-12-1610:48noogaI’m still looking for mine, I tested the S, X, P fns and my “parser” seems correct#2017-12-1610:48orestis@nooga Looking at your code, I find something peculiar; do you want to know or want to battle it?#2017-12-1610:48noogabut the answer is wrong :f#2017-12-1610:49noogadon’t tell me, I’m going to figure it out#2017-12-1610:49orestisI don’t have time to battle part 2 at the moment…#2017-12-1610:49noogaand it’s probably something stupid#2017-12-1610:49orestisFrom past experience, this is probably going to be one of those puzzles where a lot of people will drop off; I find no shame in stealing the answer from someone and moving on though 🙂#2017-12-1610:51noogaI still haven’t done day 14, my knot-hash fn is slow and somehow I get wrong answers, too complex to debug for now#2017-12-1610:59noogaah, my S function is totally wrong 😄#2017-12-1611:05erwin@val_waeselynck removed spoiler#2017-12-1611:08val_waeselynck@U052520AT sure, so did I, I just thought some people might also be interested in the math aspects that make this 'reasonable repetition' possible 🙂#2017-12-1611:08val_waeselynckoh, and we might have spoiled the others a bit :s#2017-12-1611:08erwin> since the maximum idempotence exponent for a 16-elements permutation is 5 4 140 I do not understand this part, how do you calculate this?#2017-12-1611:09erwinoriginal message: your explanation for part-2 is difficult to understand ... 😅 I did "dumb" reasoning: the naive implementation is way to slow (8 hours of calculation), lets assume there is reasonable repetition (even though a 16 items permutation is larger then 1.000.000.000), because otherwise this puzzle is no fun 😉#2017-12-1611:11orestisI did a far more naive thing, tried to see if there were repetitions in the states which is somewhat expectable as I calculated at least 10 days of calculations…#2017-12-1611:12orestisAnd indeed I arrived at the 24 + 16…#2017-12-1611:15orestis@val_waeselynck Can you point me to the math concepts/names that you explain in part 2?#2017-12-1611:16orestisI had some initial idea that some instructions might cancel each other out (e.g. the pairings) but I lacked the formal math to prove it.#2017-12-1611:17orestisi.e. my first hunch was to do what you did for “fun” but had no idea how to reason about it. Would love to learn more 🙂#2017-12-1611:19noogamy idea is to find a cycle and basically start from the last one#2017-12-1611:23val_waeselynckSome keywords: Permutations (one-to-one functions of a finite set onto itself), the fact that transpositions and rotations of elements are permutations, the fact that a permutation composed to another permutation is still a permutation, and finally the fact that every permutation can be decomposed into rotations of disjoint support, which is what helps you compute that idempotence exponent (the lowest common multiple of the cycles' lengths).#2017-12-1611:23val_waeselynckNot useful to solve the problem per se, but useful to be confident in the fact that the period will be small#2017-12-1611:28val_waeselynck@U7PBP4UVA @U052520AT ^#2017-12-1611:50erwinthanks#2017-12-1611:55orestisThanks, I will have to dig deeper some time. And I'll also have to see how you did the AOT analysis of the input, as that is a generally useful technique. #2017-12-1612:01val_waeselynck@U7PBP4UVA what I called AOT here was just compacting the steps into 2 permutations, not sure it will be much reusable as it leveraged the same algebraic properties I mentionned above 🙂#2017-12-1702:24val_waeselynck@U1YPTG4UF re: your question, see this thread 🙂#2017-12-1611:10orestisGot it: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day16.clj#2017-12-1612:08noogaha, done#2017-12-1612:18noogahttps://repl.it/repls/UnhealthyBeautifulPrairiedog#2017-12-1612:19noogait crashes this funny repl but works on my machine#2017-12-1612:21noogaI tried to compile the input into something like (fn [initial-state] (-> initial-state (S 1) (X 1 3) ...)) and then evaling it for fun but it just caused a stack overflow in clojure compiler#2017-12-1612:21nooga😂#2017-12-1612:23noogaI could probably get away with series of swap!s on an atom though#2017-12-1613:32mfikesDay 16: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_16.cljc#2017-12-1614:06bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day16.clj#2017-12-1614:11bhauman@nooga your are probably having a cons explosion?#2017-12-1614:12nooga@bhauman where?#2017-12-1614:12bhaumandoes your stack overflow say "lazySeq.Cons" or someting like that?#2017-12-1614:13bhaumanwhat happens is that you can build up too much lazy state#2017-12-1614:13bhaumanand when it finally comes due it explodes#2017-12-1614:13noogano idea, I scrapped this “compiler” function#2017-12-1614:13noogabut I’d suppose that was rather caused by putting too many expressions in ->#2017-12-1614:15bhaumanno its normally from nested lazy seqs that grow to large by the time you start to consume them#2017-12-1614:16bhaumanso basically the code I'm looking at is different from the code you were using earlier#2017-12-1614:17bhaumananyway asking for a billion was a dead give away, it would have been brutal if they asked for something just outside of plausible#2017-12-1614:34grzmokay. I thought I'd just let that run overnight. Still hasn't finished.#2017-12-1614:39borkdudeGreat puzzle today. I have yet to clean up my code.#2017-12-1614:49mfikesYeah, while part 1 can be tedious, it is straightforward. Part 2 had nice characteristics.#2017-12-1616:20borkdudehttps://github.com/borkdude/aoc2017/blob/master/src/day16.clj#2017-12-1616:25borkdudeMy InstaParser is a bit slow (~850ms). Wonder how long your folks’ parsing takes?#2017-12-1616:30borkdudeCould probably optimize it by handwriting it.#2017-12-1616:38nooga@bhauman the code I was talking about looked more or less like this https://repl.it/repls/KookyBestTurkey#2017-12-1617:42borkdudeHand-written parser: ~8ms https://github.com/borkdude/aoc2017/blob/master/src/day16.clj#L119#2017-12-1620:01grzmInteresting. I've got a solution which works for part-1, gives me the correct period for part-2, but not the correct answer for part-2. It's two transpositions off. And it doesn't look like an off-by-one error, as neither solution on either side is correct either.#2017-12-1621:06nooga@grzm I was in the same situation and then I noticed 10e9 instead of 1e9#2017-12-1621:06noogaso it was off by 0 this time 😉#2017-12-1621:08grzm@nooga thanks for an idea to confirm. but that's one off-by-zero that I don't have 😞#2017-12-1621:08grzmI do wish Clojure accepted number syntax like 1_000_000_000 for cases like this.#2017-12-1621:21noogait does accept scientific notation like, well, 1e9 for cases like this#2017-12-1621:22grzmtrue. doesn't help with 1234765890, though#2017-12-1621:23bhaumanI always make the mistake of thinking this syntax exists b/c we have such an awesome reader, but alas I'm always wrong
#2017-12-1621:32grzmHow can it be wrong when it feels so right?#2017-12-1621:54borkdudeAdded a Kern parser implementation for day 16: https://github.com/borkdude/aoc2017/blob/master/src/day16.clj#L115#2017-12-1623:46val_waeselynckNothing like a 26-hours plane trip to catch up on AoC 🙂 I know I'm late to the party, but I wonder what you guys thought of day 11 (Haxagonal Grid)? Did you find it difficult? It took me a lot of head scratching to achieve a clean solution, and even then if feels like it could be simpler (here if you're curious: https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day11.clj)#2017-12-1700:13mfikes@val_waeselynck I did some quick research before solving it and read about the coordinate systems at https://www.redblobgames.com/grids/hexagons/ and found one that seemed to have a simple distance formula. I’m pretty sure that without having done this research it would have taken a lot of thinking to sort through this one. I went with cube coordinates, which seemed to be pretty popular. The solution for me ended up being fairly clean: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_11.cljc#2017-12-1702:26val_waeselynck@mfikes Cool blog! I did not have the option of doing that kind of research as I was on a plane, so I ended up working out some math that are a similar but slightly inferior approach to cube coordinates. I did have to sleep over the problem to come up with this, so definitely not a viable approach if I wanted to be competitive on AoC#2017-12-1717:38thegeezI have a solution to day11 without using coordinates https://github.com/thegeez/clj-advent-of-code-2017/blob/master/src/advent/day11.clj (in the alternative for part 2 and 1)#2017-12-1705:44mfikesDay 17: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_17.cljc#2017-12-1708:37borkdudeHmm, after the state
[[0 2 3 1] 3] ;; s1
I expect it to be
[[0 4 2 3 1] 4] ;; s2
but the example gives 0 2 (4) 3 1
#2017-12-1708:39borkdude3 is the current position of s1. going 3 steps means going to position 0 whereafter 4 will be inserted.#2017-12-1708:43val_waeselynckMy solutions for day 17: https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day17.clj#2017-12-1708:43borkdudeo wait, I don’t have to go back and forth probably#2017-12-1708:55borkdudeGot it.#2017-12-1709:40borkdudeSolved.#2017-12-1709:41borkdudehttps://github.com/borkdude/aoc2017/blob/master/src/day17.clj#2017-12-1710:40noogathese puzzles…#2017-12-1711:17noogaI have a solution that works with the example#2017-12-1711:17noogabut doesn’t with 50M#2017-12-1711:27noogahah, I used wrong input 😂#2017-12-1712:21orestisMy solution for part 1 is slow, no way it can scale to 50M…#2017-12-1712:53orestisBah. Still too slow for my tastes.#2017-12-1713:48fellshardIt's another one that's asking you to dig into the math of it#2017-12-1713:48fellshardOr, at least, to find a simplifying pattern#2017-12-1713:54orestisI hang my head in shame; I had a limited time to solve this, explored some time looking for patterns, then in the end copied @val_waeselynck algorithm.#2017-12-1713:54orestisI was looking for some mathematical properties, cycles and so on; but I found too many 🙂#2017-12-1713:55orestisHere’s my exploration, warts and all if anyone is interested: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day17.clj#2017-12-1713:58orestisIn my case, I found that 0 is always at the end; therefore the value I care about is always going to be first.#2017-12-1713:59orestisI’m not sure if this is what the requirements say; i.e. do they care for the first element after the value 0 or the element at the 0 position? Is it the same for all the inputs?#2017-12-1714:03orestisBTW, some eval’ed comments there are stale; I was tweaking things in the editor a lot.#2017-12-1715:43grzmThey're looking for value (get buf 1)#2017-12-1716:01bhaumanwell my second part should finish in 6 minutes#2017-12-1716:02bhaumanI'm finished with mine but again I'll have to wait for 6 minutes to pass to be sure#2017-12-1716:04bhaumanlooked for patterns but just couldn't swing it, so I optimized the heck out of the data structure and the transitions#2017-12-1716:11bhaumanwell the answer was correct at least#2017-12-1716:18bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day17.clj#2017-12-1716:25bhaumanoh position zero has a special property that the rest don't have ...#2017-12-1716:26bhaumanwell that would have been easier, nice work @val_waeselynck#2017-12-1716:41mfikes@bhauman Still, it is remarkable that you were able to come up with an imperative version that could solve it by brute force.#2017-12-1717:05borkdudeMine runs in 2s 🙂#2017-12-1717:08borkdudeIn part 1 I lost time because I thought you should run back and forth in the buffer instead of cyclic. Doh…#2017-12-1717:19borkdude@bhauman how does yours even work? is this work parallelizable at all? (well yeah, supposedly, but I have to think about it)#2017-12-1717:44bhaumanI used a cyclical datastructure {a -> b, b->c} i.e. a circular linked list which allowed for fast insertion and lookups#2017-12-1717:45bhaumannot really paralizable#2017-12-1717:46dpsuttoncan anyone do me a favor? I'm behind, only on day 7. My friend is taking a flight from SF and wants to do days 10 and 11. Can anyone print those pages with both parts and the answers so he can work on them on the flight and email them to me?#2017-12-1717:46dpsuttonah nevermind. he found them on reddit#2017-12-1717:46dpsuttonsorry for the noise#2017-12-1717:46bhaumancool!#2017-12-1717:47bhaumanno worries#2017-12-1717:48borkdude@bhauman r/reduce applies the function in parallel over the sequence right?#2017-12-1717:48bhaumannope#2017-12-1717:48mfikesOne twist I really liked was Nathan Armstrong's approach of keeping the insertion point at the end of the actual collection representing the circular buffer, thus allowing conj to be used to insert.#2017-12-1717:48bhauman@borckdude it can't as it needs the input from the previous iter#2017-12-1717:49mfikesNathan's approach also means you need not keep track of the current position, if I'm reading his code correctly.#2017-12-1717:50bhauman@mfikes with a circular buffer you don't need to keep track of the last position#2017-12-1717:50mfikesNathan's code, for reference: https://github.com/armstnp/advent-of-code-2017/blob/master/src/advent_of_code_2017/day-17.clj#2017-12-1717:50mfikes@bhauman Exactly. I didn't take that approach.#2017-12-1717:51bhaumanoh sorry,let me look at nathan's ...#2017-12-1717:51mfikesThe main idea is to rotate the representation so that the current position is always at the end of that representation.#2017-12-1717:51borkdude@bhauman let me try it differently: what did you use reducers for specifically?#2017-12-1717:51bhaumanspeed#2017-12-1717:54bhaumanactually I didn't need to use a reducer#2017-12-1717:55borkdudecan you elaborate? if there’s nothing to parallelize, what’s the speed gain?#2017-12-1717:55bhaumanI thought the reducer would treat the range as an iterable#2017-12-1717:55bhaumanand not a lazy seq#2017-12-1717:57bhaumanwhich it think is the wrong assumption, transduce would have done that for me#2017-12-1717:58dpsuttonon second thought, could anyone email me the full page for day 13?#2017-12-1717:59dpsuttonwas trying to find it online for him but no luck#2017-12-1718:01dpsuttonperfect! thanks!#2017-12-1718:02dpsuttonyou'll make a flight of his much better.#2017-12-1718:02bhauman@borkdude inputs?#2017-12-1718:10mfikesI'm curious: Is there a technique that behaves like iterate, but produces something that can reduce itself? The reason I ask is that when running the solutions in ClojureScript, the lack of locals clearing can be worked around by carefully using transducers. By way of an example, you can count this way without blowing out memory:
(transduce (comp (map inc) (filter odd?))
  (completing (fn [c _] (inc c)))
  0
  (range 1e8))
#2017-12-1718:19bhaumanthis is a good question, I'd like to know the answer as well#2017-12-1718:35borkdude@dpsutton if you want an input: https://github.com/borkdude/aoc2017/blob/master/resources/day13.txt#2017-12-1718:35dpsuttonah thanks#2017-12-1718:45thegeez@mfikes something like this for reducible iterate:
(deftype Iter [f init]
  clojure.lang.IReduceInit
  (reduce [this xf xf-init]
    (loop [state (xf xf-init init)
           i init]
      (if (reduced? state)
        @state
        (let [i (f i)
              ret (xf state i)]
          (recur ret i))))))

(comment
  (into []
        (take 10)
        (Iter. inc 0))
  )
#2017-12-1718:50borkdude@dpsutton Why am I sending a PDF if this page is public btw? https://adventofcode.com/2017/day/13#2017-12-1718:51dpsuttonbecause it only shows the first half until you solve it#2017-12-1718:52borkdudeah ok. and now he also has my outcomes + input, so that should do it.#2017-12-1718:52dpsuttonand he's on a flight so he could only see the first half. yeah. he's gonna get the answer himself he just wanted something to work on#2017-12-1718:52dpsuttonand usually the second half is the more interesting half#2017-12-1718:58borkdude@mfikes aren’t iterate results already reducible? https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Iterate.java#L15#2017-12-1718:59borkdudeNot in ClojureScript it seems.#2017-12-1718:59borkdudeFound this link: http://insideclojure.org/2015/01/18/reducible-generators/#2017-12-1719:16mfikesOh, cool @borkdude. Perhaps a patch could land in ClojureScript to make it behave like Clojure 🙂#2017-12-1721:28bhaumanso if I wanted range to be reducible?#2017-12-1721:55bhaumanOK I have explored the sources and I've got my head on straight now, range does know how to reduce itself and this behavior is obvious from how fast it is#2017-12-1722:23val_waeselynck@erwin @orestis @nooga @fellshard Still having fun with Permutations Algebra, I reimplemented day 16 ("Permutation Promenade") without leveraging the cyclic nature of the dance at all, using exponentiation instead: https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day16.clj#L320#2017-12-1722:24val_waeselynckI also added a more "literate style" guide explaining how it all works: https://github.com/vvvvalvalval/advent-of-code-2017/blob/master/src/aoc2017/day16.clj#L146#2017-12-1722:28val_waeselynckI do realize I'm totally over-engineering this btw 😄#2017-12-1722:47bhauman@val_waeselynck am I correct in thinking that this day17 part 2 solution only works in the first position? I don't think it will work other positions as their positions are more easily disturbed?#2017-12-1722:52val_waeselynck@bhauman that is correct, I'm relying on the fact that in my representation of the cyclic data structure, 0 has a stable position#2017-12-1722:58bhaumangot it#2017-12-1723:38Miķelis Vindavs@val_waeselynck nice, looks like I came up with something similar https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day16.clj#L63-L78 Although I unfortunately don’t fully grok the math beneath it, I just experimented around until I confirmed my intuition#2017-12-1801:51val_waeselynck@U89SBUQ4T AFAICT the main difference is that in your solution, compilation consists of composing functions to avoid the cost of navigating data structures, whereas in mine it consists of compacting the steps into a concrete data structure - which is what enables exponentiation#2017-12-1809:21Miķelis VindavsHmm it’s function composition only in the sense that mapping a vector of indices over a vector of indices is composition. I’m compiling the dance down to 2 actions - spin+exchange and partner. They could each be passed to exponentiate to get the nth result#2017-12-1809:21Miķelis VindavsActually I should probably try that :)#2017-12-1822:55val_waeselynckAh right, I guess I misunderstood the code then#2017-12-1723:38Miķelis Vindavsthe optimized log n exponentation part is nice, probably saves even more time if you know which index you need#2017-12-1723:41Miķelis Vindavsyeah, mine still relies on finding the cycle period, with log n application that wouldn’t be needed.. very nice solution & explanation!#2017-12-1723:44Miķelis Vindavsfor example, I haven’t really gotten my mind around why the order of applying the spin+exchange and partner moves matters (that is, (spins (partners state)) is not the same as (partners (spins state)) except at the cycle period#2017-12-1800:03mfikesIs Val's exponentiation somewhat along the lines of saying x^16 = (x^8)^2 = ((x^4)^2)^2 = (((x^2)^2)^2)^2 ? (Thus leading to logarithmic time complexity?)#2017-12-1800:57val_waeselynck@mfikes exactly :)#2017-12-1800:05mfikesThe pre- and post- multiplication aspect is frigging cool too!#2017-12-1802:51bhaumanwow this is really cool#2017-12-1803:30minikomiweekend is done, need to catch up (^_^;)#2017-12-1811:08minikomiaww man, stuck ininfinite loops for 18pt2#2017-12-1811:10orestisDay 18 is fun; I implemented my first multi method for part 1, and I’m tempted to use core.async for part 2 🙂#2017-12-1811:27minikomioh shit.. is it first in first out.. ahhhhhhh#2017-12-1811:27minikomilol#2017-12-1811:28minikomidamn#2017-12-1811:28minikomiok got it#2017-12-1811:29minikomitime to go home#2017-12-1814:36noogahttps://adventofcode.com/2017/day/16 it just struck me that wrapping the function from the part 1 in memoize would be even less work than finding cycles#2017-12-1814:36noogaand it looks like it finishes in 5 minutes, thanks clojure#2017-12-1814:45bhaumanok the instructions are really unclear on this one, does "how many sent" mean "sent and received" ?#2017-12-1814:46borkdudeI’m counting the messages that p1 sends (so not on the queue but sent in total).#2017-12-1814:46borkdudeBut I haven’t finished it yet.#2017-12-1814:46bhaumanyeah I'm counting that and my answer is wrong, too high to be exact#2017-12-1814:46borkdudeMy program doesn’t halt. And when it did it was indeed too high.#2017-12-1814:47borkdudeHow long does yours take to run?#2017-12-1814:47bhaumannot long#2017-12-1814:47bhauman22s#2017-12-1814:47borkdudeok, there must be an error in mine somewhere. I’ll look at it tonight#2017-12-1814:48bhaumanok what about this what if one program comes to and end and the other is still running sending its little heart out#2017-12-1814:49borkdudethat’s not deadlock#2017-12-1814:49borkdudeat least not for both programs#2017-12-1814:50ihabunekdeadlock is reached when both programs are stuck on rcv, so it means they received all messages sent by the other#2017-12-1814:50ihabunekso it shouldn't matter if you count sent or received#2017-12-1814:51ihabunekbut my result is wrong, so what do i know.#2017-12-1815:02mfikesDay 18: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_18.cljc#2017-12-1815:05bhaumanI was counting wrong#2017-12-1815:06bhaumanI was counting messages received let's see if that fixes it#2017-12-1815:14ihabuneklol, i just got: > That's not the right answer; your answer is too high. Curiously, it's the right answer for someone else; you're either cheating, logged in to the wrong account, or got an unlucky guess.#2017-12-1815:15ihabunek^^;#2017-12-1815:15bhaumanI got that too, I was copying your answer though 🙂#2017-12-1815:15ihabunekthis was a total accident#2017-12-1815:15bhaumanyeah me too#2017-12-1815:15ihabunekat least i'm in the right ballpark#2017-12-1815:22orestisBah, I get a too-low number as an answer for part 2.#2017-12-1815:24bhaumanI'm now walking through my instructions step by step, and "everything seems correct"™️#2017-12-1815:37minikomiBe careful of the jumps X value#2017-12-1815:43mfikes@bhauman Given the backlog here, I wonder if there might be a bug in Advent of Code. If your input is available, and you give me the answer you are getting, I could run my code on your input and see if I get the same answer as you. (You could theoretically do the same, but you might not want to be spoiled by seeing any code, or any answers. That last aspect could be fixed by using == instead of having the code emit the answer.)#2017-12-1815:43bhauman@mfikes yeah I'd love that#2017-12-1815:43ihabunekcool,#2017-12-1815:43ihabuneki'll pm you#2017-12-1815:43borkdudeIf there were a bug, it would be a hot topic on Reddit by now?#2017-12-1815:43bhaumangood point#2017-12-1815:43borkdude(didn’t check Reddit yet)#2017-12-1815:44mfikesYeah. Unless lots of people are building up anxiety right now, ready to start posting.#2017-12-1815:44mfikesTo be honest, this problem was sufficiently complex where an error on AoC side seems slightly possible.#2017-12-1815:46bhaumanoutput: 7477#2017-12-1815:46bhaumanreally?#2017-12-1815:49borkdudeHINT#2017-12-1815:51borkdudeok… jgz can also take two ints as operators#2017-12-1815:51borkdudejgz 1 3, I definitely didn’t handle that case. Thanks to this reddit comment: https://www.reddit.com/r/adventofcode/comments/7kkumq/help_2017_day_18_part_2rust_stuck_on_infinite_loop/#2017-12-1815:52ihabuneki discovered that when i got an exception#2017-12-1815:51mfikes@borkdude Spec saved my ass immediately with that particular gotcha#2017-12-1815:52borkdudelong live Spec!#2017-12-1815:52borkdudeIf I’d used a decent parser (non handwritten) I would have discovered it too#2017-12-1815:52bhaumanyeah but > doesn't work very well on 'p#2017-12-1815:53borkdude@bhauman What do you mean?#2017-12-1815:53bhaumanjgz p p#2017-12-1815:53mfikes@bhauman For your input (which differs from mine in only one instruction), I get a lower value of output than 7477#2017-12-1815:54bhaumancool that's what AoC is telling me#2017-12-1815:54borkdude@bhauman That is valid. You should compare p to zero and jump the value of p if p > 0.#2017-12-1815:54mfikesWhat was your part 1 answer, @bhauman I can check that as well#2017-12-1815:55bhaumanmy part 1 answer was accepted at 8600#2017-12-1815:55borkdudeMy part 1 was 3188#2017-12-1815:55mfikesCool. That's what I'm getting on your input as well.#2017-12-1815:56ihabunekok, so it's not a bug, we're just stupid 🙂#2017-12-1815:56bhauman@borkdude I here you I got what you were saying backwards#2017-12-1815:56noogaweird, mine was 8600 as well#2017-12-1815:56ihabunekmine too#2017-12-1815:57ihabunekno idea how many variants of input exist#2017-12-1815:58mfikesThis part 2 is brutal because if you get it wrong, then there isn't much to go on...#2017-12-1815:58bhaumanI looked at @mfikes code and we are basically doing the same thing so the is obviously a wrong assumption in my code#2017-12-1815:58mfikes(I got part 2 wrong a couple of times, but was able to suss it out.)#2017-12-1815:58bhaumanyeah they don't give you a real example program and answer for part 2#2017-12-1815:58mfikesAhh, good point...#2017-12-1815:59ihabunekhaving a very close answer is a pain because it's not obvious what's wrong#2017-12-1815:59mfikes@bhauman Since you looked at my code, you can also diff your input with mine. Up to you.#2017-12-1816:00mfikesI don't see how that diff would provide much of a clue... hmm#2017-12-1816:00bhaumanthanks, well I would have an example program and output to target#2017-12-1816:00mfikesTrue 🙂#2017-12-1816:00bhaumanso I'm not just chasing nothing#2017-12-1816:07bhaumanoh I think I found it#2017-12-1816:12bhaumanits a very very clojure trap to fall into#2017-12-1816:12mfikesPlease. I'm really curious now.#2017-12-1816:15noogahttps://repl.it/repls/CompassionateGroundedHalicore this is my 1st part#2017-12-1816:19orestisAh! Read the requirements, the p register is not that special…#2017-12-1816:21ihabunekit's just pre-populated#2017-12-1816:21orestisYep; I misread that somehow as “it resolves always to 0 or 1”.#2017-12-1816:21orestisMy day 18: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day18.clj#2017-12-1816:26orestis@mfikes Ah, clojure.lang.PersistentQueue - this doesn’t show up on my Dash doc viewer…#2017-12-1816:27mfikes@orestis Yes. I wonder if Clojure will get a reader tag for it like ClojureScript has.#2017-12-1901:13minikomiWow, that’s neat.. I also made three mistake of using a vec with peek/pop and getting stuck for ages until I realized the queues were fifo and not like a stack 😑 #2017-12-1816:29mfikes^ https://dev.clojure.org/jira/browse/CLJ-976#2017-12-1816:30orestisI was looking for a way to do an atomic pop-and-return-value, that would return [head, rest-of-coll] — I initially thought of running the two programs in two threads and use some of Clojure’s concurrency constructs, but I don’t know enough and it seemed a bit fiddly.#2017-12-1816:31bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day18.clj#2017-12-1816:32bhaumanI won't spoil it by saying what hung me up but feel free to message me if you want to know#2017-12-1816:33borkdude@orestis you can use compare-and-set for that… I tried it, but my program isn’t working yet 🙂#2017-12-1816:33borkdude@bhauman Feel free to put a HINT in a thread under this message#2017-12-1816:34bhaumanHINT#2017-12-1816:35bhaumanmy problem was a common clojure problem#2017-12-1816:35bhaumanI was using a vector for an input-queue#2017-12-1816:36bhaumanand using conj to append to the end#2017-12-1816:36bhaumanbut then the queue type got flipped to a seq#2017-12-1816:36bhaumanand then conj started adding to the front#2017-12-1816:36borkdudehmm, I used a PersistentQueue for that#2017-12-1816:37orestisThat is so annoying. I thought of that, and in the end just used (vec (rest ..))#2017-12-1816:37borkdudeIs PersistentQueue somehow not valid for this problem?#2017-12-1816:38mfikes@borkdude That's what I used#2017-12-1816:38bhauman@borkdude just not needed in my implementation#2017-12-1816:38borkdudeok, phew… my program still won’t terminate… annoying.#2017-12-1816:38bhaumanmy runtime is 500ms#2017-12-1816:38orestisI couldn’t figure out a way to make the two program communicate cleanly what with the circular dependency; I took a different approach.#2017-12-1816:38orestisYes, it should end within 3-4 seconds…#2017-12-1816:38mfikes@borkdude I was hypothesizing: If you implement it with threads, is a potential outcome a bona fide deadlock.#2017-12-1816:39borkdudeI didn’t do threads. To make it easy on me I started using two atoms with a PersistentQueue in each which are shared with both programs.#2017-12-1816:39bhaumanpersistent queue is better for this#2017-12-1816:40borkdudeI first had an algorithm which exchanged the queues after each iteration, but since that didn’t work I turned to atoms.#2017-12-1816:40bhaumanI'm still doing stepwise evaluation in mine#2017-12-1816:40borkdudeI had some stupid mistakes like not setting the init value properly and things like that. There might still be something like that in there.#2017-12-1816:40orestisI took a hint from the puzzle description, and run the programs one-by-one until they block…#2017-12-1816:40bhaumanright on that's my approach#2017-12-1816:41mfikesI wonder if there is a name for that approach. Greedy zig-zag?#2017-12-1816:41borkdudeThis is what I’m trying right now: run program 1 until it’s waiting, then turn to program 2, etc. until they are both waiting.#2017-12-1816:41borkdudeShould work right?#2017-12-1816:41bhaumanoh I'm not doing that#2017-12-1816:42borkdudeSince the speed is arbitrary it should be valid.#2017-12-1816:42bhaumaneach program gets one instruction evaluated each step#2017-12-1816:42borkdudeThey are not running on their own instruction set?#2017-12-1816:43bhaumanyes each program runs its own set#2017-12-1816:43borkdudeyeah#2017-12-1816:43bhaumanor rather each has its own program-counter#2017-12-1816:43borkduderight, the instructions are immutable, but each has their own counter#2017-12-1816:45mfikesBruce, is it fair to say your queue s are of length 1?#2017-12-1816:45mfikesHmm. Maybe not... still trying to grok it.#2017-12-1816:46bhaumanonly my output-queue#2017-12-1816:46mfikesAhh, I see how you pull an item off the front of the vector.#2017-12-1816:47mfikesInteresting. So you have 4 queues.#2017-12-1816:47bhaumanreally only two#2017-12-1816:47mfikesCool. 2 of them are just temporary buffers#2017-12-1816:47bhaumanoutput-queue is a misnomer#2017-12-1816:48bhaumanshould be output-message#2017-12-1816:48mfikesYeah, maybe output-port of somesuch#2017-12-1816:48bhaumanyeah#2017-12-1816:49bhaumanI like that the states of the to programs are separate and then cross pollinated in a separate step#2017-12-1816:49orestisI get the correct answer by doing that zig-zag; run 0 until blocks, then 1 until blocks. The logic to detect the deadlock is a bit gnarly though.#2017-12-1816:50mfikes@bhauman Was your bug right on this line? https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day18.clj#L85#2017-12-1816:51bhaumannope here:#2017-12-1816:51bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day18.clj#L91#2017-12-1816:51bhaumanI skipped the fnil#2017-12-1816:51mfikesOuch. Harder to see that one.#2017-12-1816:53bhaumanif I'd just had the habit of using a persistent-queue it wouldn't have been a problem#2017-12-1816:54orestisIsn’t this a prime candidate of where a persistent data structure is more trouble? Because you need to make sure that both references point to the updated one.#2017-12-1817:27fellshardI considered moving my solution to a linearized version just to see how the solution works itself out differently. I ended up running both programs in parallel at each step, then syncing outputs of each into each other's queues to conclude the step.#2017-12-1816:41ihabuneki'm a colossal idiot.#2017-12-1816:42ihabunekprograms are 0-indexed#2017-12-1816:42ihabunekso "program 1" is the second program#2017-12-1816:42ihabuneki was calculating the value for first#2017-12-1816:42mfikesI made that mistake, FWIW 🙂#2017-12-1816:42ihabunek😢#2017-12-1816:42ihabuneki lost over an hour 😄#2017-12-1816:43ihabuneksorry, should this have been under a HINT?#2017-12-1816:43bhaumanI don't think so#2017-12-1816:44bhaumanI'm in the dunce club as well#2017-12-1816:48orestisSimilar to my dynamic rebinding dance so that p always evaluated to 0 or 1, rather than been just propulated. 45 minutes 🙂#2017-12-1816:53mfikesYeah, that p thing was a bit odd.#2017-12-1816:54bhaumanits how they got different behavior from the same program#2017-12-1816:54mfikesPerhaps it is what makes the programs follow a different path?#2017-12-1816:55mfikesCool. The use of p while also using the words “p rogram ID” probably caught a lot of people off guard if you don't read the description carefully.#2017-12-1817:03borkdudeI didn’t read this properly: > Once both of your programs have terminated (regardless of what caused them to do so) This means that not both programs have to be deadlocked…#2017-12-1817:05orestisThe only other case where a program terminates is when it jumps before or after the instruction list; so then the other keeps on going. But to be honest in my input both programs end up as blocked.#2017-12-1817:06borkdudeyeah, I would get an exception if that would happen#2017-12-1817:08mfikesYes me too.#2017-12-1817:04borkduderight?#2017-12-1817:05mfikesWell, one could fall of the end of the instruction range....#2017-12-1817:05mfikesIt is interesting if you look at https://adventofcode.com/2017/stats and calculate the percentage of participants who haven't completed part 2 for each day:
{1 16,
2 14,
3 26,
4 9,
5 4,
6 4,
7 23,
8 2,
9 2,
10 9,
11 3,
12 3,
13 9,
14 8,
15 2,
16 11,
17 7,
18 39}
#2017-12-1817:06mfikesSomething was up with day 7#2017-12-1817:07mfikesAhh right, day 7 involved some tricky math mixed with recursion#2017-12-1817:07mfikesI think that one had the highest missed guess rate for me, and I ultimately solved it by hand before successfully writing proper code for it.#2017-12-1817:08ihabunekday 3 was tricky as well, i remember my group of friends had trouble solving it#2017-12-1817:09ihabunekfortunately, i had solved something similar recently doing the python challenge#2017-12-1817:10mfikes@borkdude Do you end up with both programs going into a waiting state, or do they just keep running indefinitely?#2017-12-1817:11borkdudeThis is my output before I cancel execution:
1 waiting...
1 waiting...
1 waiting...
1 waiting...
1 waiting...
1 waiting...
1 waiting...
1 waiting...
1 waiting...
1 waiting...
1 waiting...
boot.user> 
#2017-12-1817:12mfikesThat means that program 1 is waiting?#2017-12-1817:12borkdudeyes (program 0 is still running)#2017-12-1817:13mfikesThat would seem to imply program 0 is running but never sending.#2017-12-1817:13mfikes(Like an infinite loop without a snd instruction.)#2017-12-1817:14borkdudehmm yes…#2017-12-1817:15ihabunekwhat if you just run program 0 until it blocks for the first time? does that ever happen?#2017-12-1817:15borkdudegoing to test..#2017-12-1817:16orestisDumping the queues at every step also helps. #2017-12-1817:16borkdudeI’m printing the buffers now. ^#2017-12-1817:16borkdudeit seems buffer 0 is not properly filled up#2017-12-1817:17borkdude(the one program 1 should read from)#2017-12-1817:19borkdudeThis is obviously very wrong:
p0 is writing to buf0 4424
[] [3142 7236 6781 1615 9553 9174 487 5263 8490 4877 7397 1572 2781 724 7087 1957 2396 4361 7509 630 3489 7917 1716 2592 7872 5372 8575 4031 8051 4352 5790 9023 9786 1147 1335 8212 9615 4144 2025 4572 4593 5030 3448 9823 4746 9209 5195 208 8618 9927 8093 6367 4333 5895 8710 4486 911 7895 1137 1585 8978 4112 6266 9370 5106 7721 5788 1700 4571 1129 2265 3188 6142 3291 2270 3551 6243 7724 8606 4149 5014 4268 9066 8617 474 933 645 8505 364 1643 9447 8181 3920 95 9224 1056 5457 6781 2362 2203 2164 3543 4309 3842 8826 7245 8414 5958 8188 110 7505 767 1239 9936 1807 5936 4265 1283 1809 4109 8173 385 3587 3021]
#2017-12-1817:36borkdudeHm, seems to be correct after all:
buf0 changes to [1335]
1 waiting...
buf0 changes to []
prog 1 succeeded reading 1335
#2017-12-1817:39borkdudeI think I might have the situation where p1 writes so fast to the queue that compare-and-set never wins#2017-12-1817:40borkdudewhich is a deadlock in and of itself
#2017-12-1818:12bhaumanconcurrent programming is hard 😬#2017-12-1818:18ihabunek&lt;hint&gt; i just ran the first program until it blocked, then the second, and did that in a loop until both were blocked#2017-12-1818:18borkdudeyeah I had that at first, I might revert to that. Thanks!#2017-12-1819:25borkdudeI keep getting 127, but that’s not the right anwer#2017-12-1820:31mfikes@borkdude Getting 127 was also one of my failure modes, FWIW.#2017-12-1820:35mfikes@borkdude I'm able to repro how I produced 127, if you end up wanting a hint.#2017-12-1820:47borkdudeYes please sir.#2017-12-1820:57mfikes@borkdude My coding error that produced 127 involved an incorrect calculation for when a program is blocked.#2017-12-1820:58mfikesIn other words, it concluded that it was blocked, when it need not be.#2017-12-1820:58mfikes(Not sure if these vague hints are adding confusion.)#2017-12-1820:59borkdudeI think I get what you mean yeah#2017-12-1820:59borkdudeThis is my end condition…
(and (:waiting? p0)
                   (:waiting? p1)
                   (empty? (:in p0))
                   (empty? (:in p1)))
#2017-12-1820:59mfikesCool. My 127 error involved the lack of the empty? checks.#2017-12-1821:00borkdude😢#2017-12-1821:00mfikesIt was pretty cut-n-dry for me because one of the programs was marked as waiting when it had stuff left to consume in its queue.#2017-12-1821:01mfikesDo you mark a program as :waiting? when it tries to rcv but finds its inbound queue is empty?#2017-12-1821:02borkdudeyes#2017-12-1821:02mfikesCool. That sounds right. (It matches my logic.)#2017-12-1821:02mfikesDo you ever unmark the :waiting? flag?#2017-12-1821:03borkdude
snd
      (let [v (get-val registers reg)]
        (do (when (= id 1)
              (swap! p1-sending inc)))
        (->
         p
         (update :ctr inc)
         (update :out conj v)))
      rcv (if-let [v (peek in)]
            (assoc p
                   :in (pop in)
                   :waiting? false)
            (assoc p :waiting? true))
#2017-12-1821:04borkdudethe p1-sending is just a hack for now which I would clean up when I find the answer#2017-12-1821:08mfikesIs :ctr the instruction pointer?#2017-12-1821:10mfikesIf so, I'm wondering if the instruction pointer is incremented upon a successful (non-`:waiting?`) rcv#2017-12-1821:15mfikesAnother potential problem @borkdude is that the v associated with rcv is discarded.#2017-12-1821:15mfikes(Can't tell from the code fragment.)#2017-12-1821:18borkdudeThe program counter was missing indeed.. I refactored it and forgot. Now it doesn’t terminate…#2017-12-1821:18borkdudeAnother good point. Brb!#2017-12-1822:10borkdudeFWIW here’s my day 18 so far… https://github.com/borkdude/aoc2017/blob/master/src/day18.clj#2017-12-1822:12borkdudeOh, I should store the value on RCV…#2017-12-1822:13borkdudestill 127 with that “fix"#2017-12-1822:24erwinshouldn't you reset the waiting state on a send?#2017-12-1822:25borkdude@U052520AT hm, why? I reset it when I received a value#2017-12-1822:26erwinif p1 sends you should reset waiting for p0#2017-12-1822:26erwinotherwise you stay in locked state, maybe I do not read your code correct and this is fixed in a different way#2017-12-1822:26borkdudedoesn’t that happen when p0 receives the message?#2017-12-1822:27erwinbut your loop-until-wait never gets there?#2017-12-1822:27borkdudeit does next time in the loop#2017-12-1822:28borkdudeI mean, it does next time next-state' is called I think?#2017-12-1822:28erwinhttps://github.com/borkdude/aoc2017/blob/master/src/day18.clj#L105 this is called the next time ?#2017-12-1822:30borkdudeThis is what’s happening: https://gist.github.com/borkdude/d54ad43d7001334adde2912c87d9a1d6#2017-12-1822:30borkdudeso p0 builds up the out queue as far as possible#2017-12-1822:31borkdudethen p1 takes over and does the same#2017-12-1822:31borkdudeeventually everything is empty and both are waiting#2017-12-1822:32erwinah and then you are done, but the value is wrong#2017-12-1822:33borkduderight#2017-12-1822:37bhaumanI'm looking at your code @borkdude and your jump counter looks weird to me#2017-12-1822:37borkdudetell#2017-12-1822:39bhaumanit looks like you increment twice on zero?#2017-12-1822:39borkdudethe idea is, it’s always incremented, unless (and then the old value ctr is used + something)#2017-12-1822:39bhaumangotcha you save the counter#2017-12-1822:39bhaumanand overwrite#2017-12-1822:40borkduderight#2017-12-1822:40borkdudecould someone try my input just for sanity?#2017-12-1822:40borkdudehttps://github.com/borkdude/aoc2017/blob/master/resources/day18.txt#2017-12-1822:44erwindo you want the answer?#2017-12-1822:44bhaumanyep it runs#2017-12-1822:44borkdudejust knowing it’s not 127 is good enough#2017-12-1822:44erwinit is not 127#2017-12-1822:44bhaumanits up around our numbers#2017-12-1822:44borkdudein the ballpark of?#2017-12-1822:44bhaumanno where near 127#2017-12-1822:45borkdudewhat is “our numbers"#2017-12-1822:45bhaumannear above 7000#2017-12-1822:45erwinbetween 7000 - 8000#2017-12-1822:47borkdudeI might save this one for christmas then… the first 😢#2017-12-1822:48orestisWhat happens if a program that is already waiting is re-run?#2017-12-1822:49borkdudethen loop-until-wait returns the program#2017-12-1822:49borkdudewithout modification#2017-12-1822:52orestisBut you don't give a chance to run while in waiting state? To see if new values arrived?#2017-12-1822:54orestisThat is, loop-until-wait checks for the previously set waiting flag, not the current one, I think. Reading this on a mobile, might be misreading...#2017-12-1822:56bhauman@borkdude I just added some assertions to check that the input queue is empty before you overwrite it#2017-12-1822:56bhaumanand it failed#2017-12-1822:57borkdudeloop-until-wait lets a program consume its entire in queue and then returns it in a waiting state with an empty in queue#2017-12-1822:57bhaumanits not empty??#2017-12-1822:57borkdudebhauman: I responded to orestis, didn’t see your comment yet… gonna check#2017-12-1822:58bhaumani just posted a snippet to the main chat area#2017-12-1822:58borkdudethank you#2017-12-1822:59borkdudegoing to investigate#2017-12-1822:59orestis@borkdude yes but the second time round, it doesn't call next-state, does it? The waiting flag is only cleared after next state is run...#2017-12-1823:00borkdudeaah#2017-12-1823:02borkdudeI added both bhaumans assertions and your suggestion now… it’s running#2017-12-1823:03bhaumanI know the answer if you want to check it#2017-12-1823:03erwin@borkdude I fixed a couple bugs in your code and it prints the correct answer now#2017-12-1823:04erwin(as in: the same as @bhauman and my code)#2017-12-1823:04borkdudethat’s good… 🙂#2017-12-1823:05borkdudehow many were there…?#2017-12-1823:05erwinthe problem I suggested to you, and another#2017-12-1823:05erwinso 2#2017-12-1823:07borkdude@U052520AT is this one of the solutions?
(defn loop-until-wait
  [instructions prog]
  (loop [p (next-state instructions prog)]
    (if (:waiting? p)
      p
      (recur (next-state instructions p)))))
#2017-12-1823:09erwinah, yes, I fixed it different, but that would also work#2017-12-1823:09erwinfor the other: please read carefully how the instructions work#2017-12-1823:10borkdudeyou mean snd and rcv specifically?#2017-12-1823:10orestisI'm off for the night -- I hope the elusive bug will be found soon :)#2017-12-1823:10borkdudethanks orestis#2017-12-1823:11erwin@borkdude no#2017-12-1823:11erwinzero check#2017-12-1823:15borkdudeaaaaaaa ffffff#2017-12-1823:15borkdudethanks 🙂#2017-12-1823:17erwinyour welcome 🙂#2017-12-1823:18borkdudeaw man, without you guys I would still be sitting here until 3 AM 🙂#2017-12-1823:30bhaumanI rearranged your logic and got it working, not that that is helpful#2017-12-1823:30bhaumanbut your code does work 🙂#2017-12-1823:31borkdudehow is that not helpful?#2017-12-1823:32borkdudeit’s super helpful!#2017-12-1823:32borkdudecredits in the code: https://github.com/borkdude/aoc2017/blob/master/src/day18.clj#2017-12-1823:34bhaumanyou got it working!!!#2017-12-1823:35borkdudewith a little help from my friends#2017-12-1823:36bhaumancan I show you my alternative logic?#2017-12-1823:37borkdudeyes#2017-12-1823:38bhaumanin the main chat#2017-12-1823:38mfikesUgh. So in the end it was a jgz vs. jnz mistake? That kind of stuff is insidious to find.#2017-12-1823:38borkdude@mfikes yes, that was one of the bugs. another one was pointed out by orestis and erwin#2017-12-1823:38bhaumanyes and the first exercise was so week that it didn't detect it#2017-12-1823:39borkdude@bhauman what does #(reduce conj % (seq (:out p0) do, copy the queue?#2017-12-1823:39borkdudewho not just take it as it is?#2017-12-1823:39mfikesThe challenge on this one is you need to get all of the planets in alignment with no way of figuring out which (or which ones) are off#2017-12-1823:39bhaumanI'm combining the queues because they are not empty now#2017-12-1823:39bhaumanonly taking one step at a time#2017-12-1823:39borkdudeaaah and then it worked?#2017-12-1823:39bhaumanyep#2017-12-1823:40borkdudewow#2017-12-1823:40borkdudegood catch man#2017-12-1823:40borkdudeI’m off to bed…#2017-12-1823:40bhaumanhave a good night#2017-12-1823:41borkdudethanks again#2017-12-1900:42val_waeselynckHey folks, scarce Internet access here, can someone send the part 2 instructions for day 18 as a thread comment?#2017-12-1901:14bhauman@val_waeselynck ^#2017-12-1923:13val_waeselynckThanks!#2017-12-1902:55minikomiinteresting looking at how everyone detected "deadlock"#2017-12-1905:43minikomiahhhhh whitespace-cleanup killed me for this challenge be careful#2017-12-1905:48dyankowskyyeah, I tend to go slowly and test things in the REPL, and I fortunately noticed this pretty early... but if you miss it, I'd imagine that you'd get weird results#2017-12-1905:52minikomiespecially since I was using the length of the first line to get the "shape" of the field#2017-12-1905:55minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day19.clj If you're interested 🙂#2017-12-1905:57minikomiI've been using for, :let and :when lots more since starting advent#2017-12-1905:59dyankowskyah, I see#2017-12-1906:00dyankowskyI just kept the data as a jagged vector, and used get-in everywhere#2017-12-1906:01minikomiyeah, totally valid! I just like working with directions/positions as [x y]#2017-12-1906:01dyankowskyhttps://bitbucket.org/balefrost/adventofcode2017/src/9422be409d7794fa13ab6ffdef183b9177e5284f/src/day19.clj#2017-12-1906:01dyankowskyheh, yeah, I know what you mean#2017-12-1906:01minikomiI get mixed up too easily so I like to normalize first#2017-12-1906:02minikomiwow, did you come from another lisp to clojure?#2017-12-1906:02dyankowskyheh, no, though I do FP in other languages#2017-12-1906:03dyankowskyI actually think my Clojure is pretty messy#2017-12-1906:03minikomithe letfn threw me 😛#2017-12-1906:03dyankowskyheh#2017-12-1906:03dyankowskyI feel like I use lazy-seq way too often#2017-12-1906:03dyankowskyI mean, it's really useful#2017-12-1906:03dyankowskybut I suspect there are higher-level ways to do it#2017-12-1906:03minikomiyeah, I tend to rely on for and loop/`recur` a lot#2017-12-1906:04dyankowskyand I tend to combine lazy-seq with letfn#2017-12-1906:04minikomiI did a bunch or racket last year, so structuring things as a recursive loop often makes more sense to me#2017-12-1906:04dyankowskyyeah#2017-12-1906:04dyankowskyfor is pretty great#2017-12-1906:05minikomiI really miss for/fold & other racket-isms https://docs.racket-lang.org/reference/for.html#2017-12-1906:06minikomigot to eat something! have a good day#2017-12-1906:06dyankowskytake care!#2017-12-1909:12ihabunekracket sounds like a really cool language. just a bit more verbose than clojure#2017-12-1909:13ihabuneki learned the basics reading Little Schemer (big recommendation)#2017-12-1909:13ihabunekand it actually has CTO 🙂#2017-12-1909:14minikomiyep, and it was surprising for me how useful in-scope defines are, compared to let#2017-12-1909:14ihabuneki haven't used them, what's the difference?#2017-12-1909:15minikomiJust saves you saying (let [a.. b.. c..] and indenting / nesting .. you can do (define a (something))#2017-12-1909:16ihabunekah, ok#2017-12-1909:16ihabunekso many languages, so little time#2017-12-1909:16ihabuneki wanted to check out elixir too#2017-12-1913:33orestisMy day 19: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day19.clj#2017-12-1913:36orestisToday was merciful 🙂#2017-12-1916:23borkdudeMy day 19: https://github.com/borkdude/aoc2017/blob/master/src/day19.clj (it also searches the begin position as a bonus)#2017-12-1916:25bhaumanday 19#2017-12-1916:25bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day19.clj#2017-12-1916:27borkdudeNice @bhauman, concise 🙂#2017-12-1916:30borkdudePerformance of the day, both parts: 9ms (on my machine)#2017-12-1916:31bhaumanwell thats pretty darn fast#2017-12-1916:33mfikesDay 19: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_19.cljc#2017-12-1916:35borkdudeexcellent @mfikes 🙂#2017-12-1916:36bhaumanwhoa, @mfikes gonna need some time to take that in 🙂#2017-12-1916:36bhaumangood stuff#2017-12-1916:38borkdude@mfikes How fast?#2017-12-1916:39ihabunekeduction is a new one for me#2017-12-1916:58borkdude@mfikes Why transpose the grid in the beginning?#2017-12-1917:00borkdudeI mean, it seems arbitrary how you look at the grid, as rows or columns?#2017-12-1917:00borkdudebecause you have to move through it in all directions#2017-12-1917:21borkdudeIt seems day 18 was the most difficult: https://www.reddit.com/r/adventofcode/comments/7kuaaj/2017_day_19_leaderboard_chart/#2017-12-1917:21borkdudeI think the reason (for me at least) was a lack of confirmation data and lots of places where it could go wrong#2017-12-1917:26borkdudeTimed @mfikes's solutions, both come in around 40ms on my machine#2017-12-1917:28borkdudeNow I see why he applies mapv vec, it creates a vector of vector of chars#2017-12-1917:30borkdudeHINT I didn’t get a nice word like MERRYCHRISTMAS#2017-12-1920:31bhaumanI whittled my day 19 down a bunch more#2017-12-1920:31bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day19.clj#2017-12-1920:33bhaumanHINT#2017-12-1920:34bhaumanit seems to add a bunch of extra work keeping a direction in the state#2017-12-1921:33fellshardThat's really obvious now that you say it. I'll have to shave this yak a bit more.#2017-12-1921:40ihabuneknoob question: what is #_?#2017-12-1921:42ihabunekhm, seems to be a reader macro for commenting things out, why do you use it?#2017-12-1922:18orestisYou can eval it in the repl, and also saves you commenting line by line, you just comment the next form, however big. #2017-12-1922:25ihabunekah, how do you eval a commented block of code in the repl? 🙂#2017-12-1923:06borkdude@U4P4E2FMZ C-x C-e if you’re in Emacs#2017-12-1923:16bhaumancommenting a the next form is really helpful in a lot of situations#2017-12-1923:18bhaumanalso you may not know that #_ #_ comments out the next two forms and etc.#2017-12-1922:37Miķelis VindavsAlso wanted to share mine https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day18.clj — could be optimized by running interpreters in alternating sequence instead of in parallel, but I still think it turned out pretty nice and debuggable https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day19.clj — looks quite similar to the other ones shared I suppose#2017-12-1922:38Miķelis VindavsBtw get and by extension get-in also work on strings, so there’s no need to turn them into char vectors#2017-12-1922:39Miķelis VindavsI wonder if there’s a nicer way of writing the somewhat common pattern (when (not= x bad-value) x)#2017-12-1922:41Miķelis VindavsFor the opposite case (whitelist), there’s (some-> x #{good-values..})#2017-12-1922:42Miķelis VindavsMaybe something like
(defn is [pred x] (when (pred x) x))
(defn is-not [pred x] (when-not (pred x) x))
#2017-12-1923:08borkdudePlanck:
(get-in "foo" [0 0 0 0 0]) ;;=> "f"
JVM: nil
#2017-12-1923:10borkdude@mikelis.vindavs Clean looking solution, great job.#2017-12-1923:30mfikes@borkdude If I had to guess, the get-in behavior is a consequence of characters being represented by single-character strings in ClojureScript.#2017-12-2001:32minikomiI never knew you could use case with a list! That’s useful for sure#2017-12-2003:12minikomiadjusted mine to use my new knowledge.. list-condition case and trying out cond->#2017-12-2004:59Miķelis VindavsWow, that’s interesting behavior with get-in and cljs. I wonder if that’s “undefined behavior” territory or a bug#2017-12-2005:20dyankowskyI'm not sure how I feel about my solution to tonight's problem#2017-12-2005:21dyankowskyI though about it and came up with two probablistically correct answers, and got the right answer in both cases, but I don't feel like I "solved" the problem#2017-12-2005:25dyankowskybut hey, I finally got points on the global leaderboard, so I guess I'll take that 🙂#2017-12-2005:36minikomicongrats! bit stumped on this one#2017-12-2005:36dpsuttonfor day 13 did anyone do a sieve of eratosthenes type solution?#2017-12-2006:19mfikes@dpsutton I didn’t see one in Clojure, but Kris Jenkins appeared to do so: https://github.com/krisajenkins/AdventOfCode/blob/master/src/Year2017/Day13.purs#L44#2017-12-2006:20mfikesDay 20: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_20.cljc#2017-12-2006:21dpsuttonah cool. i've been slacking and catching up. it's quite elegant#2017-12-2006:21dpsuttonand fast. 1 sec versus 10 for me#2017-12-2006:22dpsutton
(comment
  (time (solve2))
  ;; "Elapsed time: 10507.820736 msecs"
  ;; 3870382
  (dotimes [_ 20] (time (sieve-method data/data)))
  ;; "Elapsed time: 1293.195798 msecs"
  ;; 3870382
  )
#2017-12-2006:23dpsuttoni've ripped off your style of multi arity (solve1) and the data/data namespaces. thanks for that#2017-12-2006:32minikomiman i have no capacity for visualizing this problem 😆#2017-12-2006:32grzm@mfikes I'm not sure I'll be satisfied with your solution unless you also provide a 3D hologram displaying the collisions.#2017-12-2006:33grzmHelp me, Mike Fikes Kenobi. You're our only hope! 😉#2017-12-2006:34grzm@minikomi Have you gotten part-1?#2017-12-2006:34minikominope, maybe i'm overthinking it#2017-12-2006:34minikomitrying to weed out the particles moving & accelerating away from the origin..#2017-12-2006:38mfikesI’m not satisfied with my day 20 solution either @grzm — I had to fall back on what the AoC game allows 😞#2017-12-2006:40grzmI hope it's clear that's a friendly jab 😉 Your solutions have really inspired me.#2017-12-2006:40mfikesThis problem definitely has a tradeoff of overthinking vs. pragmatism.#2017-12-2006:59minikomiwow#2017-12-2006:59minikomiwayyyy overthought it hahaha#2017-12-2006:59dyankowskyget it?#2017-12-2006:59dyankowskyheh#2017-12-2007:10minikomilol..#2017-12-2007:10minikomiwell, it's done. but.. what a squiggy way to solve it#2017-12-2007:11minikomiI wonder if there's a way to fine-tune cider output .. or have it print to a terminal. Sometimes it gets reaaaaly slow.#2017-12-2007:51Miķelis Vindavstoday marks my biggest facepalm moment so far.. Took me almost 3 hours and writing a quadratic equation solver to realize that the velocities need to be updated before the positions#2017-12-2009:22erwinI have a solution for today, but I am not sure if it is valid for all possible inputs ...#2017-12-2009:22erwinhttps://github.com/ekroon/adventofcode2017/blob/master/src/adventofcode/day20.clj#2017-12-2010:51ihabunekmy solution: https://github.com/ihabunek/aoc2017/blob/master/src/aoc2017/day20.clj#2017-12-2010:51ihabunekSPOILERS#2017-12-2010:51ihabuneki have a nice solution for part 1#2017-12-2010:52ihabunekparticles with the greatest accelleration will end up furthest away#2017-12-2010:52ihabunekif they have the same accelleration, then those with greatest speed#2017-12-2010:52ihabunekif they have the same speed, then those which are initially furthers away#2017-12-2010:52ihabunekso if you sort all particles by absolute accelleration, then speed, then position from center#2017-12-2010:53ihabunekand take the first one, that's the solution#2017-12-2011:18ihabunekheh, just saw that @erwin does the same#2017-12-2012:50mfikesVery nice. I was worried that this kind of solution might be susceptible to them setting up a slow moving constant-velocity particle that is far away but would cross near the origin. But I suppose, by the problem definition, even though that one might be close temporarily at some point far out in the future, over the long run, it doesn’t meet the definition. Analogy: That extra-solar body that just passed by, but was, for a short while closer than most of our planets.#2017-12-2012:54mfikesI think your approach is fairly rigorous though.#2017-12-2012:55mfikesPerhaps there is a similar argument to be made for collisions if you somehow compare the inter-particle accelerations, velocities, and positions to know you are done detecting collisions. Quadratic cost.#2017-12-2014:58dyankowskyMy reading of the problem was, in the limit, which particle ends up closest to the origin#2017-12-2015:00dyankowskyI also cheated even more; I looked at my dataset and saw that there were no ties for smallest acceleration#2017-12-2015:03dyankowskyfor the collisions, I think you could do something like iterate until enough acceleration has accumulated into velocity that the initial velocity is negligible, and until enough velocity has accumulated into position that the initial position is negligible#2017-12-2015:04dyankowskythat is, in the limit, the acceleration is all that matters - it will completely dominate the other two#2017-12-2015:06dyankowskyI think there has to be some way that you could look at each particle in isolation and determine whether this has happened (within some tolerance) and, when that has happened, you know that any collisions that would happen would have already happened#2017-12-2015:11dyankowskymaybe a better way to put it is that, while your particles all start out at various positions around the origin, going in different arcs, eventually those arcs become nearly straight lines as the accumulated acceleration dominates the velocity. And as time ticks on and everything gets further from the origin, you can increasingly approximate your system as "a bunch of lines all shooting out from the origin". Sure, they didn't all start at the origin, but once they get far enough away, it's sufficient to assume that they all started in the same place.#2017-12-2013:57bhaumanwhat format is the answer supposed to be in?#2017-12-2013:58bhaumanfor part 1#2017-12-2014:03Miķelis Vindavsindex of the particle#2017-12-2014:03bhaumanoh gosh did they make that clear at all?#2017-12-2014:04Miķelis VindavsI felt like they did https://www.dropbox.com/s/2uza02wl3jl469v/Screenshot%202017-12-20%2016.03.54.png?dl=0#2017-12-2014:04Miķelis Vindavsusually the expected answers are monospaced with a background#2017-12-2014:04bhaumani thought that was a temp label#2017-12-2014:05bhaumangotcha#2017-12-2014:05Miķelis VindavsPicking 0 as the sample answer was perhaps not the best choice simple_smile#2017-12-2014:27mfikesIMHO, they could have improved that aspect of the problem definition. (I say "they" assuming that Eric Wastl has play testers. Who knows?)#2017-12-2014:47mfikesBy the way, if my solutions tend to look inexplicably transducer heavy (without justification), it is because I'm working on keeping memory usage down when solving the AoC problems in ClojureScript. Background: ClojureScript doesn't have locals clearing. See http://blog.fikesfarm.com/posts/2016-01-15-clojurescript-head-holding.html With transducers you can sometimes work around this limitation. I'm working on https://dev.clojure.org/jira/browse/CLJS-2445, and for many of these problems (which involve reducing over the results of iterate) they become solvable in ClojureScript with a few MB whereas previously you can easily consume several GB.#2017-12-2014:54mfikesA great example is this line, which is solved in an updated version of Planck in 155 MB (running CLJS-2445 changes), while the unchanged Planck can't effectively solve it unless it is tediously converted to a loop / recur: https://github.com/mfikes/advent-of-code/blob/a440f0ea8326f7ed2eea71270fbc7d4e6d0df1c1/src/advent_2017/day_17.cljc#L24#2017-12-2015:00mfikesActually, the unrevised Planck can run that code, but it takes 14 GB and about 2 minutes, as opposed to 155 MB and 7 seconds. A loop / recur is still faster for that arithmetic-centric problem, running in about 1 s in Planck, but I'd like to be able to work at the higher level of abstraction if it leads to reasonable results.#2017-12-2015:05bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day20.clj#2017-12-2015:06mfikesWow, is physics / calculus sufficient for this problem?#2017-12-2015:07mfikesI suppose it is a good enough approximation, given you have to approximate anyways.#2017-12-2015:09mfikesAnd, using the distance formula leads to a very fast solution. Nice @bhauman#2017-12-2015:11bhaumanits only good enough for the first part#2017-12-2015:11mfikesAhh... good point#2017-12-2015:12bhaumanthe second part relies on their slot based interpretation of time#2017-12-2015:12mfikesThe second part seems to converge more quickly for me#2017-12-2015:13mfikesI still think a lot of participants are going to end up feeling unsatisfied by this problem, even though, logically, all you need to do to solve it is type in an answer that it accepts.#2017-12-2015:13mfikesIn other words, logically, anything you can do that leads you to the right guess is perfectly fine.#2017-12-2015:14dyankowskythat's perhaps one of the more interesting things about AoC - it's not about code per se, but all the problems are problems where machine assistance is extremely useful#2017-12-2015:14mfikesAnd, if you go down that path, I like @bhauman’s transformation to continuous math as opposed to discrete#2017-12-2015:15bhaumanI spent some time "remembering" (i.e googling) that math#2017-12-2015:16mfikesYeah, @bytecrafter part 2 of day 7 seemed to be initially solved by many participants half via code with the "last mile" by hand, then backfilling with the correct code#2017-12-2015:17mfikesThat one was strange in that it was actually easier to do it by hand than to write the code to do the needed calculations.#2017-12-2015:17dyankowskyyep, I was one of those on day7#2017-12-2015:18mfikesIf you factor in that part of the game is to beat the clock, these kinds of problems are appropriate.#2017-12-2015:18dyankowskythat's also one of the things I like about doing these in Clojure - even though it's not my most comfortable language, doing stuff in the REPL is great#2017-12-2015:19mfikesSpeaking of that, I liked the 4Clojure aspect where part of the problem was to find a solution that was sufficiently efficient for it to be solved before the 4Clojure timeout kicked in.#2017-12-2015:20dyankowskyit kills off your process if it runs too long?#2017-12-2015:20dyankowsky(or request or thread or whatever)#2017-12-2015:20mfikesYes. Oftentimes you will have some code that actually solves it, but it takes, say 45 seconds.#2017-12-2015:21mfikesI don't recall the timeouts, but it may have required your code to run on their server within, say 30 seconds#2017-12-2015:21dyankowskyinteresting#2017-12-2015:22mfikesIf you get really frustrated, you can "cheat" by writing functions that produce the correct answers instantly, once you know what they are.#2017-12-2015:22mfikesBut, then you defeat the learning process 🙂#2017-12-2015:50Miķelis VindavsPart2 can be solved in a non-iterative way using quadratic equations too#2017-12-2015:51Miķelis Vindavstwo particles collide if 1/2*a1^2 + v1*t + s1 == 1/2*a2^2 + v2*t + s2#2017-12-2015:52Miķelis Vindavs^that’s for one dimension, where a is acceleration, v is velocity and s is the inital position solve for t and get the time when it happens
#2017-12-2015:53Miķelis Vindavsdo that for all 3 dimensions, and if the ts match, the particles collide at that time#2017-12-2015:53dyankowskyto match the iterative approach, t must also be an integer#2017-12-2015:53Miķelis Vindavsthat’s still O(n^2) though, where n = number of particles#2017-12-2015:54dyankowskythe iterative approach allows particles to "pass through" each other as long as they do so in the middle of a timestep#2017-12-2015:55Miķelis Vindavsyep, and also need to account for the fact that velocity is “updated” before position#2017-12-2015:55Miķelis VindavsI guess by doing v1*(t+1) instead of v1*t?#2017-12-2015:55dyankowskynot sure#2017-12-2015:57Miķelis VindavsI have an unfinished and not cleaned up approach to it at https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day20.clj#L63-L89 It doesn’t work because it doesn’t account for the velocity thing#2017-12-2016:00borkdudehmm, day 20, stuck at 1000 particles after 10^3,4,5 iterations..#2017-12-2016:01borkdudecan someone give me a hint after how many iterations you should expect collisions? 1? 10? 1000?#2017-12-2016:02Miķelis Vindavs100#2017-12-2016:02Miķelis Vindavswell, the first one start at 10-15 for me#2017-12-2016:02borkdudeok, then I’m having something wrong then#2017-12-2016:03Miķelis VindavsCould it be this? 😅 https://clojurians.slack.com/archives/C0GLTDB2T/p1513756271000087#2017-12-2016:06borkdudeDefinitely…. still got part 1 right though… thanks!#2017-12-2016:07borkdudeah, now they are colliding… phew..#2017-12-2016:08borkdudeaaaaand solved…. 😅#2017-12-2016:40bhauman@mikelis.vindavs I don't think the equation solution for part 2 will work, I'm pretty sure we'd need a different position equation as#2017-12-2016:41bhaumanoh shoot#2017-12-2016:49Miķelis VindavsNow I’m intrigued simple_smile #2017-12-2016:52ihabuneka friend of mine did part 2 quadratic equation solution in elixir, so it's possible https://gist.github.com/sasa1977/a35e87540669f32c28e3bd2b7698ca7e#2017-12-2017:03borkdudeFWIW, my day 20, no fancy math involved: https://github.com/borkdude/aoc2017/blob/master/src/day20.clj#2017-12-2017:05borkdudeI’m looking at @bhauman’s solution and instantly I remember my high school physics 🙂#2017-12-2017:08mfikesHah, I happened to have this lying around from a couple of months back when I was trying to explain some stuff to my son#2017-12-2017:22bhaumanHINT#2017-12-2017:23bhaumanthe position function will work if you do (Math/ceil (* 0.5 t t))#2017-12-2017:26bhaumanthis is for part 2#2017-12-2017:26borkdudeSo for part two you could use some algorithm which checks if functions will collide for some interval maybe?#2017-12-2017:28borkdudeNot sure which one 🙂#2017-12-2017:30borkdudeYou could solve equations for every pair#2017-12-2017:30borkdudeand if there is no solution, it won’t collide#2017-12-2017:31mfikesIf you get a closed-form solution (like what Bruce said), then take the difference between every pair, set it to 0 and see if beyond a certain t it can no longer be solved?#2017-12-2017:32mfikesIf you can find such a t that works for all pairs...#2017-12-2017:32borkdudeI didn’t read the whole thread. Will do so tonight. Have to make dinner now.#2017-12-2017:59orestisI did a numerical approach on day 20 as well: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day20.clj#2017-12-2018:28kaffeinhey guys... I have had some trouble figuring out what was wrong with my day 5 implementation! can someone tell me if I'm missing something from the following code snippet 😉 P.S : Clojure newbie here ...your eyes may hurt but I have to start with something I guess 🙂#2017-12-2018:32kaffeinthanks in advance#2017-12-2018:39erwin@kaffein I think you should end with a (inc steps) on line 14#2017-12-2018:40erwinthe last step is also a step I would say#2017-12-2018:48kaffeinThanks @erwin I will try that out ...though the unit test that I've run using the problem example seems to be okay #2017-12-2021:43borkdudeIn Postgres: https://github.com/xocolatl/advent-of-code/blob/master/Day20/script.sql#2017-12-2021:45mfikesIt make me feel better that it says "Both of these queries have shameful, arbitrary stopping points"#2017-12-2021:46mfikesAll developers hang their heads in shame for some reason for this problem. 🙂#2017-12-2022:02fellshardIt edges too close into math we're told we should know and don't really want to explore? 😛#2017-12-2022:02fellshardWe'd rather take the approach of 'make the numbers big enough we remove reasonable doubt'#2017-12-2022:08borkdudeWhen I encountered part 1 for a moment I thought, should I solve this more cleverly using Newton or …. meh, no, in part 2 they are going to ask for something ridiculous anyway, like how many times the sum of the coordinates were prime numbers in the first million runs#2017-12-2022:12borkdudeWow: https://www.reddit.com/r/adventofcode/comments/7l42yy/day_20_with_calculus/#2017-12-2108:45fellshardFun with List Processing ™️#2017-12-2114:55ihabunekwell i have a bug 😄#2017-12-2114:55ihabunekcan't trace it for a while now#2017-12-2115:54bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day21.clj#2017-12-2116:14fellshardI need to remember to use flatten more often...#2017-12-2116:17borkdudeI’m still in progress, so not looking, but I’ve already used flattened. I thought I could avoid assembling the whole grid from the parts, but then realized 3x4 is divisble by 2, sigh… 🙂#2017-12-2116:39ihabuneki found the bug, it was due to not reading the question properly#2017-12-2116:39ihabunekagain.#2017-12-2116:39ihabunek🙂#2017-12-2116:40ihabunekhttps://github.com/ihabunek/aoc2017/blob/master/src/aoc2017/day21.clj#2017-12-2116:40ihabunektrash performance#2017-12-2117:04bhauman@ihabunek just a tip. for is pretty darn powerful for comprehensions you can do (for [x (range 10) y (range x)] [x y])#2017-12-2117:05ihabuneki know but i wanted nested lists so i nested fors#2017-12-2117:05bhaumandarn well that makes sense#2017-12-2117:05ihabunek😄#2017-12-2117:05ihabunekbut i'm sure much of my code can be written in a nicer way#2017-12-2117:06ihabuneki'm still learning new functions every day#2017-12-2117:07bhauman@ihabunek I would call distinct on variants before using it#2017-12-2117:08bhaumanas "##/##" only has one variant#2017-12-2117:08bhaumanunless of course I'm missing something again#2017-12-2117:09ihabunekIt's lazy though so distinct would make the whole thing eval and slow it down.#2017-12-2117:09ihabunekI think. 😀#2017-12-2117:09bhaumandistinct is lazy 🙂#2017-12-2117:09ihabunekAh#2017-12-2117:09ihabunekNice#2017-12-2117:11bhaumanI was just looking for what was slowing you down#2017-12-2117:11bhaumani don't think that's going to help much#2017-12-2117:27mfikesDay 21: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_21.cljc#2017-12-2117:32mfikesVery clean solution @bhauman#2017-12-2117:34bhauman@mfikes our solutions are practically identical#2017-12-2117:35mfikesYes, I started thinking that when I saw (concat rotations (map flip rotations))#2017-12-2117:37bhaumanyour split-xf function is different from my break-into which is interesting#2017-12-2117:39bhaumanoh it doesn't matter if they are rotated/transposed at this point#2017-12-2117:42bhaumanI was maintaining fidelity when I didn't have to#2017-12-2117:48bhaumanI definitely really like how you are composing everything into one big transducer function#2017-12-2117:50mfikesYeah, I don't think I succeeded completely. Or, at least I can say, Planck still consumes a few GB when solving it.#2017-12-2117:50bhaumannow I get it, I really like your split-xf approach#2017-12-2117:51mfikesDunno if this is just lazy cleanup of garbage or if it is true head-holding type stuff.#2017-12-2117:51bhaumanway more straight forward#2017-12-2117:54bhaumanI would guess its the garbage#2017-12-2118:27mfikesI’m curious if there is any self-referential pattern for part 2 that would allow you to avoid brute force. (I haven’t bothered to check.)#2017-12-2118:29ihabunekthere's this https://www.reddit.com/r/adventofcode/comments/7l78eb/2017_day_21_solutions/drk8j2m/#2017-12-2119:54bhaumandiscussion HINT#2017-12-2119:54bhaumansince depth isn't a problem a recursive solution seems like it could perform well#2017-12-2119:55bhaumanbecause we don't have to transform back to the original and if done right we could memoize whole portions of the tree#2017-12-2119:56bhaumanand the return type is just a string or a number#2017-12-2120:14borkdudeSorry, I hijacked your discussion… I’ll remove#2017-12-2120:15bhaumanno worries#2017-12-2121:15bhaumanholy crap the memoized recursive solution runs in 5ms#2017-12-2121:29bhaumanthe recursive solution has to bridge past the divisible by 2 divisible by 3 ambiguity#2017-12-2120:59borkdudeI tried an answer that I seriously computed, but then it said: this is the answer for someone else. LOL#2017-12-2121:00bhaumanugh#2017-12-2121:02borkdudebut one bug I had: I didn’t consider ordering of the rules. Obviously that’s important#2017-12-2121:03ihabunekcheater! 😄#2017-12-2121:03ihabuneki had that the other day too#2017-12-2121:04ihabunekthe one with two parallel programs#2017-12-2121:04ihabuneki gave the answer for the wrong program#2017-12-2121:34bhaumanI now have a 5ms solution for part 2#2017-12-2121:50borkdudeDOH, I thought for rotate, rotating the outer nodes of the square around the center one.. what was I thinking, looool#2017-12-2121:53mfikesOooh. Does the rule order matter? I didn't incorporate that into my solution.#2017-12-2121:53borkdudeI thought it was my mistake, but now I realize my rotations are totally bogus#2017-12-2121:56borkdudesurprise it did work for the example#2017-12-2121:56mfikesMy rotations were wrong initially as well and my code worked for the example#2017-12-2121:57bhaumanthe logic order (mod 2) comes before (mod 3)#2017-12-2121:57mfikesYes, that order is crucial for, say 6 or 12#2017-12-2121:57borkdudeyeah, got that#2017-12-2121:57borkdudeI’m creating an extended rule book that already includes the rotations/flips#2017-12-2121:57borkdudeso you can just lookup by whatever you have#2017-12-2121:58borkdudebut then you have to take care of the order#2017-12-2121:58bhaumanyeah thats what we did#2017-12-2121:58bhaumanyou do???#2017-12-2121:58bhaumanI don't think so#2017-12-2121:59borkdudeok well I thought it was my mistake that there would be some rotation literally in the rule book and I would be overriding it#2017-12-2121:59borkdudebut ok#2017-12-2122:00bhaumanjust make sure your (count (distinct (vals rules)) is equal to the original rulles length#2017-12-2122:00borkdudeyeah, added an assertion for that. I’m using more assertions since you helped me out 🙂#2017-12-2122:03borkdudePhew, part 1 solved now.#2017-12-2122:04borkdudePart 2 also.#2017-12-2122:06borkdudeMy assumption was that the rules could not be orthogonal with respect to rotations. E.g. if there would be a rule A => that had rotations A’, A’‘, but there would also be a rule B =&gt; , with B equal to A’ sorting the rules like A, B, A’ would mess things up#2017-12-2122:07borkdudeBut maybe they were orthogonal or however you may put this#2017-12-2122:07borkdudeexclusive#2017-12-2122:23borkdudeMy code. Nothing fancy, but glad it works now. https://github.com/borkdude/aoc2017/blob/master/src/day21.clj#2017-12-2200:30mfikesHah. I forgot core has even?—no need to (zero? (mod x 2))#2017-12-2200:45mfikesOn a more interesting note, I sorted out how to transduce all the way through with no intermediate data structures#2017-12-2200:45mfikeshttps://github.com/mfikes/advent-of-code/commit/c8e5873603d459909f464036e912b3dca0f71562#2017-12-2200:45mfikesThis results in it processing an arbitrary number of iterations without blowing out memory#2017-12-2200:46mfikesThe mind bending bit is to replace an (into [] ...) in the core of the algorithm with an (eduction ..) which causes all the steps to complete immediately, followed by a long phase of another transduce at the end where it does all the calculations essentially lazily.#2017-12-2200:47mfikesThe learning: you can iterate where each step returns an eduction. Cool!#2017-12-2210:35ihabunekthat's impressive#2017-12-2210:35ihabuneki need to study your code, it's way above my current understanding of clojure 🙂#2017-12-2213:02mfikesThe motivation is that if you do it this way in ClojureScript, you work around the lack of locals clearing. In other words, in CloureScript you are always holding head.#2017-12-2212:08orestisBah. Day 21 is so fiddly.#2017-12-2212:09orestisYou can have both rotations and flips?#2017-12-2212:09orestisArg.#2017-12-2212:13orestisPhew, I had the rotations/flips logic wrong, I got a hint from @borkdude and now my code works for both parts, even though I didn’t take into account any ordering or whatever.#2017-12-2212:14orestisNow to read other code.#2017-12-2212:15orestisMy code: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day21.clj#2017-12-2212:18orestis@bhauman Ahh, fantastic transpose/flip/rotate functions.#2017-12-2213:00mfikesDay 22: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_22.cljc#2017-12-2213:55mfikesThe patch that helps tremendously in ClojureScript for problems involving reducing over large amounts of iterate, repeat and cycle (which a lot of the AoC problems seem to do) is now in https://dev.clojure.org/jira/browse/CLJS-2445#2017-12-2215:22borkdudeDay 22: https://github.com/borkdude/aoc2017/blob/master/src/day22.clj#2017-12-2215:54bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day22.clj#2017-12-2215:55bhaumanjust increase the complexity of the state transitions and it will have to take more time#2017-12-2215:55bhaumanthis seems to be their strategy this year#2017-12-2216:00borkdudeis that different than last year? I stopped at day 7 or so last year#2017-12-2216:11bhaumanif I remember correctly they had more stumpers in the last two advents#2017-12-2216:19borkdudemaybe they’re trying to make it more mainstream now? 😉#2017-12-2216:20borkdudeif you’re bored with today’s ant, here’s another game: https://github.com/wouter-swierstra/ants/blob/master/ants.pdf#2017-12-2216:41thegeezI remember last year to be more about best first searching, this year iterate seems to always suffice#2017-12-2217:21orestisLast year there was A* and other graph search algorithms.#2017-12-2217:22spfeifferStill being at '15 day 22 you guys won't motivate me to look into '16 and '17 ☺️#2017-12-2217:26orestis’17 feels much easier. Usually the last couple of days are simple, what with people solving the puzzle over the holidays.#2017-12-2217:31orestisMy Day 22: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day22.clj#2017-12-2217:32orestisThis year for some reason I really don’t want to refactor any code. I wonder if Clojure is scaring me.#2017-12-2218:27mfikesFWIW, I refactor heavily. The first version I write works but is garbage. 🙂#2017-12-2218:34borkdudeSame for me.#2017-12-2219:25bhaumanis there an ascicinema like way to record what happens in an emacs buffer?#2017-12-2219:26bhaumanwell i guess I could run in the terminal#2017-12-2219:26bhaumanwhich shouldn't be too hard#2017-12-2306:39ihabunekah, optimizing assembler, never thought i'd be doing that 😄#2017-12-2307:20dyankowskyWhew!#2017-12-2307:24dyankowskyI'll be curious to hear how other people decided to approach part2#2017-12-2307:26ihabunekdid you solve it?#2017-12-2307:26dyankowskyyeah#2017-12-2307:26ihabunekah, i'm feeling very stupid right about now#2017-12-2307:27dyankowskyit's really hard to see what it's doing#2017-12-2307:27ihabuneki see the loops but i'm unsure how to go about removing them#2017-12-2307:28dyankowskyyou might need to figure out what the loops are doing#2017-12-2307:28dyankowskyor rather why they exist#2017-12-2307:29ihabunekso would a middle-out approach work here? start with the innermost loop and try to remove it#2017-12-2307:29ihabunekheh, middle-out, accidental silicon valley reference#2017-12-2307:29dyankowskyheh#2017-12-2307:30dyankowskyjust make sure you get that weissman score way up#2017-12-2307:30dyankowskyI think it's worth analyzing the loops from the middle out#2017-12-2307:35dyankowskyI think it's also worth looking at how the registers are used and, most importantly, at what points their values no longer matter#2017-12-2307:43ihabunekyeah, trying to eliminate registers one by one#2017-12-2308:40Miķelis Vindavsi rewrote the assembly to C, figured out what it does and found the answer by hand#2017-12-2308:54Miķelis VindavsI’d be really curious to see others’ inputs, but at least in my case, no amount of compiler optimization would help because the algorithm itself is fundamentally flawed#2017-12-2309:45ihabuneki rewrote it in python and got the wrong answer 😄#2017-12-2309:45ihabuneki must have made a mistake along the way#2017-12-2309:49erwinI am just running the interpreter for some time now, but I don't think that is going to work 🤓#2017-12-2309:53ihabunekit makes 3 nested loops for my input, with 100k iterations each, so i don't think brute force is viable 🙂#2017-12-2310:44ihabuneki got it, i had an off-by-one twice 😄#2017-12-2310:44ihabunekoff-by-two you could say#2017-12-2310:45ihabunektoday was actually fun, although it included very little programming#2017-12-2313:01Miķelis VindavsFor fun I compiled the C code and let it for half an hour but it didn’t finish. Replacing a small subroutine with one that has better algorithmic complexity let it finish instantly#2017-12-2313:02Miķelis VindavsDid your input program also do ... ? spoilers inside#2017-12-2313:02Miķelis VindavsCount the number of non-primes in a range?#2017-12-2313:02Miķelis VindavsBy using a really bad prime checking function #2017-12-2313:07ihabunekyes#2017-12-2313:07ihabunek@mfikes i'm guessing everyones did#2017-12-2313:07ihabunekwith different bounds#2017-12-2313:09ihabunekit should be easy to fix the assembler code if you were allowed to use mod like in day 18#2017-12-2313:13ihabunekhere's my translation of asm to python:
h = 0

for b in range(106700, 123700 + 1, 17):
    f = 1
    for d in range(2, b):
        for e in range(2, b):
            if d * e == b:
                f = 0
    h += f
#2017-12-2313:42orestisAh, stupid jnz; I thought I was counting the number of primes, not of non-primes.#2017-12-2313:43ihabuneki did the same...#2017-12-2313:44ihabunekand then i missed the fact that the outer range should be inclusive#2017-12-2313:45orestisI have a list of primes from my bounds, I hope I can rely on them 🙂#2017-12-2313:49orestisHah, I had the inclusive list problem also; it’s 1001 numbers, not 1000.#2017-12-2314:02orestisI wonder what’s the O complexity for this; we have O(N N/2 M), where N ~= 100k and M 1000/17?#2017-12-2314:14Miķelis VindavsI also had the off by one error initially when solving by hand :)#2017-12-2315:43ihabunekas they say, two most difficult problems in programming are naming things, cache invalidation and off-by-one errors 🙂#2017-12-2316:45bhaumanthe sub -1 got me quite a few times#2017-12-2313:43orestisCome on, 1 minute limit 🙂#2017-12-2313:44orestis5 minutes now. D’oh!#2017-12-2313:50orestisDay 23: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day23.clj#2017-12-2316:38bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day23.clj#2017-12-2316:39bhaumanyeah program analysis for the holidays#2017-12-2316:39bhaumanits funny how the heavy the resistance to actually just analyzing the program is#2017-12-2316:41bhaumanI just wanted to find an obvious countdown, but nope#2017-12-2316:43mfikesDay 23: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_23.cljc#2017-12-2316:47mfikesNo spoilers here. I like @bhauman’s inline analysis. I ended up with this crap#2017-12-2316:47bhaumanthat looks fun too#2017-12-2316:48mfikesI wanted to optimize it but. I had already spent too much time once I saw what it was doing#2017-12-2316:49bhaumanyeah, its tough with that instruction set#2017-12-2316:49bhaumanand you have to change all the jnz offsets, blah#2017-12-2316:50bhaumanand we have christmas stuff to do#2017-12-2316:51mfikesYeah, with respect to the instruction set, I was thinking along the lines of re-adding an instruction that was in the day 18 computer#2017-12-2316:51bhaumanI know the one#2017-12-2316:51mfikesBut, f-it. Too much time spent on this one 🙂#2017-12-2317:35ihabuneki had the same but digital 🙂 cleaned up version:
set b 106700     ; starting value for b
           set c 123700     ; ending value for b
    +----->set f 1          ; iterate b from 106700 to 123700, step 17
    |      set d 2
    | +--->set e 2          ; iterate d from 2 to b - 1
    | | +->set g d          ; iterate e from 2 to b - 1
    | | |  mul g e
    | | |  sub g b
    | | |  jnz g 2 ---+
    | | |  set f 0    |      ; set f = 0 if d * e == b
    | | |  sub e -1 <-+
    | | |  set g e
    | | |  sub g b
    | | +--jnz g -8          ; jump unless e == b
    | |    sub d -1
    | |    set g d
    | |    sub g b
    | +----jnz g -13         ; jump unless d == b
    |      jnz f 2 --+
    |      sub h -1  |       ; increment h if f == 0
    |      set g b <-+
    |      sub g c
    |      jnz g 2  ---+
    |      jnz 1 3     | ; exit
    |      sub b -17 <-+
    +------jnz 1 -23
#2017-12-2318:14fellshard
total = 0
curr = 108100 to 125100 (exc.) by 17
  flag = 1
  d = 2 to curr (inc.)
    e = 2 to curr (inc.)
      flag = 0 if d*e = curr
  total++ if flag = 0
#2017-12-2318:14fellshardin loose pseudo; tl;dr, best I can tell, count all non-primes between two numbers#2017-12-2318:24fellshardI'm still missing something critical, though#2017-12-2318:48fellshardD'oh. Off-by-one.#2017-12-2411:55ihabunek@U1YPTG4UF i think everyone had the off-by-one problem in this one, i had two 😄#2017-12-2318:51Miķelis VindavsMy solution for today went similarly Part 1: - https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day23.clj Part 2: - First on paper https://www.dropbox.com/s/rmb78q1dml3d1na/IMG_8127.JPG?dl=0 - Then turning jumps into loops https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day23-1.txt - Then into more readable pseudo-C https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day23-2.txt - Used that + wolfram alpha to get the answer - Actual C (with feasible runtime) for fun https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/2017/day23.c#2017-12-2318:52Miķelis VindavsI was hoping that the task would be to programmatically optimize the algorithm#2017-12-2318:53Miķelis Vindavs@mfikes looks like we even had the same inputs#2017-12-2319:24borkdudeAsking for a little help: is it the intention of the puzzle to optimize the assembly or just calculate the answer once you know what it’s doing?#2017-12-2319:35thegeeztoday was good to get the average time per day spent on AoC to grow exponentially 😕#2017-12-2319:39bhauman@borkdude understand the alg and get the answer#2017-12-2319:40thegeez@borkdude I ran the optimized assembly until it finished for the answer#2017-12-2319:40borkdudeok, because I find it really difficult to get the algorithm right with only these instructions…#2017-12-2319:40bhaumaneven if you optimize the code it will run really slowly#2017-12-2319:40borkdudein sane computing time#2017-12-2319:40borkdude@thegeez How long did yours run?#2017-12-2319:41bhaumanpeople have mentioned adding the mod instruction back#2017-12-2319:41borkdudeyeah, you could#2017-12-2319:41borkdudeI optimized one instruction: once you find something to be true, jump ahead so the loops are short circuited#2017-12-2319:41bhaumanyeah that would help but still slow#2017-12-2319:41thegeezI replaced loops with clojure loops that were smarter, that finished in 2 seconds#2017-12-2319:43thegeezNot sure if that counts as optimized assembly or a calculation of the answer, perhaps both#2017-12-2319:44borkdudeEarlier today I was thinking, maybe I could write it in C and let the C compiler optimize the assembly, but then I didn’t know yet what it was doing. Knowing this, it will probably surely not work.#2017-12-2319:49erwinWhen you understand the instructions enough to write the C code it is faster to just calculate the answer and be done with it#2017-12-2319:50borkdudeI know, but … fun … adding the mod instruction back like @bhauman could surely work, but I’m kind of done with it.#2017-12-2319:54erwinyou could add mod and remove one loop and shortcut the algorithm, but than you could also just use isProbablePrime from BigInteger and run your algorithm a couple of rounds to find the values for b and c. #2017-12-2319:55borkdudeyup#2017-12-2319:56erwinthe theme for the last couple assignments is, do the easy thing and make it ridiculous for part 2.#2017-12-2319:56borkdudeI guess so yeah#2017-12-2320:22borkdudefwiw, my code: https://github.com/borkdude/aoc2017/blob/master/src/day23.clj#2017-12-2409:41borkdudemy code for today: https://github.com/borkdude/aoc2017/blob/master/src/day24.clj#2017-12-2412:25borkdudewonder if I could use tree-seq#2017-12-2414:50ihabuneki wonder if i could use a zipper 🙂#2017-12-2415:23bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day24.clj#2017-12-2415:30bhaumanyou could use a tree-seq if you include the current state with each child-node#2017-12-2415:34mfikeshttps://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_24.cljc#2017-12-2415:44ihabunekhah, TIL: http://clojuredocs.org/clojure.set/index#2017-12-2415:45ihabuneki could have used that knowledge earlier today#2017-12-2415:45mfikesYeah, that's a rare gem. I happened to use it in day 7 https://github.com/mfikes/advent-of-code/blob/202768383a22d6cb0d37ef7b73dab32b21cb8085/src/advent_2017/day_07.cljc#L27#2017-12-2415:47ihabunek@mfikes nice concise solution#2017-12-2415:48mfikesIt seems that some amount of golfing makes code easier to comprehend, but if you push it too far, you lose the balance.#2017-12-2415:58borkdude@bhauman, yeah, that way I would only have to build the tree on not visit each node afterwards but only apply tree-seq on it#2017-12-2416:01borkdude@mfikes interesting looking and concise solution. is it fast?#2017-12-2416:01mfikesPart 2 is around 12 seconds#2017-12-2416:02borkdudeDidn’t think about concision, although I might try the tree-seq approach.
(time (part-1)) ;; 1859, ~5.8s
(time (part-2)) ;; 1799, ~6.4s
#2017-12-2416:02borkdudePart 2 is almost identical to part 1 in my code#2017-12-2416:55borkdudeLittle speedup by not even building a tree anymore: https://github.com/borkdude/aoc2017/blob/master/src/day24.clj#L90
(time (part-1)) ;; 1859, ~5.8s
(time (part-1')) ;; 1859 ~4.8ms
(time (part-2)) ;; 1799, ~6.4s
(time (part-2')) ;; 1799, ~5.0s
#2017-12-2416:59borkdudeThis may be how @bhauman does it too? https://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day24.clj#L37 Might try his index too.#2017-12-2418:49borkdudeWith index, 1.7s for part 2 now https://github.com/borkdude/aoc2017/blob/master/src/day24.clj#L152#2017-12-2420:06borkdudeVery clean solution in SQL: https://github.com/xocolatl/advent-of-code/blob/master/Day24/script.sql#2017-12-2422:23bhaumanAdded a tree-seq example at the end. I prefer it as a solution.#2017-12-2422:23bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day24.clj#2017-12-2422:36bhaumanI just cleaned it up a bit more#2017-12-2422:37borkdudeit’s a very cool way of using tree-seq again, unexpected because the root you’re passing doesn’t look like a tree, but as long children and branch? return something useful it just keeps going 🙂#2017-12-2422:37bhaumanyeah its really a tree of states#2017-12-2422:38borkdudeNot building a tree, but only return the answers is still faster though + the index really speeds it up significantly#2017-12-2422:38bhaumanyeah no intermediate structures#2017-12-2422:38borkdudeNot that that is important, but it’s nice to play around with these trade offs#2017-12-2422:39bhaumanhmmmm I does tree-seq return a reducable?#2017-12-2422:39bhaumanno its a lazy-seq for sure#2017-12-2422:40bhaumanthat would be a nice project to make tree-seq implement the reduce protocols#2017-12-2422:40borkdudeoff to bed… tomorrow the last day of AOC…#2017-12-2422:40bhaumanhave a good one!#2017-12-2502:44minikomisuper far behind because of end of year work 😕#2017-12-2502:44minikomimaybe i'll try to squeeze today in then fill in the past days#2017-12-2504:24minikomiweird.. got day21/1 but not /2#2017-12-2505:01minikomihttps://github.com/minikomi/advent-of-code/blob/master/src/advent/2017/day21.clj#2017-12-2505:01minikomiany easy overlooked-rule type bugs? keep getting the wrong output for part2 😕#2017-12-2506:11mfikesDay 25: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2017/day_25.cljc#2017-12-2506:14fellshardHeheh, you actually parsed the directions from the file. 😄#2017-12-2506:14fellshardI took the boring way out to start#2017-12-2506:15fellshardMaybe I'll do that later 🙂
#2017-12-2506:15mfikesYeah, I was tempted to just write it in code 🙂#2017-12-2506:15mfikesEspecially since the input was so short 🙂#2017-12-2507:30borkdudeToday was easy. I think the ethical thing of them to do, to have a nice Christmas day with the family 😉#2017-12-2507:36borkdudeThanks all for the fun times in here the last 25 days!#2017-12-2508:24borkdudeNice t-shirt: https://teespring.com/advent-of-code-eu#pid=389&amp;cid=100029&amp;sid=front#2017-12-2510:10ihabuneki skipped parsing of input today, not a part i really enjoy, and very simple to convert to a clojure structure in an editor using multicursors 🙂#2017-12-2510:10ihabuneki was also slightly afraid that they will come up with something terrible today#2017-12-2510:49ihabunekmy code, nothing very clever: https://github.com/ihabunek/aoc2017/blob/master/src/aoc2017/day25.clj#2017-12-2510:51borkdude@ihabunek very similar to mine 🙂 https://github.com/borkdude/aoc2017/blob/master/src/day25.clj#2017-12-2510:51ihabunekah, iterate#2017-12-2510:51ihabuneki tend start with loop/recur and forget about iterate#2017-12-2510:51ihabunekhow fast is yours?#2017-12-2510:51ihabunekmine takes a bit, ~15s#2017-12-2510:52ihabunekah, i see the comment, 10s#2017-12-2510:52borkdudeiterate applies to a lot of solutions. 10s over here on a Macbook Pro 15" 2015#2017-12-2510:52borkdudeI’ve read somewhere in an article that all puzzles should run below or around 10s on 10year old hardware#2017-12-2510:53ihabunekyeah, saw that#2017-12-2510:53ihabunekbut depends on the language i guess#2017-12-2510:53borkdudeRight, I think he means when you’re using a mutable language like Java or C#2017-12-2510:54ihabunekon my desktop (bash on windows, i5), your solution takes 8s, and mine takes 6s#2017-12-2510:54ihabunekon my laptop it takes 15ish#2017-12-2510:55borkdudeAnd we can get to that speed, @mfikes and I got to world domination on day 5: https://github.com/borkdude/aoc2017/blob/master/src/day05.clj#L115#2017-12-2510:55borkdudeYes, loop recur is somewhat faster than iterate I think, because it doesn’t construct a seq#2017-12-2510:57ihabunek@borkdude need to examine that 🙂#2017-12-2511:00borkdude@ihabunek
(time
   (loop [counter 0]
     (if (= counter 100000000)
       counter
       (recur (inc counter))))) ;; 33ms

(time (nth (iterate inc 0) 100000000)) ;; 2797 ms
#2017-12-2511:00ihabunekright, seqs have some overhead#2017-12-2511:01ihabuneki learned that on one of the earlier days#2017-12-2511:08borkdudeSlightly faster:
(time
   (transduce
    (drop 100000000)
    (fn
      ([] nil)
      ([acc] acc)
      ([acc n]
       (reduced (or acc n))))
    (iterate inc 0))) ;; 1915ms
Not sure if there is anything better with transducers + iterate to make the overhead smaller.
#2017-12-2512:58thegeezMission accomplished! Thanks everybody that was fun#2017-12-2513:41tbaldridge@borkdude in newer versions of Clojure (1.8+ IIRC) that can be done with (range) instead of (iterate). If the input args are longs there's a fastpath in Clojure that produces a reducible that stores the state as unboxed longs.#2017-12-2520:59borkdudeThe input arg for my typical use aren’t ints, I just need the behavior of iterate to produce successive game states#2017-12-2513:57mfikesOn my hardware, the transduce over iterate above takes 2071 ms in the clj REPL. With the update to iterate in ClojureScript master, in Planck this same form takes 1779 ms.#2017-12-2514:01mfikesInterestingly in the node REPL the first execution takes around 750 ms, and subsequent ones drop back down to 1800 ms.#2017-12-2520:08bhaumanhttps://github.com/bhauman/advent-of-clojure-2016/blob/master/src/advent_of_clojure_2017/day25.clj#2017-12-2520:11bhaumanIt's been super fun and educational to do this with you all! Thanks for everything!#2017-12-2520:11bhaumanMerry Holidays!#2017-12-2520:37tbaldridgeThis is a type of project where Cljs really shines. The JS jits are much better at auto unboxing#2017-12-2603:05minikomiwhew#2017-12-2603:05minikomifixed my day21. was off by 90 degrees on my "split" function, the resulting matricies were in order of column instead of from left to right#2017-12-2610:52minikomiwooh, used a juxt in the wild lol#2017-12-2611:15borkdudeIf anyone is bored: https://challenge.synacor.com/#2017-12-2612:04ihabunekthat's by the same guy as aoc i believe#2017-12-2612:04ihabunek@minikomi me too, 🙂 https://github.com/ihabunek/aoc2017/blob/38c323f3a792af865a6a4dcd1dd966be1db6db9e/src/aoc2017/day20.clj#L32#2017-12-2612:05ihabunekfor some reason i was confused by juxt in the beginning, but maybe just because of the name, it's simple and useful#2017-12-2613:57mfikesYeah the sort-by / juxt composition is curiously strong 🙂#2017-12-2623:52bhaumanI highly recommend TIS-100 if you are looking for programming challenges#2017-12-2709:22ihabunekIMO, all Zachtronics games are worth getting into. I rarely manage to finish them and feel a little stupid though. 🙂 Recently got Shenzshen IO which is similar to TIS-100, assembler-like puzzles.#2017-12-2709:23ihabunekAnd SpaceChem was great too.#2017-12-2718:52bhauman@U4P4E2FMZ I just got Shenzen IO 🙂#2017-12-2702:27minikomiYeah, sort-by / juxt, for / :let/ :with and using tree-seq creatively were my biggest takeaway from doing advent#2017-12-2703:44theeternalpulsebeen on vacation but finally got my day 3 part 2 white whale. That was fun lol. https://github.com/deepee0086-clj/adventofcode-clojurians/blob/master/src/day_03.clj#L69#2017-12-2704:05minikomidone 🎄 that was fun, glad to be in here hacking with all of you#2017-12-2818:52orestisHey all! I’ve had to skip a few days around Christmas, but I’m finally all caught up. It’s been a great pleasure and honour to be able to learn so much from everyone in this channel. Thank you all!#2017-12-2819:02orestisMy Day 24 with tree-seq: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day24.clj#2017-12-2819:03orestisDay 25 is traditionally a simple one: https://github.com/orestis/adventofcode/blob/master/clojure/aoc/src/aoc/2017_day25.clj#2017-12-2821:51fellshardOof. Gave Synacor a poke, got the basic VM running. I forgot how rough it is working with bytes in Clojure.#2017-12-2908:34ihabunek@U1YPTG4UF i did the same, as far as i can tell it's impossible to read unsigned bytes?#2017-12-2909:21fellshardI have to consume them as signed bytes, then convert to their unsigned values inside a short.#2017-12-2901:16mfikes@bhauman I needed a reducible tree-seq for Planck (to avoid head-holding in its file-seq implementation), and came up with this
(defn reducible-tree-seq
  [branch? children root]
  (eduction
    (take-while seq)
    (map first)
    (iterate (fn [[node & queue]]
               (cond-> queue
                 (branch? node) (into (reverse (children node)))))
      [root])))
Dropping it into your day 24 solution (replacing tree-seq with reducible-tree-seq) appears to drop the runtime in half (probably simply because it is not lazy). I also tried a variant
(transduce (map #(nth % 2)) max 0
  (reducible-tree-seq branch? children [index 0 0 0]))
with similar results. Strictly speaking, since it returns an eduction, it doesn’t directly implement the reducing protocols, but if you feed it to transduce you effectively get what you want.
#2017-12-2903:02bhauman@mfikes very cool and super interesting how simple the implementation is#2017-12-2910:42borkdudeHas anyone though of doing adventofcode directly in emacs using elisp + a text buffer? 😉#2017-12-2911:49karlisSomeone published an elisp solution in reddit: https://www.reddit.com/r/adventofcode/comments/7h5n38/2017_day_2_part_1_2_emacs_lisp_still_resist_to/#2017-12-2915:16mfikesI got Shenzhen I/O and am playing it with my son. It's a pretty good game (teaching him assembly without him really realizing it.) 🙂#2017-12-2917:59orestisI blogged about my experience with Clojure and Advent of Code: https://orestis.gr/25-days-of-clojure/#2017-12-2919:06spfeifferI would be very interested in the spacemacs/CIDER demo video. I like spacemacs, but i am not yet into REPL-driven development.#2017-12-2919:51ihabunekme too, i'm using the repl but i have a feeling i'm missing out on a lot of the experience#2017-12-2918:41bhaumanposted to Hacker News#2017-12-2919:50borkdude@orestis Thanks for the writeup. What did you mean with apropos-like functionality? I suppose you didn’t mean clojure.core/apropos?#2017-12-2923:19orestisI mean similar to the apropos Linux command where you search a command by your intention, and you get a list of suggestions. #2017-12-3000:04mfikes@bhauman and others playing Shenzhen I/O—it looks like it allows you to do in-app solution scores with other people you have as friends in Steam. I have no clue how it really works, but if anyone is interested in this, my son and I are playing via the steam account fikesfarm.#2017-12-3000:05bhaumancool, have you tried TIS? is Shenzen better?#2017-12-3000:05bhaumanI bought it but haven't tried it yet @mfikes#2017-12-3000:05mfikesIs TIS the older game by the same vendor?#2017-12-3000:06bhaumanhttp://www.zachtronics.com/tis-100/#2017-12-3000:06bhaumannot sure of the release date#2017-12-3000:06mfikesI think I tried buying all of those games in one big bundle, but noticed that the bundle did not target macOS, so, I just bought Shenzen separately since it did.#2017-12-3000:08bhaumanTIS-100 was released in 2015 where as Shenzen was released in 2016#2017-12-3000:08bhaumanI'll give it a try now#2017-12-3000:10bhauman@mfikes whats interesting about assembly for teaching children is that there is a lot less abstraction, i.e. no variables#2017-12-3000:10bhaumanmoving values is explicit#2017-12-3000:14mfikesExactly, I was explaining this to my 12-yo daughter. (That she could play the game without having to learn an extensive programming language per se.)#2017-12-3009:18ihabunekTIS-100 is excellent in it's simplicity, whereas Shenzhen adds more complex components.#2017-12-3009:19ihabunekI still haven't finished all of TIS, have solved 17 out of 25 segments.#2017-12-3009:21ihabunekI found out about it on a pre-conference party for Dom Code where organisers printed out the manual for everyone, paired people up and let us play. It was a great idea and worked out well.#2017-12-3009:23ihabunekIt really brought me back to my earliest programming days, flipping through the manual for locomotive basic 🙂#2017-12-3009:36ihabunekif anyone wants to link up on steam, i'm https://steamcommunity.com/id/ihabunek#2017-12-3014:20mfikesMy son and me: https://steamcommunity.com/id/fikesfarm#2018-12-3100:36fellshardhttps://steamcommunity.com/id/kenogulabz/ , I love a good Zachtronics title#2018-01-0216:47dpsuttonhas anyone seen a better answer for day 20 (colliding particles) rather than it's just stabilized at this number? The first part can be solved because there is a particle with a minimum acceleration, but if not for this it would be quite a bit more difficult. Similarly, the end of collisions seems to happen after a few iterations but there is no guarantee of this.#2018-01-0218:39ihabunek@dpsutton a friend solved it using quadratic equations to detect collisions, but in elixir: https://gist.github.com/sasa1977/a35e87540669f32c28e3bd2b7698ca7e#2018-01-0702:09mfikesMy son and I are now investigating solving Shenzhen I/O problems in hardware 🙂 https://youtu.be/mCAhQtpnl94#2018-01-0702:34bhaumanthats dang impressive 🙂#2018-01-0703:22fellshardThat's an awesome next step!#2018-01-0708:11ihabunekthat's brilliant 🙂#2018-01-0902:20minikomiawesome#2018-01-1017:53mfikes@bhauman FWIW, while it would be much faster, we can’t have a directly-reducible version of tree-seq. Details are in the last comment in https://dev.clojure.org/jira/browse/CLJS-2464#2018-01-1017:55mfikesYou can always define your own tree-seq' as illustrated here: https://gist.github.com/mfikes/cc1d1fac47e7dc112b0b9f4e3de11eae#2018-01-1019:09bhauman@mfikes coolio, thanks for the update#2018-01-1510:49borkdudehttps://twitter.com/borkdude/status/952855100422225920#2018-01-1512:54ihabunek\o/#2018-01-1517:43borkdudeLOL: https://www.reddit.com/r/adventofcode/comments/7q6s80/2017_optimized_solutions_in_c_195_ms_total/#2018-01-1517:46borkdude@mfikes so far for world domination#2018-01-1518:04val_waeselynckHa, he also used exponentiation on day 16, was hoping to beat him on that point#2018-01-1518:04val_waeselynck(or she)#2018-01-1707:30minikomiyeesh#2018-01-1720:41borkdudeParser performance comparison for day 16: https://github.com/borkdude/aoc2017/blob/master/src/day16.clj#L244#2018-01-1914:21bhaumanI recently wrote a regexp to tokeninze clojure code it runs in under a single millis to parse a large amount of text. Regexps are freaking fast.#2018-01-1915:08borkdude@bhauman yes, that’s what my handwritten parser does (well in multiple steps, but it could be optimized into a single regex maybe). It’s by far the fastest.#2018-01-1915:10borkdudebut regexes only go so far, context free grammars are more powerful (nested parens for example), so sometimes it’s very convenient to use something like Instaparse#2018-01-1916:31bhauman@borkdude agreed 🙂#2018-05-2410:44minikomianyhting advent of code-y these days? that was super fun.#2018-05-2413:47borkdudeyes, it was 🙂#2018-05-2414:27yogidevbearI saw a reddit thread that said there were the previous 2 years of aoc that you could attempt too#2018-05-2416:36bhaumanyes it was a blast#2018-05-2417:10fellshardThe backlog is quite good as well, if not better. There were one or two real good headscratchers from 2015, I think?#2018-05-2417:22spfeifferI am still stuck in the 20's of 2015 😂#2018-05-2417:23spfeifferBecause of lack of time#2018-05-2418:14borkdudeThere is this one from a local company. You might get the text by translating it to English: https://aoc.infi.nl/#2018-05-2418:14borkdudeDidn’t do that one yet. Might if I’m bored.#2018-05-2418:18borkdudeYou could also write your own puzzles and share it with us 😉#2018-05-2419:13thegeezThe problems on this site are slightly larger, but also fun: https://cryptopals.com/#2018-05-2502:05minikomithe scramble-to-finish then refine feeling was a rush haha#2018-05-2502:12theeternalpulseI've been doing javascript-30 by wes bos.#2018-05-2502:12theeternalpulsethough I have to at least have reagent 🙂#2018-06-2604:23minikomihttps://www.reddit.com/r/dailyprogrammer/comments/8sjcl0/20180620_challenge_364_intermediate_the_ducci/#2018-06-2604:23minikomiwe can do these from time to time if you guys are interested#2018-09-1312:01borkdudefyi, there is also a #puzzles channel#2018-11-2210:16borkdudeI’m thinking of collection some test Clojure programs to run with speculative (a collection of specs for core functions). I made a small start here: https://github.com/borkdude/advent-of-spec#2018-11-2210:17borkdudeWhose Advent of Code code can I include in this repo? PRs are welcome of course#2018-11-2210:18borkdudeCode will be anonymized, so you don’t have to fear your solution will be compared with others 😉.#2018-11-2210:18val_waeselynckThat's fine by me, but are we talking about this year's AOC or last year's?#2018-11-2210:19borkdudeany year. I’ll try to include as many as I can, time permitting. But it’s most fun to include this year in “real time” of course#2018-11-2210:21borkdudeThe purpose is mostly to check our specs or to encounter usage we didn’t think of before.#2018-11-2210:25val_waeselynckHere you go: https://github.com/vvvvalvalval/advent-of-code-2017#2018-11-2210:27borkdudethanks!#2018-11-2210:31athosFeel free to use my code! 😃 https://github.com/athos/advent-of-code-2017#2018-11-2210:32eval2020How about running this year’s codeofadvent on Zulip? I created a stream there at https://clojurians.zulipchat.com/#narrow/stream/152583-adventofcode Apart from having history, and syntax highlighting it would give us an easier way to discuss exercises in a spoiler-free way.#2018-11-2210:32eval2020ah, you posted just there borkdude 😉#2018-11-2210:32borkdudeIdea for Zulip: make a topic per day?#2018-11-2210:33eval2020yeah something like that#2018-11-2210:33eval2020could be even day X exercise, day X answers#2018-11-2210:33eval2020let’s see what people come up with#2018-11-2216:00borkdudeInterestingly I get different answers for day 2017 day 2 for both @mfikes and @athos than my solution, while the Advent of Code page says my answer is correct#2018-11-2216:01borkdudehttps://github.com/borkdude/advent-of-spec/blob/master/src/aos/y2017/d02.cljc#L114#2018-11-2216:02mfikesRight, since the data varied per user, sometimes you get away with a non-general solution :(#2018-11-2216:03borkdudeShould the code work with all input data and return the same output given the same input? Think so?#2018-11-2216:05mfikesIdeally, each individual’s solution would work on other individual’s data.#2018-11-2216:05borkdudeok, maybe I’ll change the test assertion to (number? ...) instead of a specific answer then.. since I will take too much work aligning them#2018-11-2510:09thegeezHi folks, the repo is ready for links to your solutions for 2018: https://github.com/adventofcode-clojurians/adventofcode-clojurians#2018-11-2615:23magic_bloatHowdy people. Is there a 2018 clojure leaderboard yet?#2018-11-2616:12eval2020FYI as announced on Reddit Saturday (https://www.reddit.com/r/Clojure/comments/9zzgbz/lets_learn_clojure_advent_of_code_2018/), there’s also an AoC-channel on Clojurians-Zulip this year. It has persistent messages and allows (among other things) for easier spoiler-free discussion of puzzles.#2018-11-2710:51borkdudeVarious solutions are now also timed in clojure + clojurescript (look at the test step): https://circleci.com/gh/borkdude/advent-of-spec/6#2018-11-2913:06potetmI figured here was a good place to announce that I’m going to be live streaming AoC this year. Weekdays @ 12:00 CST https://www.twitch.tv/timpote#2018-11-2914:52practicalli-johnCool, I will mention your twitch on my broadcast on Saturday (11am UTC). That gives us all a few hours to try solve it ourselves before your broadcast. Good luck.#2018-11-2915:02potetmThat would be awesome! Thank you!#2018-11-2913:08potetmSpecifically going to be targeting Clojure beginner-intermediates. So if you know someone trying to pick up clojure, please point them my way.#2018-11-2917:22heliosI hope this is not too OT: other than the advent of code keep in mind also this idea for the holiday spirit: https://24pullrequests.com 😉#2018-11-2918:03borkdude@helios you can combine Advent of Code and 25 pull requests by contributing to https://github.com/borkdude/advent-of-spec 😄#2018-11-2919:23helios😉#2018-11-3010:47borkdudePivoted to “Advent of CLJC”, main challenge is now to create portable solutions. https://github.com/borkdude/advent-of-cljc#2018-11-3012:12mfikesCool!#2018-11-3015:48potetmGonna be doing a warmup round at 12:00 CST today! https://www.twitch.tv/timpote#2018-11-3020:31andofrynI wasn’t able to watch the stream live but watched the recording and this has been very informative! Thanks a lot for doing these :thumbsup:#2018-11-3015:48potetmhttps://adventofcode.com/2017/day/5 for the interested#2018-11-3015:52borkdudethat’s in 2h10m if I’m reading https://everytimezone.com/ correct#2018-11-3017:43markbastianHey all, is this the channel for all advent of code or just clojure? What I'm really looking for is the url to receive and submit challenges to if I were doing the advent of code in clojure.#2018-11-3017:44Mario C.Is there a leaderboard?#2018-11-3017:44markbastianhttps://adventofcode.com/2018 <- is that it? Sorry, I haven't participated before and it isn't clear where to get on board.#2018-11-3017:46Mario C.Yea so once Dec 1 comes around the number one becomes clickable. Then you can read the challenge and they provide your input data and all they care about is the result. So they will have an input field for the solution where you just type it in. @markbastian#2018-11-3017:47markbastianThanks so much. I was thinking it was language specific, but I'll just head over to https://adventofcode.com/2018 tomorrow morning.#2018-11-3017:48dpsuttonthe challenges just allow entering an answer so any language will do. people did it in postgres last year. probably tex or something equally crazy#2018-11-3017:49natewow, that's interesting. wonder if anyone did them in COBOL#2018-11-3017:49potetm@markbastian Not trying to over-plug my thing, but in 10min you can see exactly what the process looks like during my stream.#2018-11-3017:50Mario C.Is there a leaderboard for the channel?#2018-11-3017:50markbastianI'll have to check it out when I get off work. Thanks!#2018-11-3017:52dpsuttoni'm sure someone did them in cobol#2018-11-3017:57lilactownregex AoC anyone?#2018-11-3018:00Mario C.I still can't fathom how some people are solving them in 1-3 mins#2018-11-3018:02nateheh, yeah#2018-11-3018:02natesome are pretty fast, but you can find puzzles that take more than an hour#2018-11-3019:06borkdudeI know someone from Twitter who did it in pure Postgres last year and will do so this year#2018-12-0105:31karlishappy advent of code 2018 everyone! 🎉#2018-12-0105:32karliswoke up, made coffee, read the puzzle 1 & wasn't sure if I'm still half asleep or is that really a 1-liner.#2018-12-0105:54nateheh#2018-12-0106:00fellshardDay one is usually just a warmup. I use the time I'd normally take to get the environment warmed up, etc.#2018-12-0106:01fellshardI have a standard workspace I use now for these, since there's a lot of common core utils - reading from resources file, parsing integers, defining coarsely-curried functions for interpreters, etc.#2018-12-0106:01orestisHappy puzzling! I did today’s in Replete typing on an iPad keyboard :)#2018-12-0106:04nate@orestis wow!#2018-12-0106:05orestisYeah but it’s tiny :) #2018-12-0106:06orestisI don’t think I will do another, though with some love replete could easily be much more useful. Being able to save some files locally or even better to iCloud, some helpful keys above the keyboard. I wonder if it’s open source. #2018-12-0106:12orestisIt is! Perhaps I’ll pivot from AoC this year then. #2018-12-0115:15mfikesYeah, I maintain Replete. Custom keyboard stuff is always challenging to pull off while preserving the polished feel, but I definitely agree there could be some keyboard improvement. (You can always use a 3rd party keyboard with it.) The ability to save and edit locally or in iCloud would be nice. We can't do this, as it is not allowed http://blog.fikesfarm.com/posts/2015-08-11-loading-clojurescript-into-your-iphone.html but perhaps content created in Replete could be saved without violating any App Store rules.#2018-12-0106:28lilactownI feel like there’s a clever use of lazy seqs in the 2nd part that I’m not seeing#2018-12-0115:18mfikesHere is a way to do it using only lazy seqs, but in the end, I didn't like that approach compared to just a direct reduce to find the dup. https://gist.github.com/mfikes/53c53673f66257878ab82408635f297d#2018-12-0106:29nateYeah, or using cycle#2018-12-0106:49orestisGiven my constraints, I just went with a loop recur for part 2. Not much room for experimenting. #2018-12-0106:50potetmmy part 2 was def not 1 line#2018-12-0106:52orestisYeah, more like 10 in my case. It’s gone now so I can’t count :)#2018-12-0107:48borkdudeSubmitted my solution for day 1 to Advent of CLJC: https://github.com/borkdude/advent-of-cljc#2018-12-0107:51borkdudecurious about your solutions. if you want you can make a PR and add it to the repo#2018-12-0107:52borkdudeThe fun thing is you can see the timing of every day and user here: https://circleci.com/gh/borkdude/advent-of-cljc/55 when you scroll to the test execution#2018-12-0108:20helios@borkdude where is the private leaderboard? 🙂#2018-12-0108:22Mario C.wow part 2 was a doozy!#2018-12-0108:23Mario C.are we allowed to post solutions here?#2018-12-0108:35borkdude@helios I don’t know if there is a leaderboard. You might want to create one? @mario.cordova.862 You could also submit a PR to the above repo as an alternative of posting your solution here 🙂#2018-12-0108:36borkdudeI wouldn’t post your code here directly, a gist would be more appropriate. Of if you’re going to post it, post it only in a thread, so people don’t see the spoiler.#2018-12-0108:36helios57048-763fafc9 is the code for the private leaderboard#2018-12-0108:37borkdude@helios thanks. might also want to add it to the https://github.com/adventofcode-clojurians/adventofcode-clojurians repo#2018-12-0108:39helios@borkdude done. also added myself#2018-12-0108:49Mario C.@borkdude Added myself to the readme#2018-12-0108:50borkdude@mario.cordova.862 can you rebase your PR? it has a conflict now#2018-12-0108:50niels #2018-12-0108:57Mario C.@borkdude done!#2018-12-0109:01orestisThere used to be an adventofcode-clojurians leaderboard, but I don’t have the invitation code. Perhaps clojurians slack log might have it?#2018-12-0109:34karolCreated pull request for adventofcode-clojurians. Also slightly offtopic does anyone else has a internal conflict of writing things in a simple way vs smart? I ask because as a developers I feel that we are constantly judged on quality of our code and how "smart" it is but when reading other people code I like things rather simple.#2018-12-0109:45borkdude@karol Sometimes there’s a balance between keeping it simple and hacking it for performance#2018-12-0109:47karolof course, and that is why I like advent of code because usually the first part can be done without optimization and you need to be clever in second part 😉 but I am fan of optimize only when needed and don't introduced layers of abstraction "for future", because I saw few clojure codebases that look like Java EE with parentheses but it is morning here so I might be just complaining 😄#2018-12-0110:04borkdudeI found the old leaderboard code, updated the topic (cc @helios)#2018-12-0110:04borkdudedidn’t know the leaderboards could be re-used over multiple years#2018-12-0110:11helios👍#2018-12-0110:12heliosi have no idea how AoC works, are points based on time as well?#2018-12-0110:17borkdudethe faster you solve the problem, the higher your score in the leaderboard#2018-12-0110:22heliosgotcha#2018-12-0110:42magic_bloatAnd its nothing to do with when you start solving! Time starts for everyone when the problem appears.#2018-12-0110:48borkdude@denis.fuenzalida @dandorman thanks for contributing to advent of cljc https://github.com/borkdude/advent-of-cljc#2018-12-0110:49orestisI just realized what advent-of-cljc is, I’ll be forking that as well.#2018-12-0110:49orestisShould we add more inputs there?#2018-12-0110:52borkdudeno, the author of advent of code explicitly forbids it#2018-12-0110:52borkdudeSee: https://github.com/borkdude/advent-of-cljc/issues/6#2018-12-0110:52borkdudeSo we’ll have to do with the input of whoever does the first PR#2018-12-0110:58borkdudeupdated the README to reflect this#2018-12-0111:01orestisWorth to do the runs at least a few times to ensure warm up for the timings etc?#2018-12-0111:04borkdudeMaybe. I’m not sure how this will work out if multiple users contribute all of their days. If it gets too slow on CI, I might filter the tests only for that user. So running tests multiple times might be something you want to do locally#2018-12-0111:07orestisI guess not too important at this point, the corpus is the important thing. Great initiative!#2018-12-0111:07orestisI’ve submitted my PR. I’ll use this for this years puzzles.#2018-12-0111:17borkdudeThanks! Merged.#2018-12-0112:37TimMy repl is timing out on my part 2 solution.. 😅#2018-12-0113:23TimWould anyone have some time to help me? My process keeps running for part 2 with the puzzle input and just never ends, if I use one of the examples as the input though it does seem to work... (I'll post my code as a thread to this message so spoiler alert!)#2018-12-0113:24Tim
(def input (mapv read-string (str/split (slurp "./input") #"\n")))

(defn step [{:keys [frequency-changes current-index frequencies]}]
  (let [
        new-index (mod (inc current-index) (count frequency-changes))
        last-frequency (or (last frequencies) 0)]
    {
     :current-index new-index
     :frequencies (conj frequencies (+ last-frequency (get frequency-changes current-index 0)))
     :frequency-changes frequency-changes
     }))

(defn last-item-double [l]
  (and (> (count l) 1) (> (.indexOf (butlast l) (last l)) -1)))


(defn part2 [frequency-changes] (last (:frequencies (step (last (take-while
 (fn [state] (not (last-item-double (:frequencies state))))
 (iterate step {
        :frequencies []
        :frequency-changes frequency-changes
        :current-index 0
        })))))))

(part2 input)
#2018-12-0115:09orestisYou are using a very inefficient algorithm to check for an already seen item. Using .indexOf etc etc means every time this run means it has to “walk” all the previous steps again and again.#2018-12-0115:10orestisConsider keeping the previously seen frequencies in a set instead.#2018-12-0115:10orestisAs an aside, also consider formatting your code a little bit better as it can be really hard to follow 😄#2018-12-0120:09Timthanks for the feedback! I got it to work way faster with a different approach, using loop/recur and a set as you suggested#2018-12-0120:09Timthough my initial solution did end after 1h40 or so 🙈#2018-12-0120:09Timregarding code formatting, is there a general coding guideline for clojure and a linter like there is for python?#2018-12-0121:13orestisThere is the clojure style guidelines by Bbatsov, and a few linters. There’s a big discussion right now going on in ClojureVerse about this so you can find more info there (sorry, on mobile so can’t paste links easily)#2018-12-0121:32TimI'll have a look at them, thanks for your help!#2018-12-0113:44benoitMy solution for day 1. https://github.com/benfle/advent-of-code-2018/blob/master/day-1.clj#2018-12-0114:39ihabunekHere's mine https://git.sr.ht/%7Eihabunek/aoc2018/tree/master/clojure/src/aoc2018/day01.clj#2018-12-0114:39ihabuneki'm actually doing it in clojure and elixir in parallel, but pretty sure i won't have the time or willpower to do it all the way through in both languages#2018-12-0114:41ihabunek@me1740 using state, le gasp 😄#2018-12-0115:04benoitSimplified to use cycle. I forgot about this function. Thanks. Yes state is debatable here but since it improves readability and reusability I opted for it 🙂#2018-12-0115:22potetmI think this problem is going to be a lot of fun on the stream.#2018-12-0115:23potetmI can think of a bunch of different ways to solve it offhand — none of them will take particularly long.#2018-12-0115:24ihabunekWho is streaming?#2018-12-0115:24potetmI am: https://www.twitch.tv/timpote#2018-12-0115:25potetmM-F @ 12:00 CST (UTC-6)#2018-12-0115:27ihabunek👍 nice#2018-12-0115:54Mario C.How would day 2 be solved if we had memory constraints? #2018-12-0115:55borkdudeday 2?#2018-12-0116:08potetmwe have a cheater! 😛#2018-12-0116:09Mario C.Sorry Day 1 Part 2 #2018-12-0116:11benoitAre people ok with discussing solutions here? What is the assumption about spoilers?#2018-12-0116:12nateMaybe put the spoiler code in a thread?#2018-12-0116:13mfikesI tend to not even read this channel until I'm done with my solution. Otherwise you might see solution strategies being discussed.#2018-12-0116:14mfikesFor example, you can't help from seeing cycle being mentioned. 🙂#2018-12-0116:15benoit🙂 yeah I realized that after the fact. Sorry.#2018-12-0116:15mfikesTo be honest, I enjoy seeing solution strategies being discussed. (Otherwise, where would they be, all in side threads?)#2018-12-0116:15nateGood idea to stay away.#2018-12-0116:16mfikesAlso, the ability to look at other people's solutions and other ideas is the main value I get out of this. Much more than solving the problems myself. 🙂#2018-12-0116:17benoitSo to answer Mario. I think if you stream in the changes and stream out the frequency in a sorted file you could solve it while just keeping one number in memory. But I didn't bother doing this 🙂#2018-12-0116:17mfikesThere have been some incredibly clever solutions in the past. 🙂#2018-12-0116:17Mario C.I tend to solve it first then come on here but I am guessing at later days when it becomes more difficult Ill be coming here for pointers :P#2018-12-0116:18mfikesYeah, there's a problem where you are stuck and want a little help, without seeing the solution. :thinking_face:#2018-12-0116:21nateHeh. Separate channel? #adventofcode-help ?#2018-12-0116:22potetm:moar_channels:#2018-12-0116:25mfikesOne thing I see now is that, even though my solution works on my data, I have a defect in it 🙂#2018-12-0116:25bhaumanMy solution https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day01.clj#2018-12-0116:28mfikesMy solution gives the wrong answer for this input: [5 10 20 -35]. I suspect this will be a common mistake.#2018-12-0116:29benoitMy first solution was not handling the case when there is no duplicate either 🙂#2018-12-0116:30borkdudeThanks for submitting your solution to https://github.com/borkdude/advent-of-cljc @mfikes!#2018-12-0116:30mfikesWastl even gives a simpler example of [+1 -1] in the page#2018-12-0116:36bhauman@mfikes good catch#2018-12-0116:37mfikesI only learned about this when I saw another solution catering to that case.#2018-12-0116:37mfikesMy solution https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_01.cljc#2018-12-0116:37bhaumanTRY ALL THE EXAMPLES#2018-12-0116:37mfikesIndeed#2018-12-0116:37bhaumanthat is the lesson I learn every year#2018-12-0116:38bhaumancause I forget#2018-12-0116:48ClashTheBunnyhttps://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day01.clj#2018-12-0116:51taylorand here’s mine, enjoying seeing the different solutions! https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/1.clj#2018-12-0116:56taylorfeeling pretty cheeky about (drop-while #(apply not= (swap-vals! seen conj %))) :man-juggling:#2018-12-0117:00ClashTheBunnyI also have the same issue with my solution. I wish there was a reduce-until function or something like that.#2018-12-0117:01taylorlike reduced?#2018-12-0117:06ClashTheBunnyDamn, time to refactor!!!#2018-12-0117:12ClashTheBunnyThanks!!!#2018-12-0118:04nateoh man, the reduced function!! TIL#2018-12-0116:51ClashTheBunnyI do wish somebody would make a data oriented source of the examples. I just want to pull in a mapping of input to output.#2018-12-0116:56Mario C.@taylor wow! Learned something new with reductions, reduced :thumbsup:#2018-12-0116:59taylornice! it seems a lot of people reached the same conclusion for part 2, though I shamelessly went with atoms for my first attempt
#2018-12-0117:02mfikesI really wanted to find a way to reuse distinct. Here is one way, but I'm wondering if there is some other clever way to reused the underlying capability in the core lib. https://gist.github.com/mfikes/53c53673f66257878ab82408635f297d#2018-12-0117:04taylorI thought about making a variation of distinct transducer like while-distinct or something#2018-12-0117:13taylor
(defn while-distinct []
  (fn [rf]
    (let [seen (volatile! #{})]
      (fn
        ([] (rf))
        ([result] (rf result))
        ([result input]
         (if (contains? @seen input)
           (reduced (rf result input))
           (do (vswap! seen conj input)
               (rf result input))))))))

(->> (cycle values)
     (reductions +)
     (eduction (while-distinct))
     (last))
though that name isn’t great because it includes the first non-distinct value :man-shrugging:
#2018-12-0117:09borkdudemy solution: https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2018/d01/borkdude.cljc#2018-12-0117:11borkdudeI’m not sure why people are using reductions?#2018-12-0117:11benoitTo get a sequence of the frequencies after applying the changes.#2018-12-0117:11lilactownyeah I ended up using loop-recur and cycles: https://github.com/Lokeh/advent-2018/blob/master/day1/src/advent/day1.clj#L54#2018-12-0117:11potetmTo generate a list of accumulations, instead of manually managing in reduce#2018-12-0117:12borkdudeclever#2018-12-0117:12potetmyeah#2018-12-0117:12potetmless efficient, but breaks part of the computation out#2018-12-0117:13_rj_r_is it less efficient since it is lazy? (I'm asking because I genuinely don't know)#2018-12-0117:14potetmit generates another data structure (the laziness only helps with efficiency).#2018-12-0117:14potetmIt’s honestly not something you should think about all the time. But I like running through various levels of efficiency in my head.#2018-12-0117:16potetmso, using cycle+reductions+reduce -> (seq of cycle) + (seq of reductions) + #{set of reduce}#2018-12-0117:16_rj_r_my thought was that pretty much either way a new data structure needs to be generated at least from the solutions I've seen thus far, so I wasn't sure if using reductions was actually less efficient than managing the computations and what has been seen in a reduce.#2018-12-0117:16potetmreduce is only (seq of cycle) + #{set of reduce}#2018-12-0117:17_rj_r_hmm.. I think I understand that#2018-12-0117:17potetmbut it’s evaluated lazily, so you only do the computational work that you must#2018-12-0117:17_rj_r_right.. gotcha#2018-12-0117:17_rj_r_thanks!#2018-12-0117:17potetmyep!#2018-12-0118:30pesterhazyyo!#2018-12-0118:31pesterhazyHere's my solution: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle01.clj#2018-12-0118:32pesterhazyI'm curious how much room for difference there is in a simple task like this#2018-12-0118:42potetmhttps://twitter.com/potetm/status/1068887983246532608#2018-12-0118:42potetmoff the top of my head, I’ve got ~5 diff ways to go about it#2018-12-0118:44pesterhazynice#2018-12-0118:45potetmI’ll ping back here after the stream with a link to github if you just want to review results.#2018-12-0118:35mfikesIt seems like most solutions involve a reduce or a direct loop / recur to essentially walk the sequence looking for the first dup.#2018-12-0118:36pesterhazy@mfikes I saw your tweet and couldn't resist 🙂#2018-12-0118:37ClashTheBunnyI thought a bit about how to just calculate it analytically, but didn't see anything easy. Did anybody come up with a way?#2018-12-0118:37mfikesExcellent. 🙂#2018-12-0118:37pesterhazyOf course I spent 90% of the time setting up the clj tool with nREPL and the Corfield Comma#2018-12-0118:39pesterhazy@mfikes your idea of using two reductions on top of each other is clever#2018-12-0118:40pesterhazyother than that mine is identical almost to a character#2018-12-0118:41dpsuttonreduce the reductions you mean?#2018-12-0118:41pesterhazyyeah#2018-12-0118:41pesterhazyis that a common FP pattern? I wasn't aware#2018-12-0118:42dpsuttoni did something similar. the data to investigate is the reduction. seems not necessarily FP but just this problem to me#2018-12-0118:42mfikesPaulus, does your solution handle the sequence [+1 -1]? (This is a common defect.)#2018-12-0118:42pesterhazyreduce is a great abstraction (obviously!) because you can swap in reductions and get a nice debugging output for free. Plus if the sequence doesn't terminate, you can lazily take n#2018-12-0118:42potetmoff the top of my head, I’ve got ~5 diff ways to go about it#2018-12-0118:43pesterhazy@mfikes yep#2018-12-0118:43mfikesCool#2018-12-0118:44dpsutton(first-duplicate (drop 1 (reductions + 0 (cycle values)))) yeah something similar#2018-12-0218:35rmprescottWhy the drop 1? This is probably related to why I disagreed with [+1 -1] => 0 rather than 1. But I still don't see why.#2018-12-0218:38dpsuttonyes it gets rid of the 0 sum for the sequence of length 0. i originally didn't have it#2018-12-0118:45mfikesMaybe some could be used to mechanize the linear scan?#2018-12-0118:46mfikesYour predicate would be stateful 😞#2018-12-0118:46pesterhazyMy solution uses a "composite accumulator", in this case a vector [acc-freq acc-seen]. I find myself reaching for composite accumulators often for less-than-simple reduces but I wonder if it's a good pattern#2018-12-0118:47potetmthat’s^ normal — although there’s often other ways of going about it#2018-12-0118:48dpsuttoni do that all the time. i only get annoyed because it usually requires a step to pluck apart the composite accumulator at the end#2018-12-0118:48pesterhazyThe (->> xs (reductions step-1 init-1) (reduce step-2 init-2)) pattern avoids the composite acc#2018-12-0118:50pesterhazy@dpsutton right, although when you know that you're going to end with reduced, you won't need it#2018-12-0118:53pesterhazyit would be interesting to compare performance as well. reductions must incur some performance cost#2018-12-0118:53dpsuttonI always feel a little bad using reduced. The short circuit makes me feel like I'm abusing reduce#2018-12-0118:54mfikesYeah, it always makes you feel like you failed, in some way. 🙂#2018-12-0118:54pesterhazy😆#2018-12-0118:54mfikesIt is like an inclusion an an otherwise perfect diamond.#2018-12-0118:54borkdude@pesterhazy I have the same pattern#2018-12-0118:55pesterhazy@borkdude ours are practically identical#2018-12-0118:56dpsuttonI've seen reducing functions defined outside of the reduce call where they include reduced and I have no idea what reduced does if it is not in a reducing context#2018-12-0118:58pesterhazyit just returns a special Java class, clojure.lang.Reduced#2018-12-0119:02pesterhazy@me1740's stateful predicate is interesting: https://github.com/benfle/advent-of-code-2018/blob/master/day-1.clj#L16 - I'm not sure how I feel about that#2018-12-0119:04mfikesRight, keep's docstring is at odds with that approach#2018-12-0119:05mfikesPerhaps, close to that idea, but safer, would be to take the source of distinct and produce an opposite function named duplicates, and then take the first from that#2018-12-0119:06potetmthat’s what I did^ for one of mine#2018-12-0119:06potetmcan use as a transducer#2018-12-0119:06mfikesYeah, and a nice little reusable fn falls out of the effort 🙂#2018-12-0119:06potetmyep 🙂#2018-12-0119:07potetmI was hoping to do a big unveil on stream then post back here w/ the code!#2018-12-0119:07mfikesHah. It is still a very nice solution. Especially if the transducer version is fast.#2018-12-0119:08potetmyeah I might benchmark them all for fun as well#2018-12-0119:08potetmgood point that#2018-12-0119:11pesterhazyI guess a stateful sequence processing function (like distinct) is safer than a stateful predicate#2018-12-0119:11potetmnot safer#2018-12-0119:12potetmbut stateful transducers are more idiomatic#2018-12-0119:12pesterhazy"safer" in the sense that using a stateful predicate for filter or keep is violating its contract#2018-12-0119:12potetmright#2018-12-0119:13potetmbut you could generate a lazy-seq of dups#2018-12-0119:13pesterhazywhereas the contract of sequences has no such provision#2018-12-0119:13potetmthat would be fine#2018-12-0119:13potetmright#2018-12-0119:14pesterhazyso the idea would be a while-distinct function?#2018-12-0119:14potetmjust (duplicates coll) the same as (distinct coll)#2018-12-0119:15pesterhazydoes the name duplicates make sense though?#2018-12-0119:15benoit@mfikes good catch. not sure why keep needs to be free of side effect though.#2018-12-0119:16pesterhazywe're looking for the opposite of duplicates, r ight?#2018-12-0119:16potetmI think so? “I want all of the duplicates in this seq.” As opposed to, “I want the duplicates removed from this seq.”#2018-12-0119:16potetmoh for the problem#2018-12-0119:16potetmyeah it depends on how you’re going about it!#2018-12-0119:17pesterhazygotcha, you'd use (->> xs duplicates first)#2018-12-0119:17potetmyep#2018-12-0119:18pesterhazyactually while-distinct would work only if it was inclusive of the dupe (which makes little sense)#2018-12-0119:21tayloryeah I had the same thought earlier, duplicates makes more sense https://clojurians.slack.com/archives/C0GLTDB2T/p1543684422093600?thread_ts=1543683763.088200&amp;cid=C0GLTDB2T#2018-12-0120:07pesterhazyIt’s cool to see to which degree thought processes converge #2018-12-0119:21mfikes@me1740 Trying to come up with an example:
cljs.user=> (def x (eduction (keep (duplicate?)) [1 2 3 2 4 2 3]))
#'cljs.user/x
cljs.user=> (into [] x)
[2 2 3]
cljs.user=> (into [] x)
[1 2 3 2 4 2 3]
#2018-12-0119:24benoitOh ok I see, thanks. Also explain why you should initialize your state inside a transducer function.#2018-12-0119:29benoitSo I had to rewrite that as a transducer with the state inside it:
(defn duplicates
  []
  (fn [xf]
    (let [seen (volatile! #{})]
      (fn
        ([] (xf))
        ([result] (xf result))
        ([result input]
         (if (contains? @seen input)
           (xf result input)
           (do
             (vswap! seen conj input)
             result)))))))
#2018-12-0119:29taylorhaha I’m playing w/Quil to visualize the solution as it’s calculated, but then I just figured out it’ll take ~40 minutes to finish @ 60fps#2018-12-0120:29bhaumanhaving both reductions and duplicates transducers would be interesting, I wonder if I would remember to use the duplicates one#2018-12-0120:31potetmcgrand has it in xforms#2018-12-0120:31bhaumanoh ho ho#2018-12-0120:32potetmreductions that is#2018-12-0120:32potetmI don’t think duplicates is there#2018-12-0121:40borkdudexforms is also available in advent-of-cljc, just sayin’ 🙂#2018-12-0122:07helios@borkdude I just updated the invite code for the leaderboard, I deleted the ones I created this afternoon#2018-12-0122:14borkdudewho owns this advent-of-clojurians repo, I think @thegeez? can you add more people with PR merge rights? It seems I’m the only one doing that right now#2018-12-0122:49adammillerProbably not the ideal use, but I used NextJournal to do the day 1 challenges. Link if anyone wants to remix it with other styles: https://nextjournal.com/akmiller/advent-of-code-2018--day-1#2018-12-0123:20lilactownI decided to do the first day in both CLJ and Rust. https://github.com/Lokeh/advent-2018/tree/master/day1#2018-12-0123:21lilactownwe’ll see how far I get before succumbing to my lack of Rust knowledge (and frustrations with the type system) and just do the rest in CLJ :P #2018-12-0123:31lilactownI think I might update my CLJ solution with a duplicates xf - wanted to in the moment but it was very late for me last night#2018-12-0123:39mfikesI like how you name the predicate seen?, even though it is implemented using a set. Nice.#2018-12-0123:40mfikesIt is a predicate that doesn't return a Boolean value, but maybe that's OK.#2018-12-0123:43lilactownYeah I thought it felt nice. I often do that when using sets as predicates#2018-12-0200:01pesterhazyI think the "rule" that predicates should return booleans is a bit silly#2018-12-0200:02pesterhazyThere nothing wrong with truthiness#2018-12-0200:20taylorI think Rich himself strayed from this guideline for at least one predicate in spec #2018-12-0200:05mfikesI like how Dan Dorman's solution uses a transient that is eventually discarded (no persistent! needed to derive value from the transient). https://github.com/dandorman/advent-of-code-2018/blob/master/src/aoc2018/d01.cljc#L18#2018-12-0221:46danielgrosseAmazing how this speeds up the calculation. I had the solution without transient and it took my mac around 10 minutes to get the result. With Dormans one it had no calculation time at all.#2018-12-0200:10lilactownoh that input->vec is also very nicely clever#2018-12-0200:11mfikesOh wow. Nice hack.#2018-12-0200:11lilactownwish I had thought of that. I didn’t even think to reach for the reader like the rest of ya’ll; I pieced together a solution using Integer/parseInt#2018-12-0200:16pesterhazy@lilactown same here#2018-12-0200:17dpsuttoni prefer traditional parsing steps. more like real life. I would never ship production code that calls read on input like that. i also don't like when the language makes some things more easy like that#2018-12-0200:17dpsuttonlike when the syntax they pick happens to align with literals in the language you are using. unless you make a language like that a la racket#2018-12-0200:25lilactowntrue. It just ate up about 80% of the time of part 1 for me :P#2018-12-0200:25lilactowngotta get those leaderboard spots!#2018-12-0200:32mfikesOh, come on, how often do you get to do something like
(eval (read-string (str "(apply + [" input "])")))
😜
#2018-12-0200:35vijaykiran
(eval (read-string 
          (str "(+ " input ")")))
#2018-12-0200:40mfikesCool, I was getting a stack overflow on my input size for this.... wondering why.#2018-12-0200:34mfikesShia LaBeouf / Chuck Norris, style programming#2018-12-0200:34vijaykiran🙂 That’s pretty much what I did 😄#2018-12-0200:34ihabunekhere's a solution in grep for one task in 2015 https://github.com/ihabunek/aoc2015-elixir/blob/master/src/day16.sh 🙂#2018-12-0200:47potetmomg… the waste!#2018-12-0200:48potetmjust | into a single grep process!#2018-12-0200:48potetmsry — I’m a bash dev by training 😛#2018-12-0200:35mfikesHah#2018-12-0200:36mfikes"This solution does not require programming." Just pure thought.#2018-12-0200:36borkdudeI didn’t know Integer/parseInt and js/parseInt both accept +1 and -1, else I would have used that instead of read-string#2018-12-0200:37mfikesTo put things in perspective, when I mentioned this problem to my 15-yo, he first said he would take the absolute value of each, but remember the sign, so you would know whether to add or subtract the absolute value.#2018-12-0200:39dpsuttonthat's where i went at first. they just happened to encode the data in a convenient literal#2018-12-0200:45lilactownI decided to try parseInt +5 first, but if it hadn’t worked I was planning on just removing all +’s before parsing #2018-12-0200:45potetmsame^#2018-12-0200:45mfikesI forgot to even look for + in the input, and just proceeded Leroy Jenkins-style.#2018-12-0200:46potetmhttps://i.imgur.com/3L9vyNi.gif#2018-12-0200:47mfikesYesss#2018-12-0200:47mfikesThe way most code is written.#2018-12-0200:47potetmtruestory#2018-12-0200:47mfikesUnless the hammock calls.#2018-12-0200:50lilactownI recently bought an iPad so that I could still computer without being near a dev workstation, so that I would spend less time writing code and more time hammocking#2018-12-0200:51lilactownthat went OK until I figured out how to setup ssh / emacs / tmux 🤪#2018-12-0218:42rmprescottI probably shouldn't mention https://repl.it then... ;D#2018-12-0218:59lilactown😱#2018-12-0219:07rmprescottMy mac is in the shop so I'm working there: https://repl.it/@RalphPrescott/AoC-2018#2018-12-0200:51mfikesThe difficulty of entering forms into Replete gives you plenty of time to think if you go that route.#2018-12-0200:52lilactownhaha. I did mess with replete. it’s pretty impressive!#2018-12-0200:53lilactownI threw up an issue about being able to save to disk or gist :P I know it’s just a wish-list thing#2018-12-0200:57mfikesI'm curious what fraction of the solutions fail to handle the "back to 0" case. (For input [+1 -1], for example)#2018-12-0201:14tayloris the correct answer 1 for that input?#2018-12-0201:16dpsuttondepends if you consider a sequence of 0 elements having a sum of 0, then the sequence of 2 elements would have a sum of 0. or most likely the sequence of [1] an then [1 -1 1] having sums of 1 is what they most likely mean#2018-12-0201:17tayloroh, I’m thinking specifically about part 2#2018-12-0201:18dpsuttonwell that's what i'm talking about as well. there are arguments for 0 or 1#2018-12-0201:20taylorohh I see now, one argument is that the starting frequency of 0 should be considered when looking for the first duplicate#2018-12-0201:21taylorin that case, my solution fails 🙂#2018-12-0201:21taylor>+1, -1 first reaches 0 twice.#2018-12-0201:23taylorbut I suppose I can just start with #{0} instead of #{} and handle that#2018-12-0201:24dpsuttonit's easy to miss this subtlety. not sure which way to fall but i guess good to be conscious of which one you think is the right answer rather than whatever your reduce expression returns#2018-12-0201:25taylorthe AoC test cases seem to indicate the answer should be 0#2018-12-0201:38dpsuttonWhich test case?#2018-12-0201:40lilactownIt's written in the description of the puzzle#2018-12-0212:38uoslMine did until I started adding tests. At that moment I realized why your solution had consed the reductions onto 0 😛 Although passing 0 as init to reductions worked for me.#2018-12-0203:36Stephen LesterI hope I'm not the only one who smashed the stack trying part 2 😞#2018-12-0204:58Mario C.2 mins gentlemen 😛#2018-12-0205:20Stephen Lestersad, rank 757#2018-12-0206:40mfikesDay 2 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_02.cljc#2018-12-0207:44orestisSo in part2, instead of considering one string against all others, repeating, you are dropping the first character, search for duplicate, second character, search for duplicates etc? Neat!#2018-12-0210:40pesterhazyvery clever#2018-12-0215:48bhaumanthats fun 🙂#2018-12-0206:52dpsuttonAh. The day 1 first duplicate is clever#2018-12-0206:52dpsuttonI didn't think of deleting and checking#2018-12-0206:53mfikesThis problem will lead to a richer variation of solutions. 🙂#2018-12-0206:54dpsuttonI just realized mine is not funny general. I compare them to their neighbors after sorting. But there is no reason the single difference would not move their position in the sorted list#2018-12-0206:54dpsuttonFunny = fully#2018-12-0206:56dpsuttonAlthough now I can't think of a better approach than your brute force#2018-12-0207:01ClashTheBunnyDay 2 https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day02.clj Happy about some of it, other parts seem like they could be MUCH better. Perfomance is fine.#2018-12-0207:06dpsuttonYou can drop the first two comparisons in your levenshtein since all the strings are either equal or replaced. There are no deletions or additions to worry about#2018-12-0207:07dpsuttonAh ok you use simple cost only :)#2018-12-0207:12dpsuttonhttps://github.com/dpsutton/advent/blob/master/2018/src/advent/02.clj#2018-12-0207:16Mario C.Day 2 part 1 took me 2 hours to do ooof.. Can't come up with a solution for part 2, too tired >.<#2018-12-0207:21orestisWoof, I solved day2 part2 but mfikes has already contributed his data to advent-of-cljc. How do I submit a patch instead of a PR to Github? 🤪#2018-12-0207:28orestisDay2: https://github.com/orestis/advent-of-cljc/blob/master/src/aoc/y2018/d02/orestis.cljc — I need to finally figure out how to get a CLJS REPL setup so I can see why the CLJS tests are failing. Most likely something to do with chars/ints etc.#2018-12-0208:02dpsuttonI'm interested to see different approaches that are sound. Mine was probabilistic#2018-12-0208:18helioshere's mine: https://github.com/Heliosmaster/advent-of-code-2018/blob/master/src/adventofcode_2018/day2.clj but i liked @mfikes answer a bit more 😉 there are some functions (like keep) that I have used rarely so I tend to forget about them 😄#2018-12-0213:53mfikesOn the surface, when count is applied to filter vs. keep, you essentially get the same result for this problem. So you might wonder why I was using keep... it was because the intermediate output in the REPL looked a little simpler, that's all.#2018-12-0208:21borkdude@orestis about failing CLJS-tests: if you change the deftest to clojure.test/deftest you will see the error. I’m not sure why it’s not showing right now. I wrapped the deftest body in time to see the performance. PR welcome that fixes this#2018-12-0208:22orestisIn the end cider can happily jack in to a CLJS REPL for me so I fixed my code interactively.#2018-12-0209:43thegeez@borkdude I've invited a few more people as collaborators to help with merging pr's#2018-12-0210:15borkdude@thegeez thanks#2018-12-0210:28pesterhazyMy solution to Day 2: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle02.clj#L60#2018-12-0210:30borkdude4 solutions in advent-of-cljc so far: https://github.com/borkdude/advent-of-cljc/tree/master/src/aoc/y2018/d02#2018-12-0210:30pesterhazyThis time I spent most of my time on setting up rebel-readline, and on writing a lazy pairs function#2018-12-0210:31borkdudeI didn’t try to write clever code, just did the most straightforward thing to get to the solution fast, because I had a coffee meeting coming up#2018-12-0210:31pesterhazyNo excuses!! 🙂#2018-12-0210:33borkdudehaha 🙂#2018-12-0210:42pesterhazyis there a cutoff time when you need to submit solutions? https://clojurians.slack.com/archives/C0GLTDB2T/p1543726681192500#2018-12-0214:49ClashTheBunnyYou get more points on the leaderboard the faster you submit! You don't have to finish every problem to work on the next one. You could practice on other years' problems if you wanted to!#2018-12-0211:58orestisNo, not at all. You could do these next year. #2018-12-0212:09karolhttps://github.com/kfirmanty/advent-of-code-2018/blob/master/src/advent_of_code_2018/day2.clj my solution is also rather not optimized, but it might be fun to look back after few days and try to create most performant solution (but probably with lesser readibility)#2018-12-0212:11karolI especially have a feeling that there is a simpler way to do: (defn without-diff [id1 id2] (apply str (map #(when (= %1 %2) %1) id1 id2))) so I will check other solutions 😉#2018-12-0212:28gklijsAnyone hooked in something like https://github.com/gobanos/cargo-aoc I got jmh setup for Java now, would be nice to compare results. I don't know if I have the time, but otherwise I might setup a project, comparing several solutions.#2018-12-0212:29helios@pesterhazy the countdown was for the new puzzle release 🙂#2018-12-0212:38borkdude@gklijs are you aware of https://github.com/borkdude/advent-of-cljc or is that a different thing?#2018-12-0212:39gklijsI know it's there and like to look at the solutions, but don't know if there is some performance measure there?#2018-12-0212:39borkdudeif you go to the CircleCI icon, open a build and then look at the tests, you will see something like that#2018-12-0212:40gklijsok#2018-12-0212:40borkdudenot anything fancy, just time, not criterion#2018-12-0212:40gklijsfound them#2018-12-0212:41borkdudebut it would be trivial to hook that up. I’m only concerned about the time to build#2018-12-0212:43gklijsYou don't want it in your build, it takes really long. I now have a separate profile to run them, just putting the result back with the method and then remove the annotation in java, so I can easily run the other ones.#2018-12-0212:44borkdudeyou could make a branch, replace the time call with criterium quickbench, push the branch and watch the build. if we don’t merge it to master, it should be fine.#2018-12-0212:47benoitVery clever solution from @mfikes. It ismy first advent-of-code. Do the solutions often build on previous days's solutions? Do we build up code for 23 days to make writing the solution on the 24 a bit easier?#2018-12-0213:17karolIf I remember correctly in 2017 there was once a day to built upon solution of previous day but I think it was a exception to the rule#2018-12-0213:19gklijsthe @mfikes solution is also very fast compared to the others
Testing aoc.y2018.d02.borkdude
part-2 took 54.986879 msecs
part-1 took 0.38845 msecs

Testing aoc.y2018.d02.dfuenzalida
part-2 took 126.335371 msecs
part-1 took 5.086755 msecs

Testing aoc.y2018.d02.mfikes
part-2 took 4.250777 msecs
part-1 took 7.145989 msecs

Testing aoc.y2018.d02.mrmcc3
part-2 took 82.483809 msecs
part-1 took 4.544113 msecs

Testing aoc.y2018.d02.orestis
part-2 took 103.404907 msecs
part-1 took 8.286482 msecs
#2018-12-0213:23mfikesHmm. I didn’t write it with speed in mind.#2018-12-0213:25mfikesI actually wonder if day 2 had day 1 in mind… in this case there was the concept of “sameness / duplication” in both problems.#2018-12-0213:31gklijsno, I was also surprised, gonna use it in my javaRx now, and compare to me previous solution.#2018-12-0214:04benoitok, thanks.#2018-12-0214:47gklijsTurned out to be slightly faster than the previous solution, 3.445 msecs on a warmed up vm#2018-12-0218:38vijaykiranAre these from CI ?
part-1 "Elapsed time: 5.87954 msecs"
part-2 "Elapsed time: 0.829347 msecs"
These are mine from (time …) < it is super-ugly-code though
#2018-12-0219:15gklijsThe list is from CI, the 3,445 is from jmh benching.#2018-12-0219:16vijaykiranokay! I only ran (time ..)#2018-12-0219:19gklijsI have something similar in Java now, and the rust create also has it, will be adding some CI config to get some numbers there#2018-12-0212:48gklijsCan of related to that I often struggle with how generic a solution should be, for my java colleagues I also see them putting some effort in nicely handling edge cases.#2018-12-0212:49gklijsDefault settings, at least in java take about 15 minutes for each method.#2018-12-0214:49ClashTheBunnyYou get more points on the leaderboard the faster you submit! You don't have to finish every problem to work on the next one. You could practice on other years' problems if you wanted to!#2018-12-0215:02taylorday 2 was fun. I feel like there’ll be more variety in the solutions, here’s mine https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/2.clj#2018-12-0215:45bhaumanjust finished#2018-12-0215:46bhaumanhttps://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day02.clj#2018-12-0215:46bhaumannow to look at the other answers 🙂#2018-12-0215:50dpsuttonSo it seems brute Force is the only strategy?#2018-12-0216:00bhaumanfor the most part one way or the other you are going to have to compare until you find#2018-12-0216:01bhaumanone interesting thing is that sorting the list may increase the likelyhood that the search ends sooner#2018-12-0216:02bhaumanas you normally generate combinations from the original order#2018-12-0216:06bhaumanactually this is not true for my data it increased the number of cycles quite a bit#2018-12-0216:20bhaumanactually a tree search would probably provide the best performance#2018-12-0216:21bhaumanas you are eliminating prior comparisons#2018-12-0217:16mfikesIt is possible to parallelize the search. For the algorithm I'm using, the problem is essentially linear in the input, but with it doing a linear search over each character position, one at a time. The answer happens to be at position 20 for my input data. Those searches per character position can be done in parallel. The problem size isn't really big enough to benefit greatly from this, but it can cut it down from 3 ms to 1.5 ms. https://gist.github.com/mfikes/d2cf0c9de3808564f7b039f10635ede4#file-parallel-clj-L34-L44#2018-12-0217:22bhaumanmy tree solution is 7ms#2018-12-0217:22bhaumancompared to lazy search of 99ms#2018-12-0217:25bhaumanthe tree search intelligently eliminates large swaths of search area#2018-12-0217:37bhaumanhttps://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day02.clj#L50-L63#2018-12-0217:48taylorVery cool. Gonna need to study this for a while :face_with_monocle: #2018-12-0217:39bhauman@mfikes ^#2018-12-0217:40gklijsIs that with warm up? Rust is doing around 0.25 ms for each of day two#2018-12-0217:40bhaumanlol#2018-12-0217:41bhaumanof course it is#2018-12-0217:47gklijsWith RxJava it's about 3/6 ms, measured with jmh. I'm still kind of figuring out what I like best/want to get better in.#2018-12-0218:12andrew.sinclairHi all! I love this time of year! My solutions aim for leaderboard points rather than elegance and best practices. It’s great to see all the unique ways other clojurians come up with!#2018-12-0218:13andrew.sinclairhttps://github.com/AndrewSinclair/aoc-2018#2018-12-0218:17vijaykiranMy day2-one has more lines than day2-two https://github.com/vijaykiran/aoc-2018/blob/master/src/aoc_2018/two.clj#L279 🙂#2018-12-0218:18dpsutton@bhauman i was reading your tree search and it prunes a bit too heavily (search ["abc" "ddd" "zbc" "ahg" "zzz"]) should match abc/zbc => "bc" but it fails to find them#2018-12-0218:55bhauman@dpsutton oh cool thanks, I think thats a base case lemme check it out#2018-12-0218:57bhaumanoh I broke it when I refactored#2018-12-0219:00lilactown> TFW you accidentally leave that println inside the inner loop of your solution and you run it on your real input facepalm#2018-12-0219:01lilactownat least in CIDER/Emacs outputting that much text to a buffer wrecks me#2018-12-0219:02rmprescottTempted to ask this on another channel - but it's also some hints on the first few problems. Are there any more idiomatic approaches to these short helpers?#2018-12-0219:03rmprescott#2018-12-0219:04bhauman@dpsutton nope its just wrong 🙂#2018-12-0219:04dpsuttonMine too :)#2018-12-0219:05dpsuttona sort and compare with neighbor works on the input but is not right in general. (i realized after doing that)#2018-12-0219:13bhaumanI found the problem but of course it slows it down 🙂#2018-12-0219:13dpsuttonyes you have to be more cautious of when you can prune things#2018-12-0219:14dpsuttonis it instead of apply intersection you look for duplicates?#2018-12-0219:15bhaumanright now I’m intersecting two by two#2018-12-0219:16dpsuttoni was mulling that idea just now#2018-12-0219:16bhaumanwhich is searching for duplicates#2018-12-0219:16dpsuttonlook for things with the first two characters have non-empty intersection#2018-12-0219:16lilactownoof, ya’ll are making me feel bad. my day2 part2 solution is ~600ms 😆#2018-12-0219:17bhaumanI’m thinking that its better to do this as a tree as well#2018-12-0219:17vijaykiranAs long as it works 🙂 We are not in a hurry#2018-12-0219:17vijaykiran@lilactown ^#2018-12-0219:18dpsutton@lilactown but the "fast" versions we are talking about are unsound 🙂 slow and steady#2018-12-0219:18lilactownstill, going fast is fun!#2018-12-0219:19vijaykiranHey - my version is fast and it is very sound (as in very noisy) 😄#2018-12-0219:20vijaykiranFor the second one, I was even considering not writing code and Cmd+F and eye-ball the similar strings#2018-12-0219:21rmprescott@bhauman - i'm missing something. I don't see how you can do this other than pairwise. What would you use as the comparison in your tree?#2018-12-0219:22rmprescottI can't think of anything that (properly) constrains the solution space.#2018-12-0219:22bhaumanhold on committing#2018-12-0219:24bhauman@rmprescott https://github.com/bhauman/advent-of-clojure/blob/master/src/advent-2018/day02.clj#L50-L63#2018-12-0219:25bhaumanin this solution I’m doing a depth first search#2018-12-0219:25bhaumanso it should eliminate comparisons#2018-12-0219:26bhaumanits takes a third of the amount of time as my straight forward solution#2018-12-0219:27bhaumannow breadth first search would really be interesting#2018-12-0219:27bhaumanas well#2018-12-0219:27bhauman@dpsutton mines updated#2018-12-0219:59bhaumanand updated again with comments#2018-12-0220:01mfikesIIRC, we will probably see a few perf-critical ones in a couple weeks (where your algorithm is important if you want it to complete in a few minutes)#2018-12-0220:01mfikesOr within the RAM you have 🙂
#2018-12-0220:03lilactownanswer: just throw a naive solution at a cluster and come back the next day 😛#2018-12-0220:03lilactownslow and steady!#2018-12-0220:03pesterhazysurely @mfikes's solution must be the fastest no?#2018-12-0220:04mfikesOddly, mine wasn't at all meant to be fast. It got lucky.#2018-12-0220:04uoslwas there a problem like that last year? it does say this in the about page: >every problem has a solution that completes in at most 15 seconds on ten-year-old hardware.#2018-12-0220:05uoslalthough my first attempt at day 1 part 2 would have taken at least 15 minutes to finish :rolling_on_the_floor_laughing:#2018-12-0220:05pesterhazymy super-inefficient solution completes in 47ms#2018-12-0220:05mfikesThere was that one with the particle simulation that was a real PITA, where you had to almost eyball the solution.#2018-12-0220:09taylorThat was hard https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2017/20.clj#2018-12-0220:06mfikesDay 20 last year.#2018-12-0220:07uoslooo. this is my first year so looking forward to any problems that places me in a rut#2018-12-0220:08mfikesIIRC, one pattern is where part 1 can be done with a naive algorithm, and then Wastl asks you to do it for a problem with a billion iterations in part 2.#2018-12-0220:08potetmyep^#2018-12-0220:08pesterhazyIt's my first year as well. What will Day 3 bring? More duplicate detection? 🙂#2018-12-0220:10bhauman@vijaykiran try [“abc” “ddd” “zbc” “ahg” “zzz”]#2018-12-0220:10bhaumanyour solution fails for me on that#2018-12-0220:34vijaykiransorted stuff breaks it - I made some assumptions after sorting my puzzle input#2018-12-0220:11Mario C.wow part 2 was pretty cumbersome my solution was kinda hacky but it got the job done 😛 https://github.com/HeyItsMario/AdventOfCode2018/tree/master/day2#2018-12-0220:12lilactownlet’s see. last year’s day 1 was pretty similar (summing things). day 2 was doing some integer math (finding min/max, divisors)#2018-12-0220:13dpsuttonyeah. and then you start trying to code generically for part 1 and then you don't get to reuse any for part 2 sometimes#2018-12-0220:14lilactownthere were a few times last year where if you solved part 1 a certain way, part 2 fell out of it quite nicely#2018-12-0220:14lilactownbut most of the time I spent trying to make part 1 “generic” without knowing part 2 was a waste, yes#2018-12-0220:18mfikesDay 16 was of last year was an example of naive part 1 could in theory solve part 2, but it involved a dance of some sort that went out a billion iterations#2018-12-0220:34potetm@gklijs I’d love to see your Rust/RxJava example#2018-12-0220:35potetmdid you do any optimizations or is it basically brute force?#2018-12-0220:40potetmI can’t get my brute force below ~130ms or so#2018-12-0220:40gklijsI did do the mfikes trick, but that didn't do much to performance, did lose half the needed code. In Rust I'm really inexperienced, so need to google for a lot of stuff,and just happy when it runs. But I figure especially the second one really does well, since it's just moving pointers around. Code at https://github.com/gklijs/advent_of_code_2018 'Gerard' is RxJava, 'Rust/oac_2018' is rust, the other folder are Java from colleagues.#2018-12-0220:42gklijsIt could also be your problem is harder, that's the nice thing about https://github.com/borkdude/advent-of-cljc they all use the same data#2018-12-0220:42potetmah, didn’t even consider that#2018-12-0220:43potetmI mean… also just hardware#2018-12-0220:45gklijsIt's the first year for me, and also for the company, maybe next year I set something up with GraalVM#2018-12-0220:48potetmthe mfikes trick (w/ transducers) gets me down to ~2ms#2018-12-0220:49potetmactually… holy hara#2018-12-0220:50noogafor early puzzles I just write really long oneliners in a repl, they tend to be convoluted and slow 😂#2018-12-0220:50potetm
(str (subs s 0 i)
     (subs s (inc i)))
^is WAY faster than
(.toString (.deleteCharAt (StringBuilder. s) i))
#2018-12-0220:51potetmdown to .5ms#2018-12-0221:01mfikesReflection?#2018-12-0221:05potetmI hinted the constructor#2018-12-0221:05potetmin my timing#2018-12-0221:06pesterhazy@nooga I'm the same way, whatever I can possibly squeeze into a one-liner in the repl#2018-12-0221:07potetm@mfikes that was it#2018-12-0221:07pesterhazyonly roadblock: rebel-readline, as great as it is, doesn't submit when I hit Return while the cursor is not at the end of the line#2018-12-0221:07potetm
(fn [^String s]
  (.toString (.deleteCharAt (StringBuilder. s)
                            ^Long i))
is comparable
#2018-12-0221:09mfikesSo, transducers got it down to half a millisecond. Nice.#2018-12-0221:09mfikesRust speed within reach. 🙂#2018-12-0221:10mfikeshttps://clojurians.slack.com/archives/C0GLTDB2T/p1543772430255300#2018-12-0221:11bhauman@pesterhazy ctrl-x ctrl-m#2018-12-0221:11mfikesHah! Every time that happens on Apropos, we shout out Bruuuucee!#2018-12-0221:12mfikesNow we know they way 🙂#2018-12-0221:12potetmBad news…#2018-12-0221:12potetmMy .5ms was bugged#2018-12-0221:12potetm2.1ms#2018-12-0221:12mfikesDamn. 👿#2018-12-0221:12potetmikr#2018-12-0221:14slipsetah, spent way too much time on part two of day two.#2018-12-0221:15mfikesIMHO, day 2 part 2 was a bit harder than you would expect, so early on#2018-12-0221:16pesterhazy@bhauman wow, thanks#2018-12-0221:17slipsetI was over complicating things a bit.#2018-12-0221:22slipsetI’m probably not so concerned with speed 🙂#2018-12-0221:23slipsethttps://github.com/slipset/aoc-2018/tree/master/src/aoc#2018-12-0221:23slipsetDon’t want to spoil anything 🙂#2018-12-0221:26pesterhazy@bhauman is there any way to bind the Enter key to clojure-force-accept-line rather than accept-line?#2018-12-0221:26pesterhazyI tried
cat ~/.clojure/rebel_readline.edn
{:key-bindings { :emacs [["RETURN" :clojure-force-accept-line]] }}
#2018-12-0221:27pesterhazyI can bind ^J, which is nice, but a real Enter/Return would be better#2018-12-0221:27bhauman^J or ^m I think#2018-12-0221:27pesterhazywait! this works#2018-12-0221:27pesterhazy
{:key-bindings { :emacs [["^M" :clojure-force-accept-line]] }}
#2018-12-0221:27bhaumanyes control M is a real return#2018-12-0221:28pesterhazyit's always just after bothering someone that you find the answer yourself#2018-12-0221:28bhaumanso the thing is that you don’t get multiline that way#2018-12-0221:28pesterhazyyeah maybe I can bind that to ^j#2018-12-0221:29pesterhazyhonestly I don't often write multiple lines except by mistake#2018-12-0221:30pesterhazyyeah, ^j is bound to accept-line by default - that works well for me#2018-12-0221:33pesterhazynow it's perfect 🎉#2018-12-0221:57borkdudeDay 2 for Advent of CLJC:
Testing aoc.y2018.d02.borkdude
part-2 took 47.616232 msecs
part-1 took 0.408357 msecs

Testing aoc.y2018.d02.dfuenzalida
part-2 took 118.803809 msecs
part-1 took 5.012151 msecs

Testing aoc.y2018.d02.iamdrowsy
part-2 took 362.461886 msecs
part-1 took 4.806461 msecs

Testing aoc.y2018.d02.mfikes
part-2 took 4.994811 msecs
part-1 took 7.194342 msecs

Testing aoc.y2018.d02.mrmcc3
part-2 took 92.999763 msecs
part-1 took 5.206182 msecs

Testing aoc.y2018.d02.orestis
part-2 took 98.666185 msecs
part-1 took 8.78663 msecs
https://circleci.com/gh/borkdude/advent-of-cljc/91
#2018-12-0221:58borkdudeGood job everyone and thanks for contributing.#2018-12-0222:00borkdudemfikes really nailed it. when I saw his function that deleted one char from a string I was like: oh yeah, of course… 🙂#2018-12-0222:15Mario C.very humbling seeing y'alls such succinct solutions#2018-12-0222:37potetm
(criterium/quick-bench
  (into []
        (comp (keep (fn [i]
                      (first (into []
                                   (comp (map (fn [^String s]
                                                (.toString (.deleteCharAt (StringBuilder. s)
                                                                          ^Long i))))
                                         (dups)
                                         (take 1))
                                   in))))
              (take 1))
        (range (count (first in)))))
Evaluation count : 828 in 6 samples of 138 calls.
             Execution time mean : 702.838769 µs
    Execution time std-deviation : 19.556882 µs
   Execution time lower quantile : 668.965703 µs ( 2.5%)
   Execution time upper quantile : 718.893138 µs (97.5%)
                   Overhead used : 1.830592 ns
#2018-12-0222:38potetmwhere dups is a transducer that emits duplicates#2018-12-0223:01slipsetI wish I understood the reasoning behind @mfikes solution to todays second problem.#2018-12-0223:02mfikesMaybe I could draw a picture of it#2018-12-0223:04mfikesI visualize it as first eliminating a column of characters and then seeing if that causes a duplicate to appear in the remaining strings#2018-12-0223:43rmprescottdivide and conquer -- nice!#2018-12-0223:05mfikes
abc
axc
def
Eliminate the middle column in that example
#2018-12-0303:56joaohgomesHad the same idea 🙂 https://github.com/gomes-work/advent2018/blob/master/src/advent2018/day_2.clj#2018-12-0223:06mfikesac then appears twice#2018-12-0223:11slipsetQuite cheeky to use yesterdays solution though 🙂#2018-12-0223:15borkdudehe factored out a function that he could re-use: https://github.com/borkdude/advent-of-cljc/commit/17c8f768c75fbb69187eb4ecf892d17612172cdd it could have ended up in some utils namespace as well#2018-12-0223:36fellshardI'm trying to recreate my solutions in Elixir as a sort of lift-and-shift approach. A lot of common utility between Clojure and Elixir, though the latter is certainly far more verbose and doesn't have quite the same expressiveness for its core lib. Still not bad.#2018-12-0223:53devnwow, did not think i'd wind up using reductions on problem 1 😄#2018-12-0223:53devnone of my favorite functions that i keep in my back pocket#2018-12-0223:53dpsuttonReductions and iterate always feel so fancy and sophisticated to me ha#2018-12-0223:54devnwow, that's actually kind of interesting#2018-12-0223:54devni feel like early on when i was using clojure i used iterate a lot#2018-12-0223:54devnbut i don't use it very often these days#2018-12-0223:54devnlike when you mentioned it, i was like "oh right, that exists"#2018-12-0223:55dpsuttonI don't use it very often in our webapp or backend stuff but I like to model solutions to "clever" problems with it#2018-12-0223:55devni guess i used it pretty often in 4clojure problems when golfing#2018-12-0223:56devnand in project euler solutions#2018-12-0223:56devnwhich is why i remember it being a "back in the day" kind of thing#2018-12-0223:57dpsuttonThat makes sense. It doesn't seem to align with real world things I have to do so it really feels insightful when it works#2018-12-0223:59devnbtw, reductions is "fancy", but i remember using it for a problem where i had a sequence of lines of chat, similar to the way they're presented in slack, so you'd see a nickname, and then you wouldn't see it on any lines they typed immediately after, but i wanted it filled in everywhere#2018-12-0300:00devn[["frank" "hello"] [nil "how is everyone?"] ["ethel" "good, you?"]] => [["frank" "hello"] ["frank" "how is everyone?"] ["ethel" "good, you?"]]#2018-12-0300:00devnsomething like that#2018-12-0300:02devni forget the structure of the input, so that might be nonsensical at this point, but remember feeling like i'd unlocked some kind of secret when i found that#2018-12-0300:03devnfound it:
(defn forward-propagate
  "If the keyword (kw) specified does not exist in the next map in the
  sequence, use the previous value of the keyword (kw).

  Example:
  (forward-propagate :nickname '({:nickname \"Fred\"} {:nickname nil}))
  => ({:nickname \"Fred\"} {:nickname \"Fred\"})"
  [mapseq kw]
  (rest
   (reductions
    (fn [{prev kw} next]
      (update-in next [kw] #(or % prev)))
    {}
    mapseq)))
#2018-12-0300:03devnname suggestions welcome 😄#2018-12-0300:05devnshame on me for the clever destructuring, shadowing next, a docstring that doesn't show the real true desired behavior, and other things#2018-12-0300:06devnwritten before update was a thing, so there's another wart#2018-12-0300:07devn</bikeshed>#2018-12-0300:22Stephen LesterI'm not sure if placing in the top 1000 is any good 😕 I think two years ago I managed to get in the top 50 but perhaps there are a lot more doing it nowadays#2018-12-0300:23dpsuttonit's all by time right? seems like being somewhere such that midnight on the east coast happens at a bright and thoughful hour is key to getting on the leader board#2018-12-0300:25Stephen Lesterand being smart! 😄#2018-12-0302:20potetm@mfikes I just dumped code while I was on the move earlier, but got it down to 0.7ms w/ a proper benchmark#2018-12-0302:20potetm(sry for the spoiler ya’ll, wasn’t thinking)#2018-12-0304:19taylorI used Quil to make a visualization of day 2 part 2 string comparisons https://youtu.be/Y_UuASYf6bM#2018-12-0309:46erwinrooijakkersHahaha this is awesome#2018-12-0309:46erwinrooijakkersDo same for day 3 😛#2018-12-0313:42taylorI did but it’s not very exciting. Just a bunch of multicolor rectangles #2018-12-0316:04taylorSanta’s suit not looking very coherent, can you spot the single patch that doesn’t overlap?! https://i.imgur.com/jV7Atfn.png#2018-12-0316:12borkdudeIs it the green one?#2018-12-0316:14taylorhaha it’s basically impossible to see without animating it; it’s in the top-right quadrant but I can’t even find it now looking at the still image#2018-12-0318:32rmprescottI'll bet someone could write a program to find it. ;D#2018-12-0305:28potetmToday’s was a little more fun imo 🙂#2018-12-0306:25ClashTheBunnyIt took a bit to think about a good solution to the first one, and I guessed correctly on what types of information I would need to recover for the second one: https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day03.clj#2018-12-0306:45lilactownOk I'm ready to make a duplicates transducer now:grin:#2018-12-0306:46lilactownSecond time it's been an "I wish I had that"#2018-12-0306:54taylorhttps://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/3.clj#2018-12-0307:20fellshardI solved the first one in a horribly slow manner, then went back around with an idea I had and rejected the first go 'round and ended up being far more efficient.#2018-12-0307:20fellshardFirst time was brute-force squared, second time was brute-force linear 😛#2018-12-0307:41fellshardOof. And looking at those solutions, I see some obvious places I was still overthinking it. I'm out of shape with Clojure 😅#2018-12-0308:01nielsPeter Tseng is a machine#2018-12-0308:29pesterhazyI feel a little dirty about my solution https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle03.clj#L38#2018-12-0308:29borkdudemutable array is perfect for this#2018-12-0308:33pesterhazydoesn't exactly translate into raw speed 🙂
Elapsed time: 16054.534362 msecs
#2018-12-0308:51heliosmy part2 is slow as hell 😛#2018-12-0309:00ihabunekhttps://git.sr.ht/%7Eihabunek/aoc2018/tree/master/clojure/src/aoc2018/day03.clj#2018-12-0309:00ihabunekthat's around 3 seconds for both parts, could probably speed it up by using a transient set#2018-12-0309:19borkdudeThe weird thing is that on Node part 2 takes less long than part 1…
=== Running clojure test 2018

Running tests in #{"src"}

Testing aoc.y2018.d03.borkdude
part-2 took 567.30943 msecs
part-1 took 60.775506 msecs

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.

=== Running cljs test 2018

Testing aoc.y2018.d03.borkdude
part-1 took 6239.000000 msecs
part-2 took 1018.000000 msecs

Ran 2 tests containing 2 assertions.
0 failures, 0 errors.
#2018-12-0309:21borkdudemaybe it’s doing something very inefficient in part 1… maybe something to do with lazyiness#2018-12-0309:59pesterhazyIs there anyone doing AoC based on a different paradigm, like Prolog or APL?#2018-12-0403:03rmprescottWhy do you say APL is a different paradigm? Aside from laziness it's pretty similar - just a very different notation.#2018-12-0406:50pesterhazyBecause I don’t know APL :)#2018-12-0310:20borkdude@pesterhazy I know someone who does it in Postgres#2018-12-0310:22borkdudehttps://twitter.com/pg_xocolatl#2018-12-0310:58erwinrooijakkersHi @borkdude can we use reader conditionals in advent-of-cljc or does that defeat the purpose?#2018-12-0310:59borkdude@erwinrooijakkers you most definitely can. you can also add (cross platform) libraries#2018-12-0310:59erwinrooijakkersThanks#2018-12-0310:59borkdude@erwinrooijakkers note that there are already two useful functions in aoc.utils#2018-12-0311:01erwinrooijakkersAha#2018-12-0311:01erwinrooijakkers🙂#2018-12-0311:01borkdude@erwinrooijakkers your tests are failing exactly on the functions I already provided in aoc.utils 🙂#2018-12-0311:01borkdudeyou just have to prefix them with u/#2018-12-0311:02erwinrooijakkersI see 🙂#2018-12-0311:03erwinrooijakkersAlright now back to work. Hope to do day 3 this evening.#2018-12-0311:04erwinrooijakkersNice repository!#2018-12-0311:38nooga29 lines today but slow as hell 😄#2018-12-0311:38noogaI basically limited myself to what resources https://repl.it has so it’s easy to get a timeout once in a while, can’t be bothered to start a new lein project for AoC#2018-12-0311:54borkdude@orestis fixed the FAIL output problem in cljs#2018-12-0311:55borkdude@erwinrooijakkers merged#2018-12-0312:54benoitMy solution: https://github.com/benfle/advent-of-code-2018/blob/master/day3.clj As long as it is under a second I don't look at perf 🙂#2018-12-0312:55potetmmine is basically identical^#2018-12-0312:55potetmexcept#2018-12-0312:56potetmI used sets#2018-12-0312:56potetmso for the second part, I took a union of all overlaps#2018-12-0312:57potetmand then set/difference from every identifier#2018-12-0312:58helios@potetm interesting idea, i hadn't thought of that and did the brute-force approach first 😄#2018-12-0312:58potetmoh mine is def brute force#2018-12-0312:58borkdudemy solution: https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2018/d03/borkdude.cljc#2018-12-0312:58potetmjust get to talk about sets so I feel fancy#2018-12-0312:59benoityeah at the end I tried to use sets for the list of claim ids. It seemed less performant when computing the surface area.#2018-12-0312:59pesterhazyI wonder why my solution is so much slower (>16s): https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle03.clj#L38 - I naively thought that a mutable 2d Java Array would be faster#2018-12-0315:59fellshardObservation: The problem statement only lists that the canvas is at least 1000 inches per side. You're better off not pre-allocating the whole set of cells; that might help, dunno. Using atoms in your array won't be terribly useful, and will just cause overhead unless you're writing all your claims in parallel. As it is, everything's synchronous.#2018-12-0316:04pesterhazyI'm not using atoms in the array#2018-12-0316:08fellshardNoticed that after. Still probably not necessary for accumulation, though?#2018-12-0316:23pesterhazyyes, I'd have to replace the doseq's by for's I believe#2018-12-0316:23pesterhazycombined with reduce#2018-12-0313:00benoitI also wondered if sets would be better for the fabric instead of vec of vec in case it was sparse but the perf seemed a bit worse too so I gave up perf improvements 🙂#2018-12-0313:00borkdudeI probably could have made my parse function shorter by using @me1740’s (str/split s #"[ ,: instead of multiple steps 🙂#2018-12-0313:00potetmah, mine a vec of vec of sets#2018-12-0313:01potetm(instead of list in your case)#2018-12-0313:01borkdudemy data set looks like a list of {:id id :coordinate [x y]}#2018-12-0313:03benoit@borkdude yeah I fully trusted the input to be well-formed 🙂#2018-12-0313:03benoitI usually don't do that in real life 🙂#2018-12-0313:05helios@borkdude I have done a single re-match and got {:x x :y y :w w :h h} 🙂#2018-12-0313:05borkdudere-find would probably also work?#2018-12-0313:05heliosyeah i guess#2018-12-0313:05benoit@helios It was my first idea but I was too lazy to get the regexp right 🙂#2018-12-0313:05borkdudenice, I’m going to try that#2018-12-0313:06heliosyeah i was thinking the regex would be a PITA to write but it turned out quite easy#2018-12-0313:07heliosspoiler: https://github.com/Heliosmaster/advent-of-code-2018/blob/master/src/adventofcode/2018/day3.clj#L6#2018-12-0313:08heliosI also, in a sense, trusted the input to be well formed (same amount of spaces, etc)#2018-12-0313:08heliosotherwise you would need to add just a lot more +? everywhere 😛#2018-12-0313:11borkdudemuch better: https://github.com/borkdude/advent-of-cljc/commit/b06d17691b8173c040eeef35e2ce0b1d8784d361#2018-12-0315:30mfikesDay 3 https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_03.cljc#2018-12-0315:41pesterhazy@mfikes nice and concise#2018-12-0315:56borkdudefunny timings. CLJ:
Testing aoc.y2018.d03.borkdude
part-2 took 967.53 msecs
part-1 took 60.77 msecs

Testing aoc.y2018.d03.mfikes
part-2 took 726.61 msecs
part-1 took 602.41 msecs
CLJS:
Testing aoc.y2018.d03.borkdude
part-1 took 6087.00 msecs
part-2 took 1843.00 msecs

Testing aoc.y2018.d03.mfikes
part-1 took 6375.00 msecs
part-2 took 6525.00 msecs
#2018-12-0315:57borkdudeCLJS seems to be 10x slower#2018-12-0315:57mfikesYeah, I saw the same thing locally. I haven’t pinpointed what it is.#2018-12-0316:04taylorSanta’s suit not looking very coherent, can you spot the single patch that doesn’t overlap?! https://i.imgur.com/jV7Atfn.png#2018-12-0317:15gklijspart 2 took 26,02 ms (Java)#2018-12-0317:16quollI decided to use this one to practice a bit with core.matrix. I learned about some interesting gotchas, so I was happy with doing that.#2018-12-0319:55erwinrooijakkersNice#2018-12-0317:20borkdude@gklijs nice!#2018-12-0317:23gklijsSpoiler#2018-12-0317:25gklijsI did a reduce and kept a set of all the id of 'patches' I added, then add the id to all the fields. But before I checked when one of the fields was already taken, in that case I would remove all the founds id's from the set.#2018-12-0317:35borkdudesimilar to what I did#2018-12-0317:35borkdudebut this is more optimized 🙂#2018-12-0317:37quollBasically what I did too#2018-12-0317:39quollexcept, I added ids to a matrix (using assign! on a submatrix), and did the reduce as an ereduce over the submatrix#2018-12-0317:37Ben GrabowSpoiler#2018-12-0317:37Ben GrabowYou can efficiently tell that two rects overlap when there is overlap in their x-extents and overlap in their y-extents. No need to enumerate all the points inside each rectangle. This also works in the continuous domain.#2018-12-0317:38Ben GrabowAlso the regex is easier than it looks: #(re-seq #"\d+" %)#2018-12-0317:41quollI thought about the overlaps that you mention, but don’t you then need to do O(n^2) rectangle comparisons?#2018-12-0317:45Ben GrabowYep. It's a balance between O(n^2) rect comparisons vs O(n) rect processing steps times O(height*width) set insertions. If the rectangles are mostly small and you have many of them then the set approach will win.#2018-12-0318:23Ben GrabowThere are probably optimizations that I'm missing in the set-based approach but it's currently 10x slower than my bounds-checking approach. 1400 ms for set intersection, 170 ms for O(n^2) bounds-checking.#2018-12-0317:54potetmGoing live soon! Could def use some backup 😄 https://www.twitch.tv/timpote#2018-12-0318:24andrew.sinclairIs anybody going for leaderboard points? Hot tip, I won't be able to do tonights puzzle until tomorrow, so feel free to take the top spot on the adventofcode-clojurians leaderboard!#2018-12-0318:32rmprescottI'll bet someone could write a program to find it. ;D#2018-12-0319:35orestisI decided to take it easy this year — no pressure to solve every day as soon as possible. Very busy at work, and I’m learning a new language in the evenings (human language, not computer language) so suddenly free time is not so plentiful as last year 🙂 Have fun!#2018-12-0319:49borkdude@orestis my statement on this year: https://twitter.com/borkdude/status/1069546247034466304 🙂#2018-12-0319:51fellshardI need the challenge to incentivize me, but I'm trying to stream this year in order to practice explaining things out loud and build my vocabulary for talking about solutions in Clojure, so the competitive edge is dulled. I've got a lot to learn 🙂#2018-12-0320:07quollLast year I focused on FP approaches. That made sense for some puzzles, and others were 50/50 as to whether keeping state would be helpful, but there were a handful of puzzles which cried out to be solved with mutable data structures. Those ones took some effort to stick to “pure” approaches. It was useful practice#2018-12-0320:11pesterhazyBarely anything is impossible to do in an FP way, except sometimes it’s hard to make it fast enough... I think#2018-12-0320:12potetmyou’d be surprised at how fast it gets#2018-12-0320:12potetmand yeah, I haven’t found any barriers#2018-12-0320:12potetmexcept in my approaches#2018-12-0320:13borkdudeRight. In 2015 I encountered that problem and I needed mutable arrays. It was easier to solve that in Java or Scala but eventually I got it working Clojure just as fast: https://stackoverflow.com/questions/34153369/why-is-this-clojure-program-working-on-a-mutable-array-so-slow#2018-12-0320:13borkdudeThen I thought: maybe there is something to Scala… but I never needed to do that kind of stuff in my daily work#2018-12-0320:13pesterhazyEspecially given that the puzzles haven input->output shape#2018-12-0320:15pesterhazy@potetm I know pure approaches can be fast but the simplest solution is often not the fastest #2018-12-0320:29quollI’m aware that everything can be done with pure functional programming, which is why I stuck to it. Sometimes it’s not the most elegant approach though. But forcing myself to stick to it often helped me identify elegance that wasn’t immediately apparent #2018-12-0320:29quollAnd if all else fails, use a state monad 🤪#2018-12-0320:35Ben GrabowDay 02 Part 2 - The problem can be narrowed down using group-by on the first and second halves of the IDs. The subdivided problems are then small enough to quickly brute force with an O(n^2) comparison. I tried also doing the "delete column" approach to attack the subdivided problems, but the perf was about the same. Either way it's about 100x faster than the naive brute force approach.#2018-12-0320:35Ben Grabow
(ns advent.scratch
  (:require [clojure.string :as str]))

;; Hybrid approach. Group the words by their first half and group them
;; by their second half. Perform a brute force O(n^2) search for
;; almost-duplicates in each group. Take the first pair of almost-
;; duplicates found and extract the common characters.
;;
;; Rationale: A pair of almost-duplicates will have their differing
;; character in either the first half or the second half, meaning
;; either their second half or their first half will be identical.
;; Grouping by first half and by second half guarantees that the
;; pair will end up in a group together. The grouping step also
;; drastically cuts down the number of pairings we need to consider.
;; Searching within the group is O(n^2)

(def day-02 (-> (slurp "resources/day-02/input")
                (str/split-lines)))

(defn differences [x y]
  (filter #(apply distinct? %) (map list x y)))

(defn extract-common-chars
  [pair]
  (->> pair
       (apply map list)
       (filter #(apply = %))
       (map first)
       (apply str)))

(defn find-almost-duplicates [ids]
  (for [lhs ids
        rhs ids
        :when (distinct? lhs rhs)]
    (when (-> (differences lhs rhs)
              count
              (= 1))
      [lhs rhs])))

(defn in-twain [s]
  (let [mid (quot (count s) 2)]
    [(subs s 0 mid)
     (subs s mid)]))

(defn group-by-first-and-second-halves [coll]
  (concat (vals (group-by #(first (in-twain %)) coll))
          (vals (group-by #(second (in-twain %)) coll))))

(time (->> day-02
           group-by-first-and-second-halves
           (filter #(> (count %) 1))
           (map find-almost-duplicates)
           (some first)
           extract-common-chars)) ; 0.8 - 2 msecs
#2018-12-0321:13pesterhazyNice idea#2018-12-0320:49lilactownI'm trying to solve today's problem in Rust and Rich's "Maybe Not" talk is echoing in my head as I try and figure out the correct sigils and incantations to make the type checker happy#2018-12-0320:52adammillerMy problem is the sunk cost issue. I have a hard time not seeing my initial idea through even though I may realize there is a better way half way into it. On problem 3 today I thought it would be simple to convert 2d indexes into 1d array...and it was simple for the first part (if not a bit verbose) but was not terribly helpful to solve the 2nd part.#2018-12-0320:53adammillerand then of course I saw @mfikes solutions which was half the length of mine! But I guess that's what this is great for, seeing how others approach the problems!#2018-12-0321:11erwinrooijakkersI use a one-dimensional vector and updating on index as well. I was happy to discover that the performance is about 25 times better than the other solutions 😄:
Testing aoc.y2018.d03.borkdude
part-2 took 805.32 msecs
part-1 took 113.23 msecs

Testing aoc.y2018.d03.iamdrowsy
part-2 took 971.44 msecs
part-1 took 80.25 msecs

Testing aoc.y2018.d03.mfikes
part-2 took 713.25 msecs
part-1 took 605.19 msecs

Testing aoc.y2018.d03.mrmcc3
part-2 took 818.67 msecs
part-1 took 0.43 msecs

Testing aoc.y2018.d03.transducer
part-2 took 15.80 msecs
part-1 took 21.30 msecs
#2018-12-0321:33gklijsWatching some solution, but so far I don't see anyone else using the 1000 square inch for the solution.#2018-12-0322:09quollOh, are people posting in some central place? I must not have scrolled back far enough in the Slack.#2018-12-0322:10quollBut I tried the 1000x1000 grid. It’s smaller than most images, so I didn’t see a problem with that approach #2018-12-0322:11quollAnd it let me practice with core.matrix#2018-12-0420:37uosl@quoll there's a link in the topic to a repo with a list of clojurians participating https://github.com/adventofcode-clojurians/adventofcode-clojurians#2018-12-0321:37fellshard1000 square inch is a specified minimum for the size, hence the caution, I think#2018-12-0321:38fellshardPlus given there's some relative sparseness to the rectangles, I think allocating an entire area for the entire expected space isn't as useful as could be hoped (though to be far it would be a one-shot allocation)#2018-12-0321:38fellsharda 1d array wouldn't be expandable correctly if you didn't know the size beforehand; a pass of the inputs could give you the max coords, though#2018-12-0321:38gklijsit's not really clear, I also kind of cheated by checking there was no id of 0 (initial value of an int)#2018-12-0321:39borkdude@erwinrooijakkers Did you see my comment to your PR? > Doing “expensive” computations at top level is something I would like you to avoid, since this cuts of time from the test.#2018-12-0321:39borkdudeyour solution is likely to be faster because of that#2018-12-0321:39erwinrooijakkersAh I cheated? 😞#2018-12-0321:40erwinrooijakkersI calculate a grid with the counts that I reuse in the second one#2018-12-0321:40borkdudeAlso from my comment: > If you want to re-use the same calculation from solution 1 in solution 2, then you can memoize or use a delay.#2018-12-0321:40erwinrooijakkersOkay#2018-12-0321:41borkdude@erwinrooijakkers e.g.: https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2018/d03/borkdude.cljc#L20#2018-12-0321:42erwinrooijakkersWhy is that allowed?#2018-12-0321:42borkdude@erwinrooijakkers because parsed is a function. the work is done within the test#2018-12-0321:42erwinrooijakkersAh and it is not actually memoized between tests#2018-12-0321:43erwinrooijakkers?#2018-12-0321:43borkdudeit is, but at least the work is part of the tests.#2018-12-0321:44erwinrooijakkersAh I see#2018-12-0321:44fellshardThat pre-processing work needs to show up in at least one test, basically#2018-12-0321:44borkduderight#2018-12-0321:44erwinrooijakkersOh wait now I see#2018-12-0321:45borkdudealso when you make an exception, the application won’t work at all anymore#2018-12-0321:45erwinrooijakkersI’ll fix it#2018-12-0321:45fellshardMight be good to use deterministic ordering of test execution so that folks' times are comparable#2018-12-0321:45fellshard(though I'm guessing you've already got that covered)#2018-12-0321:45borkdudeI think it is deterministic, but the test runner reverses part 2 and then part 1#2018-12-0321:45fellshardAh, cool#2018-12-0321:46fellshardI'll pipe mine through later, hopefully#2018-12-0321:48borkdudeI’m using https://github.com/cognitect-labs/test-runner for the tests. you may be able to find out why it first does part-2 and then part-1#2018-12-0321:49gklijsI got about 0.25 ms and 1ms for the first and the second, but that's with some warm up interation, https://circleci.com/gh/gklijs/advent_of_code_2018/79 probably in the weekend I have time for a similar setup for clojure#2018-12-0321:53mfikesPerhaps the Advent of CLJC solutions should avoid defs with inits that calculate or otherwise cache things. It is really easy to make the solutions appear to take zero time otherwise.#2018-12-0321:55borkdude@mfikes we were just discussing that yeah. only top level functions, but memoizing is permitted#2018-12-0321:56borkdudeand maybe top level lazy sequences for parsing the data. those don’t realize outside the tests either#2018-12-0321:57mfikesYeah—a problem is that the second one to run benefits from the realizing done by the first. Hrm.#2018-12-0321:57erwinrooijakkersYes thanks @borkdude I did in my latest force push 😉#2018-12-0321:58borkdude@mfikes I saw this pattern was used last year a lot: the output from part 1 served as input for part 2. I think it makes sense to memoize, because the build time on CI can go up a lot if we double these calculations?#2018-12-0322:00borkdude@mfikes the time is a nice gimmick, but the purpose is really to build a corpus to find errors in speculative or measure performance improvements in clj/cljs#2018-12-0322:01mfikesBeing able to compare valid timings is nice :)#2018-12-0322:02mfikesI’ve always been focusing on clear, idiomatic code. But it is also nice to know how much slower that code is when compared to highly optimized solutions.#2018-12-0322:02borkdude@mfikes are you arguing for or against memoize?#2018-12-0322:03potetm@pesterhazy @quoll Apologies for my tone earlier. I shouldn’t have commented unless I was willing to really engage. I was in between things at the time and just threw a comment to the ether.#2018-12-0322:07quollI’ll just have to hassle you in HipChat#2018-12-0322:19pesterhazyno worries#2018-12-0322:04mfikesI’m suggesting that, once a test starts, if anything has been calculated prior to it running, it really makes timing comparisons bogus#2018-12-0322:05borkdude@mfikes agreed. but can results from part-1 be used in part 2?#2018-12-0322:06mfikesOh, yeah, that seems “fair” IMHO :)#2018-12-0322:06borkdudecool. I’ll add this to the README#2018-12-0322:07borkdudewhen a test runs in 10ms when most of the solutions run in 200 or 300 ms it’s a smell 😉#2018-12-0322:07borkdudeso then I check if this is the case#2018-12-0322:08mfikesAn example of “cheating” would be to
(def xs (doall ,,,))
#2018-12-0322:09borkdudeyes. so top level (def data (map parse-int input)) is ok, since it’s lazy. not ok when realized outside the tests#2018-12-0322:14borkdudehttps://github.com/borkdude/advent-of-cljc/commit/543763a0f52f1f07bce1622b3bba1967c717c0d9#2018-12-0322:20borkdude@erwinrooijakkers your solution is still fast (although not as fast as measured before), congrats 🙂#2018-12-0322:27mfikesHaving said all this, ClojureScript was pretty slow on today’s problem. #2018-12-0322:33borkdude
CLJ
Testing aoc.y2018.d03.borkdude
part-2 took 756.09 msecs
part-1 took 57.66 msecs

Testing aoc.y2018.d03.iamdrowsy
part-2 took 653.79 msecs
part-1 took 83.38 msecs

Testing aoc.y2018.d03.mfikes
part-2 took 673.82 msecs
part-1 took 552.37 msecs

Testing aoc.y2018.d03.mrmcc3
part-2 took 762.67 msecs
part-1 took 0.40 msecs

Testing aoc.y2018.d03.transducer
part-2 took 157.78 msecs
part-1 took 23.40 msecs

CLJS
Testing aoc.y2018.d03.borkdude
part-1 took 5555.00 msecs
part-2 took 1677.00 msecs

Testing aoc.y2018.d03.iamdrowsy
part-1 took 5439.00 msecs
part-2 took 638.00 msecs

Testing aoc.y2018.d03.mfikes
part-1 took 5314.00 msecs
part-2 took 5760.00 msecs

Testing aoc.y2018.d03.mrmcc3
part-1 took 2589.00 msecs
part-2 took 177.00 msecs

Testing aoc.y2018.d03.transducer
part-1 took 639.00 msecs
part-2 took 75.00 msecs
#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:11baritonehands
user=> (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:06ihabunek
Advent 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:52athos
clojure.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:27borkdude
Testing 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-0522:12mfikesCool. My part 2 is naive reapplication of part 1.#2018-12-0522:12adammillerso is mine#2018-12-0522:12borkdude@mfikes clean solution!#2018-12-0522:13adammillerhttps://github.com/akmiller78/AdventOfCode2018/blob/master/src/advent/five.clj#2018-12-0522:14adammilleralso, used this example to play with the bit- fns#2018-12-0522:26mfikes@ben.grabow If you end up optimizing for ClojureScript, == is much faster than = for numerics. (It could help numeric-anti-pair? perf.)#2018-12-0522:28mfikesI wonder if Clojure is also faster if using == on numerics... Hrm.#2018-12-0522:32ihabuneki'm not seeing any speedups if i change my solution to use ==#2018-12-0522:32ihabunek~120ms for part 1 on my laptop#2018-12-0522:33Ben GrabowThanks @mfikes. I see about 30% speed up across the board with == but who knows how reliable that is across iterations.#2018-12-0522:33mfikesNice trick Ben employed, pre-purging for part 2; makes sense 🙂#2018-12-0522:35fellshardOh wow, you're right, you can leapfrog from part 1's solution into part 2#2018-12-0522:36fellshardNow I'm hyped to head home and tinker more, that's the biggest macro-level optimization I can think of for what I've got right now#2018-12-0522:35mfikesThe reason == is so much faster in ClojureScript is that it is essentially a macro, letting things compile straight down to direct numeric comparisons in JavaScript.#2018-12-0522:36adammillermade pretty big difference in my cljs times....didn't affect my clj times much.#2018-12-0522:37mfikesWow, that pre-purging trick leads to a speedup of 5.6 if applied to my naive aproach. 🙂#2018-12-0522:38ihabuneki'll be stealing that as well 😄#2018-12-0522:39adammilleryes, going to modify mine for that later this evening#2018-12-0522:42fellshardI'm sure you could map that onto category theory somehow...#2018-12-0522:42mfikesHah. Yeah, a proof that that is a legitimate optimization is right at the edge of where my mind is.#2018-12-0522:43fellshardcollapse . filter-unit = collapse . filter-unit . collapse ...#2018-12-0522:44fellshardA. collapse is already fixed-point B. filter-unit is structure-preserving, to the extent that you can run it at any point in the process without changing the end result#2018-12-0522:44fellshardBut I don't have anywhere near the terminology to express what that actually means XD#2018-12-0522:45mfikesThe single pass idea also could really use a proof. It felt a little sketchy, but I was convinced.#2018-12-0522:46fellshardIs that doing a sort of combinatoric split each time you ingest a letter, one with the letter in-place, and the other with it removed?#2018-12-0522:46fellshardStarts to remind me of... wait. Pumping lemma? Stack-based automata?#2018-12-0522:48mfikesTo me the single pass idea feels like adding a stream of single units to the end of a growing/shrinking polymer, doing the reaction as you add each individual unit.#2018-12-0522:48fellshardYeah, it's just a stack-based automata at that point, if even that, given it'd just be one node#2018-12-0522:48fellshardWhich is what your solution looks like#2018-12-0522:49mfikesYeah, Ben's does some interesting things with two ends and a reverse mixed in there 🙂#2018-12-0522:50mfikesOr something with a left and right. I haven't grokked it yet.#2018-12-0522:52fellshardHave a link to Ben's?#2018-12-0522:52fellshardAh nvm, I see it in the cljc#2018-12-0522:53Ben Grabow@mfikes It's the same thing you're doing but more opaque! My left is your reduce's accumulator.#2018-12-0522:56fellshardYeah; left is the accumulating stack, right is the remaining string stack#2018-12-0522:57fellshardThough I don't think the reverse at the end earns you anything, since the answer doesn't call for preserving the order#2018-12-0522:58mfikesYou could probably prove the single pass leads to a fully reacted polymer by using proof by induction #2018-12-0522:59Ben GrabowTrue! Reverses are not necessary since a polymer reacts the same forwards and backwards. Feels dirty to me to remove them though.#2018-12-0522:59fellshardIntuitively, the only information adding a new unit to the end can add is that A. a new element exists, or B. the top element is removed#2018-12-0523:00fellshardEven if a new element is re-exposed from that interaction, it's inert still, because it cannot interact with the thing below it on the stack (having already been tested in a prior recursive step)#2018-12-0523:00fellshardtherefore, it can only react with the following unused element in the remaining input string#2018-12-0523:01fellshardThe key is that the relative ordering of the 'seen' portion of the string remains the same, and is stable while new elements are added to the end#2018-12-0523:01mfikesYeah, base case (empty polymer) is inert, and each inductive step leads to a new inert polymer.#2018-12-0523:01fellshardThis is very similar to the type of thing you'd see for validly matching nested bracketed statements 🙂#2018-12-0523:02fellshardThat's the best way to put it, yeah#2018-12-0523:02fellshardinert#2018-12-0523:03fellshardhttps://en.wikipedia.org/wiki/Pushdown_automaton Good ol' days#2018-12-0523:15Ben GrabowI refactored to use reduce like @mfikes and got another 20-40% speed up#2018-12-0523:16mfikesIf we were competing with other languages on perf, Ben’s would be a good candidate :)#2018-12-0523:22Ben GrabowIt's like the anticipation of Christmas when waiting for CI perf test results to come back 🎄#2018-12-0600:20rymndhngfrom looking at a few other folks do it in other languages, my gut tells me the clojure solutions have been the most concise#2018-12-0600:21fingertoeI am having fun at failing at this 😉 Got mine done with about 4 or 5 approaches, all of them mighty slow… I suspect the liberal memoizing must be a pretty good skill to adopt??#2018-12-0600:30mfikesFor this particular problem, it is probably fair to say that the overall algorithm used can dramatically affect perf.#2018-12-0600:37adammilleryes, I actually got my answers with a regex/replace solution that was quite slow (but worked) but then refactored to a simple reduce that is quite fast.#2018-12-0600:40fingertoePretty good learning experience — Thanks everyone!#2018-12-0602:27ClashTheBunny@borkdude is there a reason title-cased usernames aren't allowed? Failed to validate "-u ClashTheBunny": Username must start with letter#2018-12-0602:48ClashTheBunnyAnybody know how to get a cljs repl in the advent-of-cljc repo?#2018-12-0603:39ClashTheBunnyHoly moly! Switching from last and butlast to peek and pop went from
CLJ: Testing aoc.y2018.d05.clashthebunny
part-2 took 222732.26 msecs
part-1 took 8448.07 msecs
to
CLJ: Testing aoc.y2018.d05.clashthebunny
part-2 took 405.82 msecs
part-1 took 9.60 msecs

CLJS: Testing aoc.y2018.d05.clashthebunny
part-1 took 154.00 msecs
part-2 took 905.00 msecs
#2018-12-0603:43potetmah yeah, that makes sense#2018-12-0603:43potetmlast & butlast say linear on the tin iirc#2018-12-0606:50Average-userDid anyone get a really efficient solution for day6?#2018-12-0606:55Average-userThis is what I did, but I'm not very content with it: https://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day06.clj#2018-12-0607:06fellshardStill plugging away, I did an off-by-one error at my boundary checks 😓#2018-12-0607:09Ben GrabowHaven't started yet, just brainstorming. I am expecting to need to use something like a convex hull algorithm to filter out the "infinite" regions. I might be overthinking it though.#2018-12-0607:10Ben Grabowhttps://en.wikipedia.org/wiki/Convex_hull_algorithms#2018-12-0607:11taylorI optimized for time-to-leaderboard 🙂 https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/6.clj part 1 takes 9s and part 2 takes 1s#2018-12-0607:18taylorthe infinite region exclusion is incomplete I think, but it didn’t matter for my inputs#2018-12-0607:35borkdude@clashthebunny That’s a bug in the validation probably 🙂 Welcome to fix it#2018-12-0607:36borkdude@clashthebunny specifically this line: https://github.com/borkdude/advent-of-cljc/blob/master/test/aoc/new.clj#L69#2018-12-0608:01rymndhng#6 was good -- what really helped me speedup was typehinting lol#2018-12-0608:21fingertoeSo, I think my lesson from day 5 just clicked… I am using the same recursion and such as the fast solutions.. I think the crux of the slowness is that I am asking (26*2)^2 possible questions “am I a reactive combination?” instead of asking the (2*26) questions “are you a reactive combination?” Haven’t tested it yet, but woke up thinking…#2018-12-0608:29erwinMessed up the infinite check today (but I really had no clue what to do at first...) https://repl.it/@ekroon/AOC2018-day06 #2018-12-0610:07fellshardHmmm. Now that I've done it the ugly brute-force way, I wonder if there's something simpler...#2018-12-0610:08fellshardThis is technically a discrete voronoi fill in part 1, and could probably be accomplished by a variant of Dijkstra's#2018-12-0610:13borkdudeI was confused by the description in part 2. I thought I had to calculate also if the region was connected#2018-12-0610:14borkdudebut that wasn’t a requirement per se#2018-12-0610:55borkdude
Testing aoc.y2018.d06.borkdude
part-2 took 389.71 msecs
part-1 took 5011.38 msecs
#2018-12-0610:58borkdude@mfikes there’s a warning in the build logs:
WARNING: /home/circleci/repo/cljs-test-runner-out/cljs_test_runner/gen.js:319: WARNING - incomplete alias created for namespace aoc.y2017.d07.mfikes
#2018-12-0611:00borkdudenot sure what that is about#2018-12-0611:03borkdudereproducable with script/test-one 2017 7 mfikes#2018-12-0611:27borkdude@erwinrooijakkers did you see my comment on your open PR..?#2018-12-0611:36erwinrooijakkersYes thanks, the code is different though. The guard->sleep-mask holds a data structure in the :sleep-mask key like [1 2 0 …] (length 60 vector where every index holds the total minutes). In solve-1 the sorted map is sorted by (apply +) (to find the total minutes) and in solve-2 it’s sorted by (apply max) to find the maximum. Thinking about this, maybe it sorts on another key… 🙂#2018-12-0611:38borkdudeah indeed, I see the difference is + vs max#2018-12-0611:38erwinrooijakkersMaybe it also sorts on guard number, and for your input the guard number is lower than the + and in mine it is higher. I’ll look into it! 😄#2018-12-0611:38erwinrooijakkersAfter work 😉#2018-12-0611:39borkdude😄#2018-12-0611:40ihabunek
user=> (> (priority aoc) (priority paid-work))
true
#2018-12-0611:41ihabuneki solved in elixir today so no clojure solution from me 🙂#2018-12-0614:00genmeblogspoilers!!!#2018-12-0614:00normanI haven’t had time to think about it, but I drew a boundary box around the points and assumed that anything that reaches the edge of that box would continue forever. This is probably easy to prove correct/incorrect, but I didn’ worry much about that last night.#2018-12-0614:01genmeblogboundary box coudn't be enough#2018-12-0614:02normanDo you have a counter example?#2018-12-0614:02taylorvisualization spoiler in reply…#2018-12-0614:02taylorhttps://i.imgur.com/ASYGGIG.png#2018-12-0614:04borkdudebeautiful#2018-12-0614:20borkdudeis this about part 1 btw?#2018-12-0614:21borkdudeI wondered about part 2, if the regions should be connected. I first assumed that, but I got the wrong answer#2018-12-0614:51Björn Ebbinghaus@borkdude Since you have to consider the distance to all points, it has to be a connected area.#2018-12-0615:24taylorYes this is part 1#2018-12-0616:56fellshardMy 'intuition check' for it is that I believe the convex hull of all points will pass through only the infinite regions. (With a caveat that that may not quite work for manhattan distance thanks to the square corners) If you have a square canvas around those points, which by definition encompasses the convex hull of those points, then that square should also pass through only the infinite regions, and so you can sniff around at the edges of the square to find them.#2018-12-0616:56borkdudeMy check is to verify if at least one of the coordinates in an area touches the edge.#2018-12-0616:58taylorI should note the black regions in the image are the points that are equidistant to two or more coordinates#2018-12-0616:59borkdudesorry, I meant the check if an area is infinite#2018-12-0614:03Average-userI think is enough, but I'm looking for a prove. But i think is because of manhattan distance. With euclidean distance wouldn't work#2018-12-0617:09Ben GrabowWith euclidian distance, let's take points A (0,0), B (100,0), and C (50, -1). (Assume more points below the x-axis that prevent C from having an infinite region in the +x, -x, or -y directions.) The minimum bounding box will have its upper edge on the x-axis. C will have many points in its region along the x-axis in the vicinity of x=50. To determine if C's region is infinite we need to consider whether it still has points on the edge of the bounding box as we extend the bounding box infinitely in the +y direction. As we do that, the hypotenuse distance from the box edge to the nearest point in the set of input points becomes dominated by the y distance, and the x distance becomes irrelevant. Consider a point directly above C, such that distance to C (dC) is defined as (dx, dy) and dB is (dx+50, dy-1). At small values of dy (i.e. close to the minimum bounding box), dB is larger than dC (meaning C has points on the box edge. However as dy approaches infinity, the hypotenuse distance (dx^2 + dy^2) becomes larger than ((dx+50)^2 + (dy-1)^2). So C's region is not infinite. However, if we translate this reasoning to manhattan distance, dx never becomes irrelevant as you expand the bounding box.#2018-12-0617:10Ben Grabow...continued...#2018-12-0617:11Ben GrabowIn the manhattan case, as dy approaches infinity, since the manhattan distance is the linear sum of dx + dy instead of the squared sum, dC will never get larger than dB. The same reasoning applies on the dA side, and by symmetry on all other edges of the bounding box.#2018-12-0617:13Ben GrabowThis isn't a proof that minimum bounding box (MBB) is sufficient in the manhattan case, but it shows that the reasoning I was using for the euclidian case is not applicable to the manhattan case. Someone good at proofs could probably turn this into a proof that MBB is sufficient for manhattan though.#2018-12-0617:16Ben GrabowWould appreciate some eyes on my reasoning for using the minimum bounding box approach.#2018-12-0618:21Average-userI prove that the minimum rectangle that enclose all points is enough#2018-12-0618:21Average-userproved*#2018-12-0614:04normanI spent all of 30 seconds thinking about whether it was correct or not, but it seemed like a reasonable starting poiint.#2018-12-0614:04taylora pretty naive approach worked for me w/r/t infinite regions, but I’m guessing there’s an input that would break it#2018-12-0614:05borkdudeLiving on the edge…#2018-12-0614:11genmeblog@norman I'm probably wrong... boundary box could be enough with manhattan distance#2018-12-0614:12normanMy intuition is there would always be a bounding box and the real question was how big that box would need to be. It surely shouldn’t have to be any larger than the distance between two points and may just be 1#2018-12-0614:13normanIt would be interesting to have be able to move points around in one of those visualizations to try and make a counter example#2018-12-0614:13normanWe#2018-12-0614:14normanI’ll think about it today at work.#2018-12-0614:17Average-userthe box should be the smallest rectangle that encloses all given points#2018-12-0614:18borkduderectangle?#2018-12-0614:24Average-useryes#2018-12-0614:25tayloranother spoiler visualization and how I detected infinite regions in thread#2018-12-0614:25taylorhttps://i.imgur.com/IkKGgyP.png#2018-12-0614:26taylorhere I made the infinite region coordinates darker dots than their region, and the non-infinite coords are lighter dots#2018-12-0614:26taylorand used lighter colors for the infinite regions#2018-12-0614:27taylormy approach to identifying infinite regions at first was simply finding the coordinates that were nearest the four corners of the bounding rect, which worked but isn’t “correct”#2018-12-0614:28taylormy second approach was to find the set of coords nearest each pixel around the edge of the bounding rect, and I think this is probably correct — at least it looks correct when visualized as opposed to my first approach#2018-12-0614:40borkdudeI just figured if an area has at least one coordinate with [0 y], [x 0], [max-x y], or [x max-y], then it’s infinite#2018-12-0614:40borkdudeso at least one coordinate at the edge#2018-12-0614:51taylorYeah that’s simpler and seems just as trustworthy #2018-12-0614:55borkdudeis this a vis of part 2 btw?#2018-12-0615:22taylorJust part 1. Not sure if I’ll have time to do part 2#2018-12-0621:28taylor@borkdude you've inspired me to try my hand at rendering a heat map for part 2, but maybe not until this weekend#2018-12-0614:35taylorday 6 w/Quil viz code https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/6.clj#2018-12-0615:10Average-user@taylor I sow In the code you published that you only check for closest points to corners. I think that will not always work, you should check points closest to every point in the frame that encloses all points.#2018-12-0615:12taylorAre you looking at the latest commit?#2018-12-0615:14taylorThat sounds like my first approach which worked well enough to solve the problem, but my latest commit uses a different strategy #2018-12-0615:38Average-userI'll check that out then#2018-12-0615:40Average-userOhh I see, so you did go for the frame approach. Very similar to what I did#2018-12-0616:03benoitMy super slow solution 🙂 (~ 20s for each part). Just doing the naive thing of walking through all points. https://github.com/benfle/advent-of-code-2018/blob/master/day6.clj#2018-12-0616:06borkdude@me1740 try to use (set! *unboxed-math* :warn-on-boxed), this sped up my solution significantly#2018-12-0616:09Björn Ebbinghaus1500ms/500ms [MrOerni/advent-of-code-2018/day06.clj](https://github.com/MrOerni/advent-of-code-2018/blob/master/src/advent_of_code_2018/day06.clj)#2018-12-0616:14benoit@borkdude Thanks, assuming you mean (set! *unchecked-math* :warn-on-boxed). I'm now at ~2.2s for part one and 317ms for part two.#2018-12-0616:14borkdudesorry, yeah#2018-12-0616:17Average-userI'm now at 8s/1s#2018-12-0616:18Average-userhttps://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day06.clj#2018-12-0617:16Ben GrabowWould appreciate some eyes on my reasoning for using the minimum bounding box approach.#2018-12-0618:10benoitI did a visual proof to convince me that the points on the bounding box belong to infinite areas. If you take a point and a line going through it. All the areas defined by the perpendicular bisectors with the points on one side will create areas that are infinite on the other side of this line. So if you want to close the area that includes this point you will need at least one point on the other side of this line. Now if you take a point on the bounding box and the side of the bounding box as the line, by definition the points on the bounding box have only points on one side of this line so they will all belong to areas that are infinite outside of the bounding box. That was good enough to convince me 🙂#2018-12-0618:28Average-userOk: If we have a set R of points that form the perimeter of the smallest rectangle that encloses all points. Then if some element (r) of R has minimum distance with some point (p) of given points set (P), then one of the neighbors of r will also have minimum distance with p. Inductively, if r has a point p as minimum distance, then there are infinite points that have p as minimum distance. If we have a point outside R, then every point between that and the closest point of R, will have the same minimum distance. Therefore it cant exist a point outside R that has minimum distance with some point in P. Without a point r that has minimum distance with the same point in P. Hope is understandable#2018-12-0618:29lilactownI've been stuck on yesterday's part 1 for ~24 hrs. turns out I forgot to trim whitespace :face_with_symbols_on_mouth:#2018-12-0618:29Average-userHad the same problem in day 5#2018-12-0622:13pesterhazyDay 6: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle06.clj#L82#2018-12-0622:21fellshardMine ran horrendously slowly compared to the times some others are getting. How do y'all usually get detailed profiling on execution beyond bench runtimes?#2018-12-0622:28taylorI've used https://github.com/ptaoussanis/tufte long ago, might be useful for AoC#2018-12-0622:29taylor(and of course there's Criterium)#2018-12-0622:34borkdudeyeah, except that it doesn’t work on ClojureScript right now#2018-12-0622:41lilactownso many of these later challenges make mutability feel like a real feature. funny how it in no way reflects my day job 😛#2018-12-0702:10potetmSo I thought this as well (esp on Day 4). I was wrong. The correct impl was a change of algorithm to use a linked list! The OG immutable structure!#2018-12-0622:42borkdude@lilactown yeah, it’s very different from my daily coding as well#2018-12-0622:43adammillerdefinitely great practice for both problem solving and writing code....makes me realize I need to be doing this more often!#2018-12-0622:52mattlysame, and yet, these are similar to actual problems I've hit in my real jobs at some point#2018-12-0622:52mattlyon the flip side, I don't think anyone would play "advent of Scrum"#2018-12-0702:10potetmSo I thought this as well (esp on Day 4). I was wrong. The correct impl was a change of algorithm to use a linked list! The OG immutable structure!#2018-12-0702:00potetm> You emerge from the chimney to find a circle of your peers. Hark! A spot has been left for you! You take a seat, and they inform you that they’re having a Christmas Eve Retrospective. > > Your mission is to write all of your mad, sad, and glad moments on postcards. You have three minutes. If you fail, Santa will send you back to the North Pole where you’ll spend the next year shoveling coal for the naughty boys and girls.#2018-12-0702:10Average-userI find very satisfying when is possible/necessary to apply discrete mathematics to really solve a problem, so day 6 has been my favourite this year. Like there is always Project Euler but it is too much oriented in number theory or similar topics#2018-12-0702:10fellshard'Some, but not down the rabbit hole'#2018-12-0702:11fellshardDiscrete Voronoi? ¯\(ツ)/¯#2018-12-0702:12potetmlooks like it!#2018-12-0704:24mfikesDay 6: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_06.cljc#2018-12-0704:33fellshardHoly crap. Note to self: type hint more. Those box warnings are gonna be super helpful, and the emacs integration helps narrow it right down#2018-12-0704:35ClashTheBunnySuper not proud of my six, but here it is: https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day06.clj#2018-12-0708:03rymndhngwhew, #7's part 2 was quite a grind, but ultimately fun to model scheduling in clojure!#2018-12-0708:40pesterhazyMy day 7: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle07.clj#L64#2018-12-0708:41pesterhazy@rymndhng agreed, this was fun. Would love to see your solution#2018-12-0708:41pesterhazyI wonder if recursion via loop is the best way to approach this - I did end up with a lot of nested conditionals#2018-12-0710:48borkdudeI thought I could use tree-seq for day 7, but depth-first doesn’t work here… I haven’t solved it yet#2018-12-0710:48borkdudehopefully later today#2018-12-0710:53borkdude@erwinrooijakkers note that there are 2 other solutions in 2017 that also don’t work for the given input. These solution probably have overlooked a small edge case. You’re still welcome to submit the code, but maybe do a println in the test “TODO: fix for this input”#2018-12-0710:54borkdude@erwinrooijakkers e.g.: https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2017/d02/mfikes.cljc#L20#2018-12-0713:59benoitMy solution for Day 7 https://github.com/benfle/advent-of-code-2018/blob/master/day7.clj#2018-12-0714:29taylorthese are starting to get too difficult to solve at 11pm CST 💤#2018-12-0714:43gklijsFor me they're there 6 in the morning, I do get up early, bu then I first have to travel, work, travel, cook, except for at most 30 minutes in the morning, which is to short.#2018-12-0714:50ihabunek6am for me too, not really meant for us european types. i like sleep too much to even attempt solving them at that ungodly hour.#2018-12-0714:56borkdudeI have four different letters that I can start with. If I choose the first one alphabetically, there is no answer.#2018-12-0714:56borkdudeShould I just try them all, or is there some logic to this?#2018-12-0714:56mattlyI've got a similar situation#2018-12-0714:57mattlybut then I'm not sure I don't have a bug#2018-12-0714:58ihabunekif you give me your input, i can try my solution and tell you if it gives an answer#2018-12-0714:59mattlyhttps://github.com/mattly/advent-2018/blob/master/clojure/resources/07.txt#2018-12-0715:00borkdude@ihabunek input in PM#2018-12-0715:00mattlyI'm fairly sure I have a bug#2018-12-0715:01borkdudeI’m probably having a bug too, because none of the starting letters give an outcome, while my code works for the example#2018-12-0715:02ihabunek@mattly @borkdude yeah, both of your inputs give me a solution similar to what I got.#2018-12-0715:02borkdudethanks#2018-12-0715:02ihabunekso i'm guessing you have a bug#2018-12-0715:02mattlyok cool#2018-12-0715:03mattlythanks#2018-12-0715:05benoit@borkdude I think the first letters should be handled the same way you handle the normal case.#2018-12-0715:05borkdude@ihabunek do you only have one letter to begin with?#2018-12-0715:06benoit@borkdude I had 3 letters to begin with#2018-12-0715:06borkdudeok, so alphabetically that is - right?#2018-12-0715:06mattlyfound my bug#2018-12-0715:07benoit@borkdude yes you try each in turn alphabetically#2018-12-0715:07borkdudeok#2018-12-0715:07mattlyboom, got it, thanks again#2018-12-0715:08ihabunek\o/#2018-12-0715:08ihabunek@borkdude let me check#2018-12-0715:10borkdudeI think I found my bug as well#2018-12-0715:11helioswhat was it? 🙂#2018-12-0715:11ihabunekcool, then I won't give any hints 🙂#2018-12-0715:11borkdudestill figuring out, but I’m close…#2018-12-0715:18borkdudegot it right 😄#2018-12-0715:18borkdudenow part two… 😕#2018-12-0717:22borkdudeLOL, my answer for part 2 was too low. So I tried +1… to test if I had a off by one error, and I did.. now I still need to fix it#2018-12-0717:34fellshardHad off by one here as well for quite a while.#2018-12-0717:45potetmsame, but too high#2018-12-0717:47potetmThe fix was to decrement my counter by 1 🙈 🙉 🙊#2018-12-0717:54potetmhttps://www.twitch.tv/timpote — with shoutouts to the channel 🙂#2018-12-0719:03meikemertschThanks for the stream and the answers#2018-12-0719:03potetmMy pleasure!#2018-12-0718:40rymndhng@pesterhazy here's what I got for day 7: https://github.com/rymndhng/advent-of-clojure/blob/master/src/advent_2018/07.clj I modelled part 2 with a lazy sequence 😁#2018-12-0719:18meikemertschHi folks! I am still pretty new to Clojure (and haven’t programmed any in … years.). My colleagues started AoC and I thought that’s perfect for doing some programming. Does anyone mind having a look at my code and giving me some pointers of what can be better / faster / more clear or any other way useful? Here’s a gist. I also included my test file… https://gist.github.com/MeikeMertsch/6a14074aa336f4d377c5d0fb6a01ca2b#2018-12-0719:23adammillerfinally getting around to this one today. I also am getting the correct answer on their sample data, but on real data it's not correct. Anyone else have some sample data and answer that I can use to test?#2018-12-0719:24meikemertschhave you considered both the difference in time as well as the count of workers?#2018-12-0719:25meikemertschI forgot one of them in the beginning#2018-12-0719:26meikemertschoh. Part one. I am sorry 😞#2018-12-0719:26adammillerthis is on step 1 where i'm getting wrong answer (although it's fine for the test data)#2018-12-0719:26adammillerno problem#2018-12-0719:27meikemertschDo you want to show your code? Then I can tell you if I spot where you’re making an assumption that isn’t right?#2018-12-0719:32adammillerI don't mind but I think I may have found it....working on it now. Thanks though!#2018-12-0719:33meikemertschGood luck 🍀#2018-12-0719:23adammilleron step 1 that is#2018-12-0719:23adammillersample data must definitely be missing edge case#2018-12-0719:38borkdude
Testing aoc.y2018.d07.borkdude
part-2 took 56.77 msecs
part-1 took 2.43 msecs
#2018-12-0719:50borkdude
Testing aoc.y2018.d07.borkdude
part-2 took 45.78 msecs
part-1 took 1.70 msecs
#2018-12-0719:52borkdudeOn CI:
Testing aoc.y2018.d07.borkdude
part-2 took 25.26 msecs
part-1 took 1.25 msecs
#2018-12-0719:52borkdudeThis wasn’t an easy one for me… lots of println#2018-12-0719:54borkdudecode: https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2018/d07/borkdude.cljc#2018-12-0719:59borkdudeI wouldn’t be surprised if there was a very elegant short solution to this#2018-12-0720:00borkdude(mfikes start typing, there it comes…)#2018-12-0720:00mfikesIm getting off-by one as well, wondering if AoC itself has a bug.#2018-12-0720:01borkdudeit’s a bit finicky to get the loop exactly like in the example page#2018-12-0720:01borkdudeI got it only working by mimicking that every second#2018-12-0720:06gklijsI'm just kind of done, also have the of by one. It's kind of one the example page itself. Somehow you need one second without anybody doing anything#2018-12-0720:06benoitPart 2 was challenging for me too. Which is why I broke down the algorithm into little step functions.#2018-12-0720:07benoit@gklijs I think you're right. I also used the fact that all workers were idle for the definition of done.#2018-12-0720:07taylorcan't tell if I'm getting older & dumber or if the difficulty ramp is steeper this year#2018-12-0720:07gklijsjust add one in the return then 😛#2018-12-0720:08borkdude@taylor somehow I managed to do AoC every day last year, but I wasn’t sure if I was going to do that this year…#2018-12-0720:08tayloryeah, at some point the problems (at least to me) start becoming complex in a... non-gratifying way. Last year it was the last few days#2018-12-0720:09gklijsTime for some blasphemy#2018-12-0720:09gklijsMain part of the java solution
private static Integer go(final Map<Character, Set<Character>> graph, final int workers, final int additionalSeconds) {
        int workersWorking = 0;
        List<Character> done = new ArrayList<>();
        Map<Character, Integer> atWork = new HashMap<>();
        int timeSpend = 0;
        while(! graph.isEmpty()){
            Character nextTask = nextTask(graph, done);
            while(nextTask != null && workersWorking <= workers){
                workersWorking++;
                atWork.put(nextTask, nextTask - 64 + additionalSeconds);
                graph.remove(nextTask);
                nextTask = nextTask(graph, done);
            }
            int progresTimeBy = atWork.values().stream().reduce(Integer.MAX_VALUE, (o,n) -> n < o ? n : o);
            timeSpend+= progresTimeBy;
            List<Character> justCompleted = new ArrayList<>();
            for(Map.Entry<Character, Integer> entry : atWork.entrySet()){
                if(entry.getValue() == progresTimeBy){
                    justCompleted.add(entry.getKey());
                }else{
                    entry.setValue(entry.getValue() - progresTimeBy);
                }
            }
            for(Character complete : justCompleted){
                atWork.remove(complete);
                done.add(complete);
                workersWorking--;
            }
        }
        return timeSpend + 1;
    }
#2018-12-0720:10taylorMY EYES!#2018-12-0720:10meikemertschWhat are those dots in…. wait… that’s Java 😮 😱#2018-12-0720:11borkdudenice, you optimized your Clojure code#2018-12-0723:06pesterhazyThose curly braces take a while getting used to but after while you stop seeing them #2018-12-0720:12borkdude@taylor yeah, last year there were some fun insight, like https://en.wikipedia.org/wiki/Ulam_spiral#2018-12-0720:13borkdudeand on another day bhauman had some very nice solution with tree-seq, I still remember that one#2018-12-0720:14ClashTheBunnyIt would be really nice if I didn't have to sign up for a bunch of different accounts to get more test data...#2018-12-0720:15borkdude@clashthebunny the creator of AoC was a bit worried about me doing that: https://github.com/borkdude/advent-of-cljc/issues/6#2018-12-0720:15gklijsIf you know the value from the cookie you can get their data#2018-12-0720:15ClashTheBunnyI know.#2018-12-0720:16ClashTheBunnyI just wish there were other options, like give me 5 test cases generated the same way as you do the normal ones that aren't actually for credit.#2018-12-0720:17gklijsIt's worse, the example doesn't match with the actual value needed#2018-12-0720:19borkdudeusually if there are problems, look at https://www.reddit.com/r/adventofcode/ to verify if it’s a real one#2018-12-0720:19borkdudehttps://www.reddit.com/r/adventofcode/comments/a43k6z/day_seven_part_two_example_confusion/#2018-12-0720:38borkdudeMessage from the global leaderboard: > Because of a bug in the day 6 puzzle that made it unsolvable for some users until about two hours after unlock, day 6 is worth no points on the global leaderboard.#2018-12-0720:52borkdudeoh yes, str/join can be called without a sep. so I don’t have to do (apply str coll) which I’m very used to. https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2018/d07/iamdrowsy.cljc#L36#2018-12-0720:53borkdudeand this solution is fast!#2018-12-0720:53drowsybut also not that pretty 🙂#2018-12-0720:54borkdudeI’m not sure if today has a pretty solution#2018-12-0720:55adammillerstep 1 pretty small simple....step 2 i'm still working on so I don't know yet!#2018-12-0720:57mfikesDay 7: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_07.cljc#2018-12-0721:06adammilleralthough i had problem with step 1 where my solution worked great for their test data but not the real one. Had to create some of my own examples to realize my issue.#2018-12-0721:09taylorsame, I struggled with a bad approach for two hours b/c it passed on the simple example#2018-12-0721:13gklijsIn that case I start to doubt my solution.. I get 14 on the example, but correct answer on the actual one, but a co-worker has the 'correct' answer in both cases#2018-12-0721:17borkdude@gklijs I got 14 as well a couple of times#2018-12-0721:19normanI didn’t have any major non-obvious bugs, but I did make a false start. My first pass through, I traversed the graph from leafs to head. Choosing the most expensive node that didn’t depend on anything not yet traversed.#2018-12-0722:18Ben Grabow@norman @adammiller Would either of you mind explaining how the graph-based solution works, or sharing your solutions? I know intuitively I should be able to use the graph to find the unblocked tasks at each step but I can't wrap my mind around the details.#2018-12-0722:22fellshardhttps://en.wikipedia.org/wiki/Topological_sorting#2018-12-0722:45normanhttps://github.com/orb/advent2018/blob/master/src/advent2018/day7.clj#L43#2018-12-0722:46normanpart2 is not very clean, and I think now I even see a a bug, but part 1 is a relatively straightforward traversal using loop. I’ll step through it here.#2018-12-0722:48normanI represented the graph exactly like a the input. I have a vector of edges like [“C” “A”] which means there is an edge from C to A.#2018-12-0722:49normanA very simple approach is to maintain a list of nodes you’ve visited and a list of nodes you haven’t visited#2018-12-0722:50normanThen have a function that picks an unvisited node that is reachable and visit it. (move it from the unvisited list to the visited list) You repeat until you are done#2018-12-0722:51normanIn my solution here, I maintain the graph, the nodes list (everything I can visit) and the visited list (in order)#2018-12-0722:51normanThe function next-work does the job of selecting the next node I should visit (the lowest of all the ones I can visit).#2018-12-0722:52Ben GrabowI think what is tripping me up is how to find the newly unblocked nodes by traversing the dep graph from a newly completed node. Right now I'm doing a bunch of filtering over the entire list of nodes.#2018-12-0722:52normanI did this by removing he unblocked edges from the graph#2018-12-0722:53normanSo if I visit “C” , I remove [“C” “A”] and [“C” “F”] from the graph#2018-12-0722:53normanand by doing so, A and F becoming visitable#2018-12-0722:56normanIn removing the edges like this I only have to ask for any node N if there as an edge [? N].#2018-12-0722:56normanIf you don’t remove the edges, you’d jave to ask if there is an edge [? N] where ? is not visited#2018-12-0722:59Ben GrabowIt seems like I need two graphs, one of X -blocks-> Y and one of Y -is-blocked-by-> X. I follow the first graph to find the potentially unblocked nodes when a node is completed, and I use (and modify) the second graph to figure out if a potentially unblocked node is actually unblocked. Without those I think I need to do some set-based or iteration-based queries along the way. Does that sound right?#2018-12-0723:02normanYou could invert the graph, but there’s really no need#2018-12-0723:06normanIf there is a edge [“X” “Y”], which means “X” before “Y”, if you’ve visited “X” then you can disregard the edge. There’s nothing more to check#2018-12-0723:08Ben GrabowMakes sense. Thanks for the explanation, it helped a lot!#2018-12-0721:19normanThis produced an equivalent traversal for the sample input, but not the test input#2018-12-0721:21normanChanging the traversal required only changing two words, so thankfully my poor decision didn’t cost much
#2018-12-0721:22adammillerdid the same exact thing, and yes it was pretty simple to switch from depth to head traversal.#2018-12-0721:22borkdude
Testing aoc.y2018.d07.borkdude
part-2 took 25.33 msecs
part-1 took 1.19 msecs

Testing aoc.y2018.d07.iamdrowsy
part-2 took 11.15 msecs
part-1 took 1.73 msecs

Testing aoc.y2018.d07.mfikes
part-2 took 21.22 msecs
part-1 took 39.40 msecs
#2018-12-0721:27mfikesFWIW my part-1 was initially faster, but since perf was good enough, I made part-1 be based on running part-2 in 2nd gear.#2018-12-0721:27borkdudeyeah, I liked your refactor. I was tempted to do the same#2018-12-0721:28borkdudebut I chose to move the common things into a delay instead#2018-12-0721:28borkdudewhich is ugly, but it works#2018-12-0721:23mfikesI had some false starts trying to sort first and then write a stable topological sort. I finally made progress when I carefully read the sample solution sequence and essentially wrote an imitation of that description.#2018-12-0721:24borkdudesame here#2018-12-0721:25mfikesIn other words, that bulleted list under the graph is essentially an algorithm.#2018-12-0721:27borkdudeyou mean an algorithm with a name?#2018-12-0721:28mfikesNah, I just mean: They are telling you one way to actually solve the problem.#2018-12-0721:28mfikesInstead of just leaving you with a problem description.#2018-12-0721:29borkdudeyeah, you had to read very closely.#2018-12-0721:30taylorwhich I did not do at first 🙂#2018-12-0721:30mfikesYeah, I didn't read that part initially (it is arguably not essential), and doggedly pursued my own path. When I saw the word "available" in that description, that did the trick for me.#2018-12-0721:31mfikesPerhaps many readers stop right at the sentence "If more than one step is ready, choose the step which is first alphabetically." (Recognizing that it is a partial order that it turned into a total order by that constraint.)#2018-12-0800:29potetm(sorted-set) helps a little here, I think#2018-12-0800:39fellshardGood call!#2018-12-0800:47Ben Grabowsorted-set is also useful in part 2 for keeping track of the in-progress tasks, sorted by time of completion.#2018-12-0801:44gklijsI can't quickly check for myself right now, but if you add something to a 'sorted-set' it might be added out of place? The documentation isn't clear, in Java it's a specific type of set which does keep order.#2018-12-0802:00Ben Grabow(conj (conj (conj (sorted-set) 1) 2) 0) => #{0 1 2}#2018-12-0802:01Ben GrabowSorry, that's terribly formatted.
(-> (sorted-set)
    (conj 1)
    (conj 2)
    (conj 0)) => #{0 1 2}
#2018-12-0802:02Ben GrabowMuch better#2018-12-0802:14potetm@gklijs I’m assuming it’s always natural sorting by default.#2018-12-0802:14potetm(same as the java set)#2018-12-0802:16potetmSo letters will stay in alphabetic order#2018-12-0805:27gklijsjust tries in the repl (def test-set (sorted-set "d" "c" "r" "m" "a")) gives #{"a" "c" "d" "m" "r"} and (conj "n" test-set) evaluates as #{"a" "c" "d" "m" "n" "r"}#2018-12-0805:27gklijsso it works#2018-12-0721:35mfikesWe need to get Wastl to add {:year 2018} to that little "year clicker" in the upper left of the main part of the page 🙂#2018-12-0721:35borkdudeI wonder how much fun Eric Wastl had by creating this. Oh, do these two things in one iteration sometimes so people get an off by one error probably#2018-12-0722:00Ben GrabowInteresting that on my data set and @borkdude’s data set I never had more than 5 tasks ready at a time, so I never ran out of workers. I engineered my solution (incorrectly I think) to handle a backlog of ready tasks but it never came into use. I wonder if this is true for all data sets?#2018-12-0722:02benoit@ben.grabow I think you were right to do it this way. There was no way to know this from the description of the problem.#2018-12-0722:04Ben GrabowI say "incorrectly" because I think my implementation is wrong, not because it's unnecessary. I am taking items out of the backlog in the order they were unblocked, when I should be taking out in alphabetical order at the time a worker is available.#2018-12-0722:04benoitoh ok#2018-12-0722:18Ben Grabow@norman @adammiller Would either of you mind explaining how the graph-based solution works, or sharing your solutions? I know intuitively I should be able to use the graph to find the unblocked tasks at each step but I can't wrap my mind around the details.#2018-12-0722:19adammillerI only did that in the first part. Haven't done the 2nd part yet, although i was trying a similar solution but no luck as of yet.#2018-12-0722:20fellshardThe visual chart they give for part 2 basically tells how to interpret it, I think#2018-12-0722:21fellshardEach letter on each row represents a full second starting at that number that is dedicated to that work#2018-12-0722:22fellshardSo the first row says 'starting at time 0, C is being worked on for one second, meaning that work on C will continue until at least the 1-second mark; it fills that entire first second.#2018-12-0722:23fellshardExtend that to the penultimate row, where the last piece of work is being done: 'starting at time 14, E is being worked on for one second'#2018-12-0722:23fellshardThis means that the work on E finishes at second 15#2018-12-0722:24fellshardBeing consistent in how you frame each step in terms of the overall time is a bit tricky, for sure#2018-12-0722:28mfikesI sent this to Eric: https://twitter.com/mfikes/status/1071169374587899905#2018-12-0722:41mfikes#2018-12-0722:44Ben GrabowLater tonight I'm going to take another stab at d6p2. I think it can be wildly efficient. If my reasoning is correct, then the "total manhattan distance" map has a consistent x-profile at every y-value, and a consistent y-profile at every x-value. To get the solution you compute one x-profile, one y-profile, then you can use those two profile to compute the rest of the "total manhattan distance" map without looking up the points at all. I feel like this would be instantly obvious when looking at a visual representation of the answer.#2018-12-0800:00Ben GrabowNifty, it worked. Brought the run time down from 30 secs for my naive brute force solution to 100 msecs for the efficient solution. I think there's room for improvement still, but it's super satisfying to find the efficient solution hidden in the rubble.#2018-12-0800:05fellshardIt makes sense. The manhattan distance function would just look like a 3-d inverted pyramid centered on that point (e.g. \/ ), and the sum of distances is just gonna be the sum of those functions, which in turn are just the sums of the 2-d cross-sections#2018-12-0800:29potetm(sorted-set) helps a little here, I think#2018-12-0800:38thegeez(sorted-set) ftw https://github.com/thegeez/clj-advent-of-code-2018/blob/master/src/advent2018/core.clj#L747#2018-12-0801:00fellshardMine's not exactly optimally expressed - there's some duplicate calculations I'd like to weed out - but I think it reads nicely 🙂 https://github.com/armstnp/advent-of-code-2018/blob/master/clojure/src/advent_of_code_2018/day7.clj#L67#2018-12-0804:37ClashTheBunnyI tried passing around data this time and having each function recieve and transmit the same data structure. It could have been just as easily done with an atom. I have never tried something like this before and it was super painful. What do other people do? https://gitlab.com/randall.mason/advent-of-code/blob/master/src/advent_of_code_2018/day07.clj Also, gitlab may be having struggs?#2018-12-0805:01Ben GrabowI like the idea of ancillary functions taking a large map of all the data, then only operating on the subsets the function needs. It's very "inversion of control" style.#2018-12-0805:02Ben GrabowI think you could improve your usage of the style by having your ancillary functions return the whole map, after performing some update-in calls to update the keys that pertain to that function.#2018-12-0805:03Ben GrabowThen where you are calling the ancillary functions you can use a threading macro:
(->> the-data
     do-thing-1
     do-thing-2
     do-thing-3)
#2018-12-0805:05Ben GrabowAh, I see it's basically what you're doing but instead of calling update-in and letting the other values come along for the ride by default, you are manually reconstituting the map including all the keys that don't pertain to the function.#2018-12-0805:12Ben GrabowHere are a couple examples; https://gist.github.com/bgrabow/0306387873ec31e053091eff73c50626#2018-12-0805:42ClashTheBunnyYeah, that's a whole ton more readable. The way I was doing it I was losing some keys when I tried that. Do you not have to enumerate ll the keys, or just the ones you use?#2018-12-0805:46Ben GrabowAll the data will be preserved if you bind the whole map in your arg list (the :as the-data part).#2018-12-0805:47Ben GrabowAnd then instead of returning a map from scratch, you return the result of calling (update the-data k f)#2018-12-0805:49Ben Grabow
(let [m {:a 1 :b 2 :c 3}]
  (update m :b inc)) ; => {:a 1, :b 3, :c 3}
#2018-12-0805:51Ben Grabow@U09NVRNG2 I think the second example in my gist was a little off. If you have a brand new value for a key, you should use assoc. If you want to apply a function on the old value to get the new value, you should use update. Hope that helps.#2018-12-0814:26ClashTheBunnyI have finally gotten the update assoc distinction, so at least I'm not learning that! 🙂#2018-12-0805:18mattlyso is it just me or is day8 part 1 really unclear how you're supposed to split up child nodes?#2018-12-0805:20gklijsIt's clear to me#2018-12-0805:21mattlyhm#2018-12-0805:24mattlyok i think i got it#2018-12-0805:27gklijsI just woke up, want to be the first of the team for once#2018-12-0805:36fingertoeMy day 7: https://github.com/jreighley/advent-of-cljc/blob/master/src/aoc/y2018/d07/jreighley.cljc I would love some code review — I am a lonely self taught hack. 😉#2018-12-0805:59normanI’m really curious to see other people’s approaches to stream processing today.#2018-12-0806:18mattlyI'm done with part 1, my solution is in my own repo though#2018-12-0806:40gklijsThere is a very sneaky thing in part 2#2018-12-0806:43gklijsYou might even say the business requirements aren't clear#2018-12-0806:44mattlymm, I'd say they're off by a small amount#2018-12-0806:42mattlyyeah#2018-12-0806:48athosToday's was relatively easy, compared to yesterday's 😃#2018-12-0807:54baritonehandsMy favorite part of day 7 was my fn to parse the line:
(defn parse-line [line]
  (let [[[lhs] [rhs]] (->> (str/split line #"tep ")
                           (drop 1))]
    [lhs rhs]))
#2018-12-0807:58baritonehandsDay 8 was definitely easier, day 7 was the hardest so far for me#2018-12-0808:02heliosi've never worked with zippers, and therefore I am having troubles wrapping my head about parsing day 8 😞#2018-12-0808:04baritonehandsI didn't use zippers, just regular split by space#2018-12-0808:04baritonehandsbut I did use trampoline for the first time to avoid a stack overflow#2018-12-0808:25fellshardI didn't end up with a deep enough tree to have to worry about stack overflows. Maybe I should test it against other inputs.#2018-12-0811:00magic_bloatNo stack overflow for me, raw recursion worked fine.#2018-12-0811:40rymndhngI think I had similar pains as you @helios, my solution of having a functional parser required using both stack-recursion and loops for state magenement which is unfamiliar for me to piece together. soln: https://github.com/rymndhng/advent-of-clojure/blob/master/src/advent_2018/08.clj#2018-12-0812:11benoitMy solution for Day 8: https://github.com/benfle/advent-of-code-2018/blob/master/day8.clj#2018-12-0812:12benoitIt's always painful to write a parser in a functional style so I did it with local state 🙂#2018-12-0813:49normanI’ve actually never seen/used volatile! before. Looks like a new 1.10 thing? Time to learn something new 🙂#2018-12-0813:53pesterhazythey've been there since 1.7 https://github.com/clojure/clojure/blob/master/changes.md#21-transducers#2018-12-0813:53pesterhazynot sure if they're documented except for the (tautological?) docstrings#2018-12-0813:54normanI found this, https://stackoverflow.com/questions/31288608/what-is-clojure-volatile#comment50623688_31288608 - looks like a good summary#2018-12-0814:07pesterhazyI wonder is there a rule of thumb when volatiles are safe to use#2018-12-0814:08pesterhazyand when atoms are required instead#2018-12-0815:10benoitMy rule of thumb is to use volatile unless I have concurrency. There is also transient for IEditableCollection. https://clojure.org/reference/transients#2018-12-0815:14pesterhazybasically keep them contained in a single fn right?#2018-12-0815:27benoitThere are two aspects: - for correctness: ensure the volatiles/transients are not accessed by multiple threads. They don't ensure atomicity. - for code organization: If I use state I prefer to keep it as local as possible so in this case inside the function#2018-12-0815:32pesterhazygood points both#2018-12-0813:27pesterhazyMy day 8: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle08.clj#L37 - I took the functional route#2018-12-0813:29pesterhazy- bad: I was stuck for half an hour because I didn't realized that children are 1-indexed (why??) - good: In the process I rediscovered clojure.tools.trace (which I'm sure will be useful later on)#2018-12-0813:59gklijsIt's pretty clear in the text to ignore the 0, and use the 1's as zero. Your lucky with using clojure since sometimes the index is higher then the number of children. With clojure they must are ignored, which not always is a good thing.#2018-12-0814:05pesterhazyI'm talking about the "meta-data`, which (in my test data) includes no 0s#2018-12-0814:06pesterhazyI agree that it's clear from the text (I was hasty once more)#2018-12-0813:37namenuI'm trying to use clojure.core.reducer/fold with @.mfikes's day 5 solution. https://gist.github.com/namenu/21e5d99989fddb1447ba446ca53e40a6#2018-12-0813:37namenuBut I don't know why the merging fn is not called. 😞 Any advice?#2018-12-0813:46pesterhazyStarted a journal to remember the problems I'm running into and maybe come up with some conclusions: https://github.com/pesterhazy/advent2018/blob/master/journal.md#L1#2018-12-0813:55athos@namenu By default, only a vector and a hashmap are foldable https://github.com/clojure/clojure/blob/c4dc8815272382725ca3d3d06f195e57c3228109/src/clj/clojure/core/reducers.clj#L320-L334#2018-12-0814:00namenu@athos Oh, that's the point! thanks 😄#2018-12-0814:16mfikesDay 8: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_08.cljc#2018-12-0814:17pesterhazy@mfikes almost identical to mine!#2018-12-0814:17pesterhazyhttps://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle08.clj#L37#2018-12-0814:18mfikesWow!#2018-12-0814:20pesterhazydifferences - reduce vs loop (I think I prefer loop here) - different tree-seq params (not sure why mine works)#2018-12-0814:52meikemertschAs a beginner I’d like to ask why you prefer loop over reduce here?#2018-12-0814:54pesterhazyessentially because the 2nd argument in the reduce-fn is ignored#2018-12-0814:55meikemertschI just saw you mentioned it in the main thread. Thanks tons!#2018-12-0814:25pesterhazyjust discovered the private leaderboard#2018-12-0814:45ClashTheBunnyI'm getting a spec error on my local machine from time to time on the advent-of-cljc tests. Does anybody know what I'm doing wrong? This compiled fine last night...#2018-12-0814:45ClashTheBunny
=== Running clojure test aoc.y2018.d07.clashthebunny

Running tests in #{"src"}

Testing user

Ran 0 tests containing 0 assertions.
0 failures, 0 errors.

=== Running cljs test aoc.y2018.d07.clashthebunny
#error {
 :cause Library name must be specified as a symbol in :require / :require-macros; offending spec: [] at line 1 /Users/ranmason/code/advent-of-cljc/cljs-test-runner-out/gen/cljs_test_runner/gen.cljs
 :data {:file #object[java.io.File 0x70c69586 /Users/ranmason/code/advent-of-cljc/cljs-test-runner-out/gen/cljs_test_runner/gen.cljs], :line 1, :column 1, :tag :cljs/analysis-error}
 :via
 [{:type clojure.lang.ExceptionInfo
   :message Library name must be specified as a symbol in :require / :require-macros; offending spec: [] at line 1 /Users/ranmason/code/advent-of-cljc/cljs-test-runner-out/gen/cljs_test_runner/gen.cljs
   :data {:file #object[java.io.File 0x70c69586 /Users/ranmason/code/advent-of-cljc/cljs-test-runner-out/gen/cljs_test_runner/gen.cljs], :line 1, :column 1, :tag :cljs/analysis-error}
   :at [cljs.analyzer$error invokeStatic analyzer.cljc 718]}]
#2018-12-0814:46ClashTheBunnyThat file is generated with the empty brakets at the top:
cat /Users/ranmason/code/advent-of-cljc/cljs-test-runner-out/gen/cljs_test_runner/gen.cljs
(ns cljs-test-runner.gen
       (:require [doo.runner :refer-macros [doo-tests]] []))
#2018-12-0814:49ClashTheBunnyI've done a git clean -fdx, so I am pretty sure I'm not being bitten by cache.#2018-12-0814:56mfikes@U09NVRNG2 What is that empty vector doing at the end?#2018-12-0814:57mfikes(Of your ns form.)#2018-12-0814:57ClashTheBunnyIt's an autogenerated file from cljs_test_runner.#2018-12-0814:58ClashTheBunnySo I assume I made either made an egregious error in the clojure side of things or I have a bug in the versions of things I use...#2018-12-0814:59mfikesThat empty vector would normally have the test namespaces listed.#2018-12-0814:59mfikesMine looks like:
(ns cljs-test-runner.gen
       (:require [doo.runner :refer-macros [doo-tests]] [aoc.y2018.d08.mfikes]))
#2018-12-0815:00mfikesPerhaps you deleted the deftest?#2018-12-0815:02mfikesNo... that doesn't provoke that kind of failure.#2018-12-0815:02ClashTheBunnyDamn! I figured it out.#2018-12-0815:03ClashTheBunnyIt's the whole uppercase wasn't allowed in the username and then I ran it again with lowercase.#2018-12-0815:03mfikesAhh. Damn!#2018-12-0815:03ClashTheBunnyThanks for the help!#2018-12-0815:04ClashTheBunnySo script/test-one aoc.y2018.d07.ClashTheBunny works for both cljs and clj, but script/test-one aoc.y2018.d07.clashthebunny only works for clj.#2018-12-0815:04ClashTheBunnyIs this something that would be expected? Should cljs downcase the namespace?#2018-12-0815:05ClashTheBunnyOr should clj not be downcasing it?#2018-12-0815:05mfikesNo... this isn't really a case-specific problem. It happens if you ask it to run tests for which there is no namespace.#2018-12-0815:05mfikesOr maybe you are onto something... hrm.#2018-12-0815:06mfikesI don't know where the problem lies, either Michiel's script, or upstream in one of the test runners. Perhaps file a ticket against advent-of-cljc.#2018-12-0814:51mfikes@pesterhazy Yeah, both bother me a little: loop directly says what you are doing, albeit at a very low level, and it feels like I'm shoehorning reduce by driving it with range and essentially ignoring the range values. What you really want to do in words is "iterate over this n times". I've updated my solution to try to be closer to that: https://github.com/mfikes/advent-of-code/commit/7c60c2b1468e1863a30ba5ec9573f9a12d12736e#2018-12-0814:53pesterhazyyeah iterate seems like the most descriptive choice (I actually considered but discarded it - not sure why)#2018-12-0815:30benoitFor some reasons it always bugs me when the functional style forces me to keep all the state around and change my function signatures.#2018-12-0815:36mfikesYeah, having to thread the remaining sequence through is a bit of a pain for this one.#2018-12-0816:14borkdudedamn, I’m close, but I’m having a stackoverflow. I might have to throw the towel due to time constraints 😢#2018-12-0816:16pesterhazyfunny, I used naive recursion and didn't run into any stack overflows#2018-12-0816:17mfikesYeah, I think the depth of the tree is smaller than typical stack limits.#2018-12-0816:18borkdudeyeah, my solution is probably wrong#2018-12-0816:18borkdudeit works for the test input though#2018-12-0817:03meikemertschI had the same. The test input isn’t stacked deeply. Do you need another test input? 2 1 3 3 0 1 2 0 3 7 8 9 1 1 0 2 6 12 1 4 1 2 1 3 0 1 17 1 4 4 2#2018-12-0817:09meikemertschThat one broke my first implementation as did the real data.#2018-12-0817:28borkdudethanks, I’ll try#2018-12-0817:28meikemertschIf you need the numbers for part 1 or 2, just tell me.#2018-12-0817:29meikemertsch(They’re comfortable enough to do by hand)#2018-12-0817:29borkdudecan you tell me the number for the test input you just gave me?#2018-12-0817:32meikemertschPart 1: 80#2018-12-0817:32meikemertschDo you want Part 2 as well?#2018-12-0817:41borkdudeI get 80 as well#2018-12-0818:34meikemertschsweet#2018-12-0818:34meikemertschbut the real file still doesn’t work? 😮#2018-12-0818:53borkdudeyeah#2018-12-0818:54meikemertschI’m sorry that the additional test input didn’t help 😞#2018-12-0818:55borkdudeno problem#2018-12-0818:55meikemertschHave you checked your iterations?#2018-12-0818:55meikemertschHang on.#2018-12-0818:55meikemertschHave you considered that there is a newline at the end of the test file?#2018-12-0818:56meikemertsch(That one kicked my bucket a few times already and I guess that’s not it. But as a tester I have to ask 😉 )#2018-12-0819:09borkdudegot it now#2018-12-0819:12meikemertsch\o/#2018-12-0819:12meikemertschwhat was it?#2018-12-0816:19pesterhazyAfter a few rounds of yakshaving, I ended up with a script to create the next puzzleNN.clj, usable as clojure -m advent.main: https://github.com/pesterhazy/advent2018/blob/master/src/advent/main.clj#L3#2018-12-0816:20pesterhazyEven better, scripts/dev automatically starts rebel-readline in the latest puzzle namespace#2018-12-0816:20borkdudecool. there’s also a script like this in advent-of-cljc#2018-12-0816:20pesterhazyI think I should stop now 🙂#2018-12-0816:21gklijsIf you want you could also make it to get your problem#2018-12-0816:24mfikesMy input data has a depth of 6#2018-12-0816:32normanAs I was doing this I worried there would be some degenerate case where we’d need to save the score for a node to be efficient, like maybe metadata [1 1 1 …} on 5 or 6 nested nodes…#2018-12-0816:44drowsyI took this into account and multiplied the node-value by it's frequency, and it is quite a bit faster, but as my full runtime is dominated by parsing the tree, it doesn't make much of a difference.#2018-12-0816:51fellshardI've been thinking about this, and I really do think it's possible to do both parts as a single, linear pass that doesn't require recursion...#2018-12-0816:55fellshardYeah, it's basically just turning the recursion stack into an explicit one. But it would certainly make the parts that consume the stream easier to handle, I suspect, by breaking apart the functions that handle different read states (reading header, reading body, reading metadata)#2018-12-0816:58gklijsIt's possible because I'm doing it, but it's much easier with mutable data, but you can have that as well in clojure.#2018-12-0817:11fellshardI still enjoy the lisp-y way of pushing environments onto an explicit stack. That said, I'm probably making life hard for myself 🙂#2018-12-0817:21meikemertschI can see how to do that with part 1 but with part 2 I don’t think I stand a chance to to something without a second pass. Unless I don’t understand what you mean with “second pass” :thinking_face:#2018-12-0818:02fellshardAccumulating your total with a single walk through the tree's data, beginning to end, no back-tracking#2018-12-0818:36meikemertschUrgh. Nope. I couldn’t do that. But I will now attempt to use tree-seq for walking the tree after I built it… I also want to change how I built the tree because it’s s l o w.#2018-12-0819:30potetmI’m almost certain that this will turn into manually managed frames.#2018-12-0818:34fingertoeDo we have a private leaderboard on AoC ?#2018-12-0818:37mfikesYes, the invite code is in the little bit of text next to the pin icon and at https://github.com/adventofcode-clojurians/adventofcode-clojurians#leaderboard#2018-12-0818:52meikemertschThanks. And OMG I am not last#2018-12-0819:46dmitrygusevmy solutions: https://gist.github.com/dmitrygusev/316119976f77368eb9356aa82a0d0b17#2018-12-0819:49dmitrygusevthey’re raw and not refactored after I’ve got correct answer, which should stress the pain I had while solving them 🙂#2018-12-0819:49dmitrygusevI’m new to clojure and lisp#2018-12-0819:53potetmman….#2018-12-0819:53potetmI’ve gone back and forth between reifying data and doing things algorithmically during AoC#2018-12-0820:12meikemertschUhm… I just learned a new word. Reify. I am not sure yet if I understand it completely though I consulted a lexicon#2018-12-0820:30potetmIn this case: There’s an implied data structure in the sequence of numbers for Day 8. Reifying it means to make it into clojure maps, lists, and vectors instead of requiring pre-understood knowledge.#2018-12-0820:32meikemertschStructuring it? Like building a tree?#2018-12-0820:33potetmText is hard 😄#2018-12-0820:34meikemertschYepp. Especially when you’re not a native speaker 😄#2018-12-0820:35potetmIt is a tree, but it’s represented as a list of numbers. Better is to make the relationships explicit.#2018-12-0820:36potetmSo instead of
[2 0 0 3 10 11 12]
Do
{:metadata []
 :children [{:metadata [10 11 12]}]}
#2018-12-0820:36potetmHow do you walk the first? Well… You the developer must be told what each number means.#2018-12-0820:37potetmHow do you walk the second? The relationships are explicit in the structure. It’s immediately obvious.#2018-12-0819:54potetmI feel like the results are all over!#2018-12-0819:54potetmToday’s is so much better if you just build the tree.#2018-12-0819:55potetmwell… I suppose I’m conflating “reify data” with “use sequence fns”#2018-12-0819:55potetmso reifying the data is probably always worth#2018-12-0819:55potetmsequence fns — not so much. Often too slow for the task when it comes to AoC#2018-12-0820:24meikemertsch:shocked_face_with_exploding_head: I just learned that a test that runs in 1s with vectors can run 40s if I use lists. I guess it’s worth deciding the right way!#2018-12-0820:34dmitrygusevI’m still finding it difficult to estimate computational complexity of an algorithm in Clojure 😕#2018-12-0820:34meikemertschI’m far from it, too 😄#2018-12-0820:35meikemertschBut I am learning tons by AoC. First I try to solve it and now I am trying to optimize and to try things out.#2018-12-0820:37potetm@U04V437EA Do you have an example?#2018-12-0820:38dmitrygusevpick any from the gist I’ve posted, i.e. day1 pt 2#2018-12-0820:39dmitrygusevthe problem is there are plenty of built-in functions whose complexity is unknown#2018-12-0820:39meikemertschI have four Revisions in this gist and especially the difference between Rev 3 and Rev 4 are mind blowing https://gist.github.com/MeikeMertsch/f1f3a1bfc157c3ed3a6cfcb1dec0ff57#2018-12-0820:40potetm@U04V437EA I’m not sure what you mean by that statement. The complexity is pretty well stated for most operations on most structures.#2018-12-0820:41potetmBut it is sometimes polymorphic. So you must be aware of the type of the underlying structure.#2018-12-0820:44potetm@U0A7TVBLN Is there a particular change you’re interested in hearing about. Instead of “this whole diff,” it’s easier to talk about, “This change from concat to conj” or whatever.#2018-12-0820:44dmitrygusev
(map-invert
          (frequencies
            (flatten
              (vals
                ids-by-minutes))))
i.e. how can you estimate complexity for the above?
#2018-12-0820:45potetmO(n) (3*n I think)#2018-12-0820:46potetmsry 2*n#2018-12-0820:46potetmbut O(n) anyways#2018-12-0820:47potetmflatten is lazy O(n), frequencies is eager O(n), map-invert is eager O(n). The lazy will get rolled into the first eager O(n) so it doesn’t contribute.#2018-12-0820:47meikemertschLanguage is hard… what’s “O(n)“?#2018-12-0820:48meikemertschoh. Just check the diff from rev 3 to 4. it’s just two lines. And really just a conversion#2018-12-0820:48potetmBut it’s obviously not polynomial or more. It’s going over some data a few times.#2018-12-0820:49dmitrygusevyeah, I meant the C in front of O(n) is difficult to estimate#2018-12-0820:49potetm@U0A7TVBLN The last revision changes behavior. It’s not an isolated optimization.#2018-12-0820:49dmitrygusevknowing something is O(n) helps, for sure#2018-12-0820:50potetmRight, gotcha. So is it the laziness that’s difficult?#2018-12-0820:50meikemertschI noticed. 39 seconds worth of a behavioral change#2018-12-0820:50dmitrygusevy#2018-12-0820:50potetmYeah, that takes a while to get used too, I agree.#2018-12-0820:51potetm@U0A7TVBLN One of those should return an incorrect result, I would presume.#2018-12-0820:51potetmSo it might be faster because you’ve dropped some data. idk the context.#2018-12-0820:52meikemertschno. Both rune fine. Before trying that out I changed all peeks, pops and conjs, so they would work the same for vecs and lists#2018-12-0820:53meikemertschthat’s why the vector version is so slow already. With peeks, pops, and conjs I gain almost half a second speed (see version 2)#2018-12-0820:53potetmah I’m sorry, I misread this#2018-12-0820:54meikemertschObviously I access data WAY more often from the end than from the front. And lists aren’t built for that, right??#2018-12-0820:54potetmOkay, so you’re running into the same lazy evaluation issues @U04V437EA was talking about#2018-12-0820:55potetmcalling vec goes over all the data immediately#2018-12-0820:55potetmso you’re potentially adding a lot of extra processing#2018-12-0820:55potetmdepending on the length of the list#2018-12-0820:56meikemertschusing vec made me 39seconds (!) faster (:shocked_face_with_exploding_head: )#2018-12-0820:57dmitrygusevvec vs list is like array with direct access vs linked list, get element from vec is O(1), from list it’s O(n)#2018-12-0820:57potetmSo I think I’m misunderstanding the question 🙂 It looks like you took out calls to vec (I presume to make it faster)#2018-12-0820:58potetmBut, in general, there’s a lot going on in the solution, so it’s difficult to characterize where it’s spending its time.#2018-12-0820:59meikemertschhaha. Sorry for the confusion. My tests ran 500msec and I wanted them faster so I checked my collection operations and spotted that I did a whole lot of conversions to vectors. So I refactored them out. With the result that everything was s l o w e r#2018-12-0821:00potetm😄 😄 😄#2018-12-0821:00potetmso let’s talk about butlast#2018-12-0821:00potetmthe docstring on it directly says it’s a linear scan#2018-12-0821:01potetmpop is constant time#2018-12-0821:01potetmI’m not certain that’s your issue, but that’s a common mistake#2018-12-0821:06meikemertschI am quite impressed with what you can read out of those docs. Most of the internals are just “blahb” to me#2018-12-0821:07meikemertschI can read the words but I don’t understand what they mean.#2018-12-0820:37benoitThere are some information about the complexity of the Clojure data structures here: https://clojure.org/reference/data_structures#Collections#2018-12-0820:40dmitrygusev> their specific behavior is slightly different for different types of collections this ^#2018-12-0820:48mfikesOnce you fundamentally get your algorithm sorted, you can often tweak things to ensure optimizations like chunked sequences or directly reducible collections help.#2018-12-0821:10meikemertschAt least I figured out the tree-seq again. I am fairly happy with that#2018-12-0822:09borkdudemy day 8 https://github.com/borkdude/advent-of-cljc/blob/master/src/aoc/y2018/d08/borkdude.cljc 😅#2018-12-0822:16mfikesNice. Very similar to Paulus' and mine. 🙂#2018-12-0822:18borkdudeit took me too long…#2018-12-0822:19mfikesDid you start with the tree approach? Or something optimized for part 1 that was then converted to tree?#2018-12-0822:21borkdudeno, I didn’t start with the tree#2018-12-0822:21borkdudeI had another solution that only gave me the meta values#2018-12-0822:22mfikesYeah, I suspect if you go down that path, then part 2 becomes exceedingly difficult.#2018-12-0822:23borkdudeCLJ:
Testing aoc.y2018.d08.borkdude
part-2 took 7.98 msecs
part-1 took 2.81 msecs

Testing aoc.y2018.d08.iamdrowsy
part-2 took 10.25 msecs
part-1 took 14.21 msecs

Testing aoc.y2018.d08.mfikes
part-2 took 18.30 msecs
part-1 took 21.29 msecs
CLJS:
Testing aoc.y2018.d08.borkdude
part-1 took 20.00 msecs
part-2 took 2.00 msecs

Testing aoc.y2018.d08.iamdrowsy
part-1 took 58.00 msecs
part-2 took 38.00 msecs

Testing aoc.y2018.d08.mfikes
part-1 took 120.00 msecs
part-2 took 76.00 msecs
#2018-12-0822:23Average-userday 8: https://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day08.clj#2018-12-0822:24mfikesNice, a rare appearance of trampoline 🙂#2018-12-0822:26Average-userI'm not even sure if is correctly placed#2018-12-0822:45taylorI don’t think it’s doing anything, because parse-data never returns a function#2018-12-0822:25borkdudeI noticed that too 🙂#2018-12-0822:25mfikesLots of solutions involving the expression
[{:children children, :metadata metadata} the-rest-of-the-seq]
🙂
#2018-12-0822:26potetmmine too#2018-12-0822:26mfikesIf we had a state monad that we were all used to using maybe we could avoid that. Othewise this aspect was troublesome.#2018-12-0822:27borkdudeI had [n-children n-meta & nums]#2018-12-0822:27magic_bloatI used an integer position instead of the-rest-of-the-seq, and left the input vector untouched.#2018-12-0822:27potetmyou have an outline of how state monad would have helped? i dont see it#2018-12-0822:27magic_bloathttps://github.com/bloat/aoc2018/blob/master/src/net/slothrop/aoc2018/day8.clj#2018-12-0822:27mfikes@borkdude Yeah, you had
[{:meta (vec meta)
          :children children} rest]
#2018-12-0822:28potetmjust a poorly formatted tree afaict#2018-12-0822:28borkdudeI could probably optimize that by not going through a seq at all, but staying in a vec#2018-12-0822:28Average-userI had no time yesterday to read, but how did you approach part2 of day 7?#2018-12-0822:28mfikesThe way I see it, you have this extra appendage you have to thread through all of your calls, which is state you need to pass around. Perhaps a monad of some sort would help hide a bit of that complexity.#2018-12-0822:29borkdudethat’s what the state monad is for yes#2018-12-0822:29potetmuh, I could def be wrong, I don’t think it helps in recursive situations#2018-12-0822:30mfikesOtherwise lots of [what-i-want extra-crap] destructuring, along with passing extra-crap around.#2018-12-0822:30Average-userhttps://github.com/glguy/advent2018/blob/master/execs/Day08.hs (solution with State Monad)#2018-12-0822:30mfikesYeah, I don't have enough experience with state monads to know if they work in recursive situations. Well, I have nearly zero experience.#2018-12-0822:31borkdudeI worked through the http://HaskellBook.com this year. I have a little bit of experience with the State monad, and StateT monad transformer.. but I’m not using that a lot so just a matter of time before I forget again#2018-12-0822:34potetmI saw that. And I appreciated it while it lasted 😛#2018-12-0822:35borkdudeyou saw what?#2018-12-0822:35potetmyour original posting re: haskell#2018-12-0822:36potetmjust before you deleted it#2018-12-0822:36borkdudeoh yeah 😉#2018-12-0822:32potetmwell aren’t we just a bunch of dynalang apes 😄 troll#2018-12-0822:34potetmlol#2018-12-0822:34borkdudeHaskell: banging on the type system until it works. Clojure: banging on the REPL until it works.#2018-12-0822:36pesterhazydoes anyone know any other interesting users coming from other language to follow? The postgres guy is super interesting https://github.com/xocolatl/advent-of-code/tree/master/2018#2018-12-0822:38Average-userI intended to respond to this#2018-12-0822:36pesterhazy(this was mentioned here a few days ago, thanks for that)#2018-12-0822:37Average-userI did 2017 in Prolog https://github.com/Average-user/adventofcode-pl-2017#2018-12-0822:36borkdudeno problem 😉
#2018-12-0822:37Average-userI did 2017 in Prolog https://github.com/Average-user/adventofcode-pl-2017#2018-12-0822:37borkdudeI was on a private leaderboard with him last year and one PureScript user (so three different langs). it was fun to see the different solutions#2018-12-0822:38Average-userI intended to respond to this#2018-12-0822:38borkdudeoh wow, impressive @lucaspolymeris#2018-12-0822:39pesterhazychapeau @lucaspolymeris!#2018-12-0822:40Average-userThere are some missing stuff, and others very slow . So if you know Prolog glad to accept PRs#2018-12-0822:40pesterhazyThis list looks great: https://github.com/Bogdanp/awesome-advent-of-code#2018-12-0822:46mfikesThese Scala solutions look more compact that I would have expected. (Perhaps the author is golfing or that's fairly idiomatic?) https://github.com/FlorianCassayre/AdventOfCode-2018#2018-12-0822:48pesterhazyYes that looks pretty good, better than most of the haskell/ocaml solution I've looked at#2018-12-0822:48mfikesYeah, I'm leaning towards the idea that the author is pretty good.#2018-12-0822:50taylorI think I’ve convinced myself that solving day 8 w/o recursion would require some gnarly stack juggling#2018-12-0822:53potetmyes#2018-12-0822:54potetmyou’d have to basically re-implement call stack frames 😄#2018-12-0822:54potetm“here’s all the state we had at this frame, and where we left off when we were here”#2018-12-0822:55potetm(Just for part 2. I did stack-based in part 1 for funsies.)#2018-12-0822:57taylorI feel like day 8 is foreshadowing a problem where direct recursion won’t be feasible 😰#2018-12-0823:01borkdudelast year (2017) I saw someone write here: in 2016 the puzzles were harder, now they’re sometimes too easy. I haven’t heard that this year yet?#2018-12-0823:02taylorI feel like first week of 2018 is slightly more challenging than first week of 2017#2018-12-0823:02Average-userI think untill now, hardness has been equivalent to 2017#2018-12-0823:03taylorby 2030 AoC will have exhausted every problem but P=NP#2018-12-0823:11pesterhazyNice F# solution - also has to thread through the "remainingTree"#2018-12-0823:11pesterhazyhttps://github.com/CameronAavik/AdventOfCode/blob/master/Program.fs#L762#2018-12-0823:12gklijsProbably once you've done them for one year it also becomes easier? It's a pretty specific kind of problems.#2018-12-0823:13mfikesYeah it is interesting;
let meta, remainingTree = List.splitAt metadata tree'
and
val (metadata, other) = right.splitAt(nMetadata)
and
(let [[meta rest] (split-at n-meta nums)]
all look very similar
#2018-12-0823:15mfikes(We are all roughly employing the same algorithm, even using the language's built-in "split at" functions.) That's F#, Scala, Clojure#2018-12-0823:19taylorhere’s a day 8 stack-based solution https://www.reddit.com/r/adventofcode/comments/a47ubw/2018_day_8_solutions/ebc99t8/#2018-12-0904:58taylorI adapted this to Clojure and built the tree using a zipper https://github.com/taylorwood/advent-of-code/commit/3479b928e16874fdda7469ed58e4eb1648671736#2018-12-0823:23mfikesI think there's something about this particular problem that forces you down a similar path (whereas other problems admit a richer variety of approaches.) I found James Henderson's bit of code here https://github.com/jarohen/advent-of-code/blob/master/2018/src/aoc2018/day8.clj#L9-L20 way too similar to mine here https://github.com/mfikes/advent-of-code/blob/b89aff099c2dd42928e038f3d70344b685f7d889/src/advent_2018/day_08.cljc#L9-L18#2018-12-0823:26borkdudehe used reduce where you used iterate right?#2018-12-0823:26mfikesI only later changed mine to iterate after the conversation with Paulus #2018-12-0823:27mfikesreduce over range was my first approach#2018-12-0823:29borkdudeboth make sense to me. reduce with a counter could also have been used, but that starts to look like a normal loop#2018-12-0823:32mfikesI think I learned the iterate / nth pattern from Bruce from last year#2018-12-0904:58taylorI adapted this to Clojure and built the tree using a zipper https://github.com/taylorwood/advent-of-code/commit/3479b928e16874fdda7469ed58e4eb1648671736#2018-12-0901:46baritonehandsI ended up using loop, but had to use trampoline due to stack overflows: https://github.com/baritonehands/advent-of-code-2018/blob/master/src/aoc/dec8.clj#2018-12-0902:19theeternalpulse02#2018-12-0902:33mfikesJust don't try 08; that will cause an issue.#2018-12-0906:19taylorperformance matters now #2018-12-0907:17baritonehandsYeah, my solution took 5 min to run, so 100x would be 8h#2018-12-0907:23taylor100x is ~5h for me#2018-12-0907:24taylormust be missing some intuition, there are people that solved both parts in less than 10m :thinking_face:#2018-12-0907:25taylorprobably just gonna go to sleep and let it run haha#2018-12-0907:29meikemertschDoes the given test case “13 players; last marble is worth 7999 points: high score is 146373” run for you guys? That’s the only one that fails for me 😮#2018-12-0907:29normanI often have the experience of writing a slow solution and while it is running I write a faster solution that finishes before the first one did. This time while the second solution was running, I wrote a third solution that finishes even faster. And it’s a good thing too, because I realized, 20 minutes into running the second solution, that I used the wrong number as an input#2018-12-0907:33taylorare you using persistent vectors?#2018-12-0907:35normanNo - I wrote a double-linked circular list out of volatiles. I feel dirty#2018-12-0907:36taylornice#2018-12-0907:40normanfor part1 I used a naive vector approach. That was too slow , so then I used an ArrayList. That was much much faster, but still slow. So then I hacked together the circular list real fast. I can’t think of any way to do this efficienttly with a persistent data structure.#2018-12-0916:00mfikesThis is what actually happened with one of the Voyager spacecraft, right? (They launched it and years later developed better data compression algorithms, which let the images be sent back in reasonable time even though there was a comms channel slowdown due to a defective antenna or such.)#2018-12-0907:31norman@meikemertsch advent2018.day9> (time (part2c 13 7999)) “Elapsed time: 30.633133 msecs” 146373#2018-12-0907:32meikemertschfudge 🙈 now I have no clue why that one doesn’t work but all others do#2018-12-0907:47normanDo you have an easy way to print out the removed values for that case?#2018-12-0907:48normanhttps://pastebin.com/CvYTZnD9 is mine if you get stuck and want to compare later#2018-12-0908:39meikemertschI think I know why. Funnily enough my solution still worked on the input data :shocked_face_with_exploding_head:#2018-12-0908:46meikemertschYeah. I was wrong in calculating the new positions. I didn’t consider an important edge case#2018-12-0907:32taylorI got the same answer in 1199ms#2018-12-0907:33meikemertsch1.6 secs for running all five cases :thinking_face:#2018-12-0907:37Average-userI'm using clojure.data.finger-tree but still takes 3.4m for part1#2018-12-0907:39taylorpart 1 is now 83s for me using vanilla vectors#2018-12-0907:39Average-useri was mistaken:
(time (part-1))
"Elapsed time: 924.570809 msecs"
388024
#2018-12-0907:40Average-userforgot to change reduce conj by finget-trees/ft-concat#2018-12-0907:41Average-user
(time (part-2))
"Elapsed time: 82914.062071 msecs"
3180929875
#2018-12-0907:41Average-userminute and some for part-2#2018-12-0907:49Average-userhttps://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day09.clj#2018-12-0907:58fellshardHmm, I was wondering if a tree would be a better structure for arbitrary insertion / deletion. I'd heard good things about finger trees, it seems I should pay more attention to them.#2018-12-0908:00fellshardMy attempt to use a straight Java Linked List did not fare well. In the end, I hopped over to straight Java and got pretty much instantaneous results. So I need to figure out where on earth I'm going wrong to get such poor performance. I think I cut out a great deal of potential reflection slowdown, so not sure what's up.#2018-12-0908:04heliosmy solution to part 1 is so slow 😢#2018-12-0908:04helios@taylor in the same boat as you i see 😄#2018-12-0908:05baritonehandsTransients and subvec reduced my part1 by 10x#2018-12-0908:37helios@baritonehands yeah, good advice. I got to a speedup but my code still takes ~1 minute to run (70k marbles, 400 players)#2018-12-0908:37helios@baritonehands what kind of execution time you had for part 1 ?#2018-12-0916:18baritonehandsOriginally 300+ seconds, 30+ after#2018-12-0908:40meikemertsch718902 msecs for part one 😂 I have plenty of ideas how to make it better though#2018-12-0908:41meikemertschOMG the start of the next part is “Amused by the speed of your answer” 😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:😂 :rolling_on_the_floor_laughing:#2018-12-0909:59gklijsEven for java there was no collection in the standard I could found for solving the second one.#2018-12-0910:33namenuI used ArrayDeque both O(1) for head and tail manipulation.#2018-12-0910:33namenujava.util.ArrayDeque 🙂#2018-12-0918:51pesterhazyThanks for mentioning Deque, wasn't aware of that. Did you end up using a Deque? Isn't it necessary to insert marbles at arbitrary positions, not just at head or tail?#2018-12-0911:15ihabuneki knew using lists for part 1 was silly but did not expect "Elapsed time: 527892.857699 msecs"#2018-12-0912:07plexusI ended up writing my own circular linked list implementation (after trying with regular lists and being waaaay too slow)#2018-12-0912:08plexuswith that and after fixing some reflection call sites it's a comfortable 120ms for part 1 and 16sec for part 2#2018-12-0912:09plexuscan't really do a doubly linked or circularly linked list that is functional though AFAIK so it's not a persistent data structure#2018-12-0912:11plexushttps://github.com/plexus/advent-of-code/blob/master/src/advent2018/day9.clj#2018-12-0918:54pesterhazyvery cool#2018-12-0912:14borkdudeI get a boxed math warning on (- current-idx 7) where current-idx is a loop variable starting with 0. but when I place a type hint it says: can’t type hint primitive local. what does it want…#2018-12-0912:25plexusborkdude try [current-idx (long ...)] instead of [^long current-idx ...]#2018-12-0912:25borkdudesame thing: https://www.dropbox.com/s/i49vgj4n8aoazyx/Screenshot%202018-12-09%2013.25.41.png?dl=0#2018-12-0912:26plexusstrange... from https://clojure.org/reference/java_interop#typehints#2018-12-0912:26plexus> (let [foo (int bar)] …​) is the correct way to get a primitive local. Do not use ^Integer etc.#2018-12-0912:27plexusMaybe put a (let [current-idx (long current-idx)] inside the loop?#2018-12-0912:28borkdudethat works. strange that I need this?#2018-12-0912:28plexusIt kind of makes sense if you think of it, if you put it in the loop [] it knows it will be a long in the first iteration, but you can recur something else later#2018-12-0912:30borkdudeyou can, but like with function arguments, the type hint is an invariant?#2018-12-0912:30plexusI guess you'll have to ask Rich... or dive into the compiler source 🙂#2018-12-0912:31plexusdoes that ^long (mod marble 23) make a difference? I thought type hints only worked on symbols...#2018-12-0912:32plexusthis type hinting stuff remains a black art to me... adding tags left and right until the warnings go away 🙂#2018-12-0912:32borkdudeyes#2018-12-0912:32borkdudesame here. I usually only need this in advent of code..#2018-12-0912:33plexusI recently learned tags can also be strings, so you can do stuff like this ^"[Ljava.lang.String;"#2018-12-0912:33plexusi.e. "array of string"#2018-12-0912:38borkdudenow it starts to make sense:
(defn foo []
  (loop [current-idx (long 0)]
    (- current-idx 7)
    #_(recur nil)))
you don’t get the boxed math warning if you remove the recur, so it has to do with that
#2018-12-0912:54meikemertschok, down to 45 secs for part one and out of ideas :thinking_face:#2018-12-0913:12drowsyI trying to switch to java.util.LinkedList but I'm not able to call the remove(int index) method. It keeps calling the remove(Object o) method. Any ideas?#2018-12-0918:32fellshardThis fixed itself when I type-hinted the list as a ^java.util.LinkedList and the remove method argument as an int.#2018-12-0913:16borkdudeMy hunch is when it says: now do it x100 and it already takes long, that there might be some mathematical regularity you can take advantage of#2018-12-0913:18genmeblogjust found out that using mapv instead of map on long lists give 6x speed gain 😕 (still optimizing day 6 and made 550ms instead of 3500ms)#2018-12-0913:20athosI implemented a doubly circularly linked list, perhaps almost same as @plexus's and it takes ~5sec for part 2 https://github.com/athos/advent-of-code-2018/blob/master/src/advent_of_code_2018/day09.clj#2018-12-0913:27benoitMy solution for Day 9: https://github.com/benfle/advent-of-code-2018/blob/master/day9.clj#2018-12-0913:29benoitUsing zippers. Ended up at 17s for part 2.#2018-12-0913:34borkdudeinteresting to see that zippers have similar performance to the custom data structure of plexus#2018-12-0915:31plexusTo be fair my solution is completely unoptimized outside of the custom data structure.#2018-12-0913:48athosMy code got 1.7x faster by making it a little bit more branch prediction friendly 🙂#2018-12-0914:32rmprescottI really like @mfikes day 8 solution -- using the argument list as a stack in a shift reduce parser. A new trick to add to the bag-o-tricks.#2018-12-0914:33drowsystrange, when running in the repl with time my part 2 now takes about 9 sec, running script/test-one it's about 23 sec.#2018-12-0914:38taylorYeah I never would’ve thought to try zippers even though I try them in more unusual situations. Very cool#2018-12-0914:39borkdude@drowsy maybe because your REPL has a warmed up JVM? wild guess. what if you run the code multiple times in the test wrapped in a time?#2018-12-0914:48drowsyadding 4 (time (solve-2)) to the test brings the second run down a bit (about 20sec), but than it improves no further.#2018-12-0914:49borkdudewhat are you using to run the REPL, tools.deps or lein?#2018-12-0914:49drowsytools.deps#2018-12-0914:50borkdudewhat if you use clojure.test/deftest with your own time call around the code?#2018-12-0914:50drowsybut actually cursive, so I'm not sure how the repl is started exaclty#2018-12-0914:51drowsy(time (part-2)) is fast in the REPL as well#2018-12-0914:52borkdudeI mean use clojure.test/deftest instead of aoc.utils/deftest to exclude the possibility that it is my test macro#2018-12-0914:52borkdudedid you turn on unchecked math or anything?#2018-12-0914:52drowsyyeah I did#2018-12-0914:53borkdudemaybe you didn’t turn it on in the tests#2018-12-0914:53drowsywell, it's in top of the file#2018-12-0914:54borkdudecan you try with binding around the test body?#2018-12-0914:59drowsySo it's not your macro and binding doesn't help. I will have a look at the flight-recorder#2018-12-0915:04drowsyoh wait.... it's not even the same jvm. The REPL is running on a oracle jdk 8 on windows while the test script is an open jdk 10 on the linux subsystem.#2018-12-0914:39taylorhttps://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/9.clj here’s my day 9#2018-12-0914:45taylorA little bummed the last few days problems don’t lend themselves to visualization #2018-12-0914:46taylorGuess I could visualize a much smaller game of elf marbles #2018-12-0914:47borkdudeI have the outcome for part 1 but didn’t look at the data. Why doesn’t it lend itself to visualization?#2018-12-0914:50taylorI was just thinking there are so many players and marbles it’d just be tiny pixels to look at#2018-12-0914:53ihabuneki'm playing with java.util.LinkedList which has remove(int) and remove(object) overloaded methods it's always invoking the second, but i want the first, what can i do?#2018-12-0914:53ihabunektrying (.remove lst 1) to remove element at index 1#2018-12-0914:54ihabunekbut end up removing element with value 1 from the list, if it exists#2018-12-0914:55ihabunekdocs are here https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html#2018-12-0914:55drowsyI asked this in #clojure and it seems you have to typehint the list itself in the call.#2018-12-0914:56ihabunekcool, that works#2018-12-0914:56ihabunekweird solution though 🙂#2018-12-0914:57ihabunekand i need to typehint the index#2018-12-0914:58taylorI saw a really fast Clojure solution using linked list#2018-12-0914:59ihabuneki wanted to make my own list but don't have much time now so doing this#2018-12-0915:32mattlyWow, I feel happy that I reached for a vector zipper first. I figured it’d be slower than another solution but more convenient. Little did I know...#2018-12-0915:37ihabunekzippers! i forgot about those.#2018-12-0915:37ihabunekdamn, now i have ideas for v4 and v5 of todays task 😄#2018-12-0915:42drowsyI ended up just using two lists and no fancy mutable stuff. https://github.com/IamDrowsy/advent-of-cljc/blob/master/src/aoc/y2018/d09/iamdrowsy.cljc#2018-12-0915:43ihabunek😮#2018-12-0915:43ihabunekthat's just like my deque idea, but with lists#2018-12-0915:43ihabunekhow long does it run for?#2018-12-0915:44drowsythis is somewhat strange 🙂 no an openjdk 10 it's around 18 secs, in my repl running a oracle jvm 8 it's about 8 secs. So maybe it's a bit stressfull for the GC?#2018-12-0915:46drowsyoh wow. On @borkdude circleCI the clojurescript version evens kills the vm because it's out of heap... maybe I need to do some tweaks#2018-12-0915:54mfikesDay 9: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_09.cljc#2018-12-0916:01taylorWow we got the exact same puzzle inputs#2018-12-0915:55ihabuneksorted-map works quickly?#2018-12-0915:57mfikesFor part 1, it takes 566 ms, for part 2 maybe a minute or so#2018-12-0915:57mfikesPart 2 is 90 seconds#2018-12-0916:08namenuFingertree(immutable) impl performs pretty good compared to java.util.ArrayDeque. Impressive! https://gist.github.com/namenu/402b46c61e385c801cdb4c150c3e4cd6#2018-12-0916:18benoitI got to 7s for part two with custom data structure: https://github.com/benfle/advent-of-code-2018/blob/master/day9_alt.clj#2018-12-0916:50pesterhazyI'm finding Day 9 very hard - not to get the right result but to get Part 2 to complete in time. My algorithm's time complexity is not good enough#2018-12-0916:52pesterhazywhat am I missing ?!#2018-12-0916:53mfikesOops, I had written mine in ClojureScript, and while it was working in Clojure, it was using rationals. Switching to doubles dropped part two to 30 seconds.#2018-12-0916:54pesterhazyI have two impls, one based on PersistentVector and one based on sorted-map: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle09.clj#L7#2018-12-0916:54pesterhazysorted-map is slightly faster but still takes 100+ s for Part 1 - I can't even dream of trying Part 2#2018-12-0916:55mfikes@pesterhazy Mine is sorted map as well; taking a look at yours#2018-12-0916:55pesterhazydo you have a gentle hint for me @mfikes?#2018-12-0916:57mfikes@pesterhazy I have to run out for a while, but quickly scanning through your solution, I don't see use of subseq. I was using that to find nearby indices (and rsubseq to find one 7 back)#2018-12-0916:58gklijslol, my second one now runs faster then the first one#2018-12-0916:59pesterhazy@mfikes d'oh!#2018-12-0916:59borkdudemy naive pure clojure vector based solutions runs in 85 seconds for part 1. I tried https://github.com/clojure/core.rrb-vector but got an index out of bounds exception with it#2018-12-0917:01mfikesThe main idea of the sorted-map approach is: Use it as a poor man's mutable linked list. To insert and remove you assoc and dissoc, and to navigate forward and back, subseq and rsubseq. And Paulus and I have the same indexing strategy: Use doubles as your index and use midpoint to insert a marble between.#2018-12-0917:04gklijshttps://github.com/gklijs/advent_of_code_2018/blob/master/Gerard/src/main/java/com/gklijs/adventofcode/day9/MarbleGame.java#2018-12-0917:17mfikesThis was the first problem where I had to resort to transducers to bypass ClojureScript's head holding / lack of locals clearing.#2018-12-0917:17mfikes(There were several of those last year.)#2018-12-0917:18mfikesIf you're curious, it is specifically this use of nth' here https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_09.cljc#L41 Otherwise regular nth holds head on the iterated sequence.#2018-12-0918:27pesterhazyOk here's my complete Day 09: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle09.clj#L38#2018-12-0918:28pesterhazysolution-2 takes 37s#2018-12-0918:29pesterhazya far from the estimated 12h+ of my first PersistentVector approach#2018-12-0918:30pesterhazy@mfikes thanks so much for getting me unstuck by mentioning subseq and especially rsubseq — these are functions I genuinely didn't know about (well I heard them mentioned here a few days ago but promptly forgot)#2018-12-0918:31pesterhazyusing doubles as indices works well but honestly we were lucky that we didn't reach the point where floating-point precision prevents squeezing in new positions#2018-12-0918:43pesterhazyI'm very curious about what datastructures other JVm based solutions use#2018-12-0918:45baritonehandsGot 58ms and 6864ms with my own transient map based linked list:
defn ll-init [n]
  (let [node (transient {:value n})]
    (assoc! node :next node)
    (assoc! node :prev node)
    node))

(defn ll-insert [{:keys [next] :as root} n]
  (let [node (transient {:value n})]
    (assoc! node :next next :prev root)
    (assoc! next :prev node)
    (assoc! root :next node)
    node))

(defn ll-remove [{:keys [next prev value] :as node}]
  (assoc! next :prev prev)
  (assoc! prev :next next)
  [next (:value node)])

(defn ll-nth [node idx]
  (nth (iterate (if (neg? idx) :prev :next) node) (Math/abs (int idx))))
#2018-12-0918:47pesterhazyHm, aren't you supposed to close transients by calling persistent!?#2018-12-0918:54baritonehandsIs that always necessary? They won’t just get cleaned up when I forget the reference?#2018-12-0918:54borkdudeOnly if you want a persistent I guess#2018-12-0918:55pesterhazyThe docs say, > Note in particular that transients are not designed to be bashed in-place. You must capture and use the return value in the next call.#2018-12-0918:56baritonehandsI store the return value in a seq#2018-12-0918:56baritonehandshttps://github.com/baritonehands/advent-of-code-2018/blob/master/src/aoc/dec9.clj#2018-12-0918:58pesterhazyI can't believe how simple day9 can be with a good Deque implementation: https://www.reddit.com/r/adventofcode/comments/a4i97s/2018_day_9_solutions/ebepyc7/#2018-12-0919:22baritonehandsTransients still worked for me, maybe because they were all of size 3? I would assume they change reference when the implementation changes at a certain size boundary#2018-12-0919:27pesterhazyReading up on deque, you can write rotate easily by popping on one side and pushing on the other - that should work with Java's ArrayDeque as well#2018-12-0919:29pesterhazyI wonder if a PersistentDeque would be feasible?#2018-12-0919:32mishaI promise I won't read spoilers#2018-12-0919:33Average-user@pesterhazy I do something like that. The rotate is implemented with ft-split-at from clojure.data.finger-trees#2018-12-0919:33Average-userhttps://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day09.clj#2018-12-0919:34pesterhazypjstadig has a persistent Deque implementation: https://github.com/pjstadig/deque-clojure/blob/master/src/name/stadig/deque/protocol.clj#L16#2018-12-0919:35pesterhazy@lucaspolymeris nice - how long does it take to answer part 2?#2018-12-0919:36Average-userNot very fast 1m aprox#2018-12-0919:37pesterhazythat's still pretty good for a pure solution!#2018-12-0919:37pesterhazymy sorted-set approach takes ~30s#2018-12-0919:38Average-userDo have the link? Is it pure?#2018-12-0919:53pesterhazyYeah it's pure https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle09.clj#L78#2018-12-0920:03mfikesMine is essentially the same and is also ~30s#2018-12-0919:36benoit@pesterhazy Thanks for the link to dequeue. I forgot about this one. That seems like the right data structure for the problem, yes.#2018-12-0919:37Average-userWhat would be the gain against finger-tree?#2018-12-0919:39benoitNo idea. I never took the time to look at finger trees. Maybe I should. But for this problem deque's complexity properties seem appropriate.#2018-12-0919:41benoitAnd more importantly it makes the solution pretty clear. I tried to something similar w/ my solution but zippers require a rewinding that is not very elegant. And then my custom data structure is pretty specific to the problem so not great either 🙂#2018-12-0919:42Average-userR u going to implement the dequeue one? I'm interested to compare times with finger trees#2018-12-0919:42Average-userSo if u do, could you please share it?#2018-12-0920:02benoitUsing the java.util.LinkedList which implements java.util.Deque I'm getting between 2 and 3 seconds.#2018-12-0920:06Average-userBut those r not pure i suppose#2018-12-0920:07gklijsI got 33ms, after a lot of iterations, with Java#2018-12-0920:16benoit@gklijs For part 2?#2018-12-0920:20gklijsYes, the first one runs almost 100 times faster.#2018-12-0920:31misha33ms part 2? you guys are killing me harold#2018-12-0920:44Average-userWhich has been your favourite day so far?#2018-12-0920:45meikemertschDay 7! It left me singing and dancing#2018-12-0921:52potetmToday’s. I built a data structure just for it I was proud of 😄#2018-12-0920:55benoit@gklijs The "history" trick is neat.#2018-12-0920:58benoitWith Java data structures (Deque and long array to keep scores). I'm done with this problem 🙂 https://github.com/benfle/advent-of-code-2018/blob/master/day9_alt2.clj#2018-12-0921:47Stephen Lesterm#2018-12-0921:56pesterhazyMy conclusions after (a very long) day 09: https://github.com/pesterhazy/advent2018/blob/master/journal.md#day-09#2018-12-0921:57pesterhazy@gklijs is your solution available online?#2018-12-0921:57potetmlots of solutions here#2018-12-0921:57potetmI made a mutable doubly-linked circular list#2018-12-0922:01potetmlooks pretty much like the python solution#2018-12-0922:01potetmthat @pesterhazy posted#2018-12-0922:03pesterhazyNice solution in Java: https://www.reddit.com/r/adventofcode/comments/a4i97s/2018_day_9_solutions/ebetdc5/#2018-12-0922:04potetmIf I only knew the word “deque”#2018-12-0922:04potetmoh well, had fun making my own 🙂#2018-12-0922:12potetmI’m at 20ms for p1, 9s for p2#2018-12-0922:12potetmlots of obvious waste to trim#2018-12-0922:17benoit@potetm same here: zip -> own deque -> java deque 🙂#2018-12-0922:17potetmpure clojure using deftype w/ mutable fields#2018-12-0922:17potetmyeah I bet java deque is sig better 🙂#2018-12-0922:18potetmyou see a sig timing dif @me1740?#2018-12-0922:18benoit16 s -> 7 s -> 1s roughly#2018-12-0922:19potetm😕 yeah I guess java deque is next for me#2018-12-0922:20benoitInterestingly the timing w/ Java data structure seem to vary much more than the Clojure data structures. I'm not familiar enough w/ the internals of either to explain why.#2018-12-0922:21potetmmine varies quite a bit actually#2018-12-0922:21potetmno idea why#2018-12-0922:21potetmas short as 2s, as long as 10#2018-12-0922:21potetmGC I presume#2018-12-0922:21potetmvery odd#2018-12-0922:22benoitYeah the difference seems big#2018-12-0922:23potetm
"Elapsed time: 8461.775695 msecs"
=> [344 3038972494]
"Elapsed time: 11364.651846 msecs"
=> [344 3038972494]
"Elapsed time: 2761.024937 msecs"
=> [344 3038972494]
"Elapsed time: 9324.289621 msecs"
=> [344 3038972494]
"Elapsed time: 3111.038354 msecs"
=> [344 3038972494]
#2018-12-0922:23potetm:man-shrugging:#2018-12-0922:23pesterhazyThis one takes 2.3s for p2: https://www.reddit.com/r/adventofcode/comments/a4i97s/2018_day_9_solutions/ebetdc5/#2018-12-0922:23potetmyeah but they cheated#2018-12-0922:23potetmperf enhancing drugs#2018-12-0922:23potetmtroll#2018-12-0922:24potetmNew talk idea: “Mutation is a performance enhancing drug.”#2018-12-0922:37ihabuneklol, i did that same thing in clojure https://git.sr.ht/%7Eihabunek/aoc2018/tree/master/clojure/src/aoc2018/day09.clj#2018-12-0922:38ihabunekmy excuse: i was going for a functional solution but it was too slow and i wanted to have a solution today 😄#2018-12-0922:52mfikesHas anyone built a rotate-based solution based on core.rrb-vector?#2018-12-0922:52taylorMy slightly optimized persistent vector solution was going to run for about 4 or 5 hours. Then I switched to finger tree at recommendation in this channel#2018-12-0922:54mfikesI figure you can easily build a rotate operation on top of core.rrb-vector, getting two subvec from the right place, and then doing a catvec on them. Maybe that would be O (log n) ...#2018-12-0923:52mfikesDamn, core.rrb-vector is broken. You get ClassCastExceptions deep down in its implementation. This code works if you comment the core.rbb-vector and uncomment the regular Clojure persistent vector calls. https://github.com/mfikes/advent-of-code/blob/day-9-rotate/src/advent_2018/day_09.cljc#2018-12-0923:56mfikesThat's unfortunate... the core.rrb-vector implementation works for (play 9 25), but not for larger problems, where it starts to crap out.#2018-12-0923:58mfikesSo, the fastest pure solution, using non-custom data structures is still sorted-map? Dang! I was hoping this core.rrb-vector approach would be fast, pure, and fairly idiomatic (and non-custom).#2018-12-1004:35gklijsA transient vector wouldn't do it? I might give it a try with transient vectors. I don't think it should be a lot slower then Java.#2018-12-1000:02namenu@mfikes At least you found a bug in core implementation. 😃 (BTW, I wish rrb-tree were under data.rrb-vector)#2018-12-1000:04mfikesAhh it is a known issue. https://dev.clojure.org/jira/browse/CRRBV-20 But now I can perhaps file an easier repro.#2018-12-1000:14mfikesI added the failing AoC code to that ticket.#2018-12-1000:56mishadeque, p2 "Elapsed time: 2390.909256 msecs"#2018-12-1000:57mishabeware of calling (->> q (iterate f) (take x)) on mutable things kappa#2018-12-1001:06misha@mfikes TIL rrb-vector. efficient concatenation that could have kept my room temperature lower#2018-12-1003:49potetmK, loop/recur instead of reduce gets me down to 1.2s (from 2.6s)#2018-12-1003:51potetm(still with homerolled circular doubly linked list)#2018-12-1003:51theeternalpulseI'm in the penalty box for day 3 hoping it's not telling me I'm wrong just because of one character lol#2018-12-1003:52theeternalpulseI can't think of why my algo doesn't work but I think it's the format of the id, we'll see in 4 minutes#2018-12-1003:59theeternalpulseguess not 😞#2018-12-1004:18potetmdown to 500ms with ArrayDeque#2018-12-1005:43mattlyday 10 is kinda fun, there's not really an easy way to determine the correct answer programatically, you have to start printing output at some point#2018-12-1005:44normanThere is a way#2018-12-1005:44gklijsI was wondering, you could probably have some 'statistic' like n alligned stars#2018-12-1005:44gklijsOr maybe when there most close together?#2018-12-1005:45mattlyheh, yeah#2018-12-1005:45mattlyok, that's fair#2018-12-1005:46mattlyI brute-forced it and simply printed anything with a certain compactness#2018-12-1005:47normanI mean technically, I suppose it you could make an input where the right answer was one or two off from that, so there’s no guarantee, but it’ll certainly get you in the ballpark. And, in may case it was exactly right#2018-12-1005:48mattlynote I did say "easy"#2018-12-1005:48mattly😛#2018-12-1006:00mattlyOh I suppose you could just stop when it starts growing again#2018-12-1011:36roman01lathat worked from the first try for me, stopped once the width started growing 👌#2018-12-1006:02normanWhat would be really fun, for another day, would be to write something that would find the local minimum more efficiently than stepping by 1#2018-12-1006:03mattlyYeah#2018-12-1006:03normanI wrote mine to take a range of steps and than checked each 1000 or so until I got in the area#2018-12-1006:04mattlyI waited until the height was less than 30#2018-12-1008:53heliosYeah that was the easiest direction. I had it run for 100k iteration and saw what was the minimum distance, and I tried to print that. Luckily it worked at the first go, but otherwise I would have only printed the (hopefully not many) iterations in which the distance was less than a threshold.#2018-12-1008:54heliosThe interesting bit is that this approach is far from being guaranteed to produce a good result. I wonder how you could "see" letters in the text 😄#2018-12-1006:06normanseems reasonable. I used total area. I guess when you have to read a display out many, any heuristic that gets you there is valid#2018-12-1006:21taylorI’m having trouble making any sense out of mine…#2018-12-1006:40normanAs in you aren’t converging to letters?#2018-12-1006:40tayloryeah I went straight to a visualization approach w/Quil and I’m finding it hard to pick out the exact frame as things converge#2018-12-1006:43fellshardI had an issue where all letters but the last were capital#2018-12-1006:43fellshard... and the last letter was a lower-case 'L'#2018-12-1006:43fellshard😐
#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" ns 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-user
adventofcode-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 ^^
#2018-12-1206:36normanSo, then under the assumption that I had this end condition, once I duplicated the state, I was able to advance immediately to the final 50b state (just shifting the pattern out)#2018-12-1206:37fellshardThis one pretty much depends on reaching a fixed point, yeah. The offset changes, but the pattern fixes.#2018-12-1206:38fellshardThat's often the case when they throw giant numbers at you; usually that's a hint you're missing an optimization in how you approach the problem.#2018-12-1206:42normanI don’t consider this an optimization. It feels more like side-stepping the problem to efficiently solve only the given input. Is there a guarantee we’ll always hit a cycle? Maybe - I dunno. Will it always manifest like this? I suppose with some deep thought I could answer that? In the end, I don’t feel like I wrote useful code - I just used some code to help me solve a single instance of a puzzle. That’s not very satisfying to me. (but I realize that’s how most of the top leaderboard operates overall)#2018-12-1207:47fellshardPretty sure you'd be waiting a loooong time running each generation by hand. It's expected the inputs are designed to reach some fixed point like this, just because any that diverge would be infeasible to solve for a challenge like this.#2018-12-1206:48normanOh, and just for amusement, before I searched for a pattern repeat, I searched for a score (sum of plant positions) repeat. I got several nonsensical repeats, and it took me a few minute to realize that there were many un-related patterns that could produce the same score. So then moved on to tracking the patterns#2018-12-1207:08mattlyI ended up looking for a repeat of the difference in sums#2018-12-1207:16taylorthis is what I’m currently trying but I must be missing something b/c I don’t see a repeat#2018-12-1207:45taylorhmm yeah just solved part 2 by finding the repeated pattern (started @ ~100 generations for me) and extrapolating the repetitive score difference to 50B#2018-12-1213:02ihabunekjust spent half an hour debugging the program and then discovering i was running on sample input instead of my input 😢#2018-12-1213:02ihabunektoday was familiar to anyone who played last year, pattern searching#2018-12-1213:02ihabunekhttps://git.sr.ht/~ihabunek/aoc2018/tree/master/clojure/src/aoc2018/day12.clj#2018-12-1213:11ihabunek
Part 1 "Elapsed time: 20.185556 msecs"
Part 2 "Elapsed time: 102.438381 msecs"
#2018-12-1214:28misha.
p1 "Elapsed time: 5.678204 msecs"
p2 "Elapsed time: 43.402724 msecs"
#2018-12-1214:49misha@taylor same#2018-12-1214:50taylorcurious to see what data structures people used to represent the pots. I used a map where the keys where the pot numbers and it made the logic pretty easy#2018-12-1214:52taylorhttps://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/12.clj#2018-12-1214:56misha(->> generations (drop 102) kappa#2018-12-1214:56taylor:man-shrugging:#2018-12-1214:57taylorREPL-driven development#2018-12-1214:58mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day12.clj#2018-12-1214:59ihabunek@taylor I used a sorted set containing indexes of full pots#2018-12-1214:59ihabunekit made detecting patterns very easy#2018-12-1214:59ihabunekjust (map - next-gen current-gen)#2018-12-1214:59mishatransient {pot-idx <"#"|".">} e.g. {-1 "." 0 "#" ...}#2018-12-1215:00ihabunekwhat is that 😄#2018-12-1215:02benoitToday was painful 🙂 https://github.com/benfle/advent-of-code-2018/blob/master/day12.clj#2018-12-1215:02mishatransient map + sort keys turned out to be faster than sorted-map#2018-12-1215:02ihabunekah, right#2018-12-1215:15Average-userI used something like (map rules (partition 5 1 pots) ) to get new generations#2018-12-1215:22mishaI started with it, but after 1st wrong answer, I realized I need to track pot indexes kappa#2018-12-1215:23Average-user#2018-12-1215:23mishaalso, if you don't shrink, and equilibrium is few 100k iterations away - you are in trouble#2018-12-1215:24Average-userI do track them:
(defn next-generation [pots rules]
  (->> pots
       (partition 5 1)
       (map #(let [r (rules (map second %))
                   i (first (nth % 2))]
               (if (nil? r) [i \.] [i r])))))
#2018-12-1215:24mishabut what is pots?#2018-12-1215:24mishasorted-map? sorted-set?#2018-12-1215:25Average-user(map-indexed vector "....#...###...##")#2018-12-1215:28mishadoes this assume pots don't expand below 0?#2018-12-1215:29mishaeither code is to dense or I am kappa#2018-12-1215:29Average-userNo, I add some \. to the start and the end on each generation#2018-12-1215:29Average-userI didn't post that, sorry#2018-12-1215:29mishaand you dont clean up those paddings?#2018-12-1215:30mishafirst, I added pads w/o shrinking, and boiled my CPU opieop#2018-12-1215:31Average-userYeah, not sure how to shrink#2018-12-1215:31mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day12.clj#L19-L37#2018-12-1215:35Average-userMine is something like
(defn shrink [pots]
  (if (= '(\. \. \.) (map second (take 3 pots)))
    (recur (rest pots))
    pots))
#2018-12-1215:37mishaI used indexes because I already had them in client fn, and did not want to pay reverse for shrink-right#2018-12-1215:38Average-usermakes sense#2018-12-1215:39mishaand I had them because I did not want to pay sort for map before each iteration#2018-12-1215:39mishabecause https://clojurians.slack.com/archives/C0GLTDB2T/p1544626959449600#2018-12-1215:32misham! is {-1 "." 0 "#" ...} #2018-12-1215:33mishaI am sure it has some off-by-1 error in there, but meh ¯\(ツ)/¯#2018-12-1215:41mishabut all of this does not really matter If equilibrium is just few hundred iterations away opieop#2018-12-1215:46Average-user
(time (vector (part-1) (part-2)))
"Elapsed time: 161.300258 msecs"
[3890 4800000001087]
#2018-12-1215:46Average-userEnded up with that, fair timo to be using just lists#2018-12-1215:46Average-usertime*#2018-12-1215:49Average-userHas someone prove that there always will be an equilibrium?#2018-12-1221:28Ben GrabowI tried 10,000 trials of a random initial state of 100 pots through my rule set and got a converging answer each time. So it seems the convergence is not dependent on the input pattern. It may indeed be possible to prove convergence based on only the rule set.#2018-12-1221:31fellshardThat's not unlikely, as specific automata can have such proven properties, I think.#2018-12-1215:50mishaI printed like 1000 of steps, it never changes, just drifts to the right (for me)#2018-12-1217:08meikemertschYepp, it’s useful to look at your data#2018-12-1215:51mishaI thought it would fluctuate, like gliders in game of life#2018-12-1215:52mishaand started with a loop to track anything seen to detect loops, but then printed it, and saw there is just a shift, no loops#2018-12-1216:41namenuhttps://github.com/namenu/advent-of-code-2018/blob/master/src/year2018/day12.clj I've encoded rules into binary digits (e.g. .#.#. -> 10), and looped through pots with five bits window.#2018-12-1217:49mfikesDay 12: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_12.cljc#2018-12-1221:11borkdudeAdvent of CLJC will now store times from comitted days and print an overview of times of solutions for committed days: E.g: https://circleci.com/gh/borkdude/advent-of-cljc/375
==== Scores:
  year | day | time | username | environment |  test  
------+-----+------+----------+-------------+--------
 2018 |   1 |    0 | borkdude | jvm         | part-1
 2018 |   1 |   31 | borkdude | node        | part-1
 2018 |   1 |  156 | borkdude | jvm         | part-2
 2018 |   1 |  329 | borkdude | node        | part-2
#2018-12-1221:28Ben GrabowI tried 10,000 trials of a random initial state of 100 pots through my rule set and got a converging answer each time. So it seems the convergence is not dependent on the input pattern. It may indeed be possible to prove convergence based on only the rule set.#2018-12-1221:53borkdude@ben.grabow I see there is an issue with my ssh command when building a PR. I’ll fix that now and let you know#2018-12-1221:54Ben GrabowNo worries. Tell me if you need me to do anything on my end.#2018-12-1221:57borkdudeFixed. Can you rebase or merge with master and then update the PR?#2018-12-1222:00borkdudeSeems to work now?#2018-12-1222:01Ben GrabowYeah, looks great. I don't see a table summarizing the times though. Should I?#2018-12-1222:01borkdudeNo, not in PRs, since the private key of my server is needed for that and PRs can’t access that#2018-12-1222:01borkdudebut once I have merged it to master, you will#2018-12-1222:02borkdudeso shall I?#2018-12-1222:02Ben GrabowSure go ahead!#2018-12-1222:04borkdudecrap, there’s still an error, I will fix#2018-12-1222:12borkdudefixed#2018-12-1222:15magic_bloatthe pots were two infinite lazy lists for me - one representing postive numbered pots, one representing negative numbered pots. The negative pots were in "reverse" order, -1, -2, -3, -4, -5#2018-12-1222:15magic_bloathowever negative points weren't really needed, my pattern moved rightwards, apart from a few exceptions at the start.#2018-12-1222:23fellshardI think they were mostly needed to ensure pot 0 had known empty pots to its left at the beginning. You say it did dip below 0 briefly?#2018-12-1222:32taylormine definitely went negative for a few generations but after that went straight positive#2018-12-1222:16Ben GrabowI considered doing something like that but shuddered at the thought of coding the step function near the origin. How did you handle it?#2018-12-1222:19magic_bloatactually not too tricky:#2018-12-1222:19magic_bloat(defn evolve-lhs [[lhs rhs]] (map (comp rule reverse) (partition 5 1 (cons (second rhs) (cons (first rhs) lhs))))) (defn evolve-rhs [[lhs rhs]] (map rule (partition 5 1 (cons (second lhs) (cons (first lhs) rhs)))))#2018-12-1222:19magic_bloatjust take a little of the other side#2018-12-1222:19magic_bloatand add it to the front of this side.#2018-12-1222:27Ben GrabowI guess you keep a little padding at the ends of each list so the partition 5 picks up the entire range?#2018-12-1222:30fellshardI pad the ends at the beginning and trim the ends at the end, keeping track of the new initial index. It seems to have worked reasonably well, though may be overkill; it really is just there to make the partition work.#2018-12-1222:33magic_bloatthe lists are infinite, so no manual padding required.#2018-12-1222:35magic_bloat(def start-row [(repeat \.) (lazy-cat (seq input) (repeat \.))])#2018-12-1222:35magic_bloatThe first item in the vector is the left hand side, all dots, the second is the right hand side, i.e. my input followed by dots.#2018-12-1222:38magic_bloatThis scheme ran out of stack space before I got to 500 iterations though 🙂#2018-12-1222:31taylorthis is why I used a map with indices as keys and did get with default value of \. for simplicity#2018-12-1222:34magic_bloatIf this has piqued anyones interest then Wolfram Alpha can show you your pot plants graphically, and millions of other pot plant reproduction schemes also!#2018-12-1222:34magic_bloathttps://www.wolframalpha.com/input/?i=rule+3111423880+r%3D2+random+ic#2018-12-1222:34magic_bloatThat's my rule working on random initial conditions#2018-12-1222:36magic_bloathttps://www.wolframalpha.com/examples/science-and-technology/computational-sciences/cellular-automata/#2018-12-1222:38borkdude@drowsy https://www.dropbox.com/s/wx0j13fj2iks455/Screenshot%202018-12-12%2023.34.54.png?dl=0#2018-12-1222:44drowsyoh nice new table 🙂#2018-12-1222:46borkdudeyeah, it’s instead of running all solutions now, which seemed not feasible anymore given the accumulation of state in namespaces#2018-12-1222:51drowsyyeah, I saw this when looking at the ci job 🙂. Pretty cool!#2018-12-1222:57borkdudehttps://github.com/borkdude/advent-of-cljc#scores#2018-12-1306:33normanThat was refreshingly fun after yesterday#2018-12-1306:45fellshardNice, relaxing one.#2018-12-1306:45taylorreally frustrating for me 😕 sample input works, real input fails#2018-12-1307:11taylorgah finally got it after finding all my dumb bugs. felt like I wrote way too much code for this one#2018-12-1307:31borkdudeare there any people doing Advent of CLJC and using Windows?#2018-12-1307:54mrmcc3Yeah i did my last solution from a windows machine#2018-12-1307:59borkdude@mrmcc3 does tools.deps work fine for you on Windows?#2018-12-1307:59borkdudeI’m considering using Planck or Lumo for scripting instead of bash, but I’m wondering if this would be problematic for some people. It’s not strictly necessary#2018-12-1308:01mrmcc3Ah i just use the tools.deps built into cursive/intellij. Once I solved the problem in clojure from the repl I run the scripts in WSL ubuntu#2018-12-1308:02borkdude@mrmcc3 would it be reasonable to assume just about every developer on Windows uses WSL?#2018-12-1308:04mrmcc3Ha no idea I only just started trying on AOC#2018-12-1308:06borkdudeI’m glad to hear the scripts work in WSL 😉#2018-12-1308:10borkdudeI wonder if Planck works under WSL#2018-12-1308:13mrmcc3I can try it out don't see why not#2018-12-1312:34magic_bloatday 13, quite fiddly - I had a bug that had trains going completely the wrong way at the junctions, but cleverly and annoyingly it managed to get the right answer on the test input.#2018-12-1312:50benoitMy solution for Day 13 https://github.com/benfle/advent-of-code-2018/blob/master/day13.clj#2018-12-1312:56mfikes@borkdude Planck does work under WSL. There is an upstream WebKit issue that has a workaround (not sure if that issue has been fixed and the fix widely deployed; I haven't looked at it in a while). https://github.com/planck-repl/planck/issues/746#2018-12-1312:57borkdude@mfikes cool! I haven’t made my mind up about it yet, since I think most of the stuff works, but it would be more maintainer friendly if some bash was replaced with clojure. on the other hand, I’m forcing an extra installation step on advent-of-cljc users#2018-12-1312:58borkdudebut good to know it’s an option#2018-12-1313:15borkdudebtw, if you want to trigger recording of the scores for certain days, all you have to do now is create a PR to a branch named yyyy/dd/rescore, then I’ll accept it, and all the changed namespaces will be recorded. I did that here: https://github.com/borkdude/advent-of-cljc/tree/2018/01/rescore these changes won’t have to be applied to master, just being in a branch in my repo is enough#2018-12-1313:15borkdudeI might make a script that does this automatically per day#2018-12-1316:21Average-userI just read day 13, seems fun. But I don't know if I'll have time to implement it today#2018-12-1317:01taylorI'm too ashamed to commit my solution :biohazard_sign:#2018-12-1317:17helios@borkdude replying to something of a few days ago: https://github.com/lambdaisland/trikl a new project to make terminal UIs in clojure. It might be good for some of the visualizations of the AoC#2018-12-1317:23borkdude@helios I think you’re replying to something that was a reply to that lib 😉#2018-12-1317:26helioswhoops 😛 it happens when they are discussions of days ago 😄 sry!#2018-12-1317:42pesterhazyI'm getting an "incorrect answer" on day13 part 2#2018-12-1317:42pesterhazyBut I'm not sure it's incorrect or how it could be wrong - it works on part 1 and on the extra sample input provided for part 2#2018-12-1317:44pesterhazyHere's my attempt: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle13.clj#L120#2018-12-1317:44ccannthat is the worst feeling#2018-12-1317:45pesterhazyHaven't encountered that in any previous day#2018-12-1318:06potetmhttps://www.twitch.tv/timpote#2018-12-1318:23gklijsThat's cheating ;)#2018-12-1318:51borkdudecool!#2018-12-1318:53borkdudeis this live btw?#2018-12-1319:12potetmYeah when I post it’s live.#2018-12-1319:13potetmVODs are available for 14 days#2018-12-1319:13pesterhazysounds fun, this was my first Twitch experience#2018-12-1319:13borkdudeVOD?#2018-12-1319:13pesterhazyi thought it was only for games!!#2018-12-1319:13potetmVideo On Demand#2018-12-1319:13potetmsry gamer term 😛#2018-12-1319:14potetmYeah, no. Twitch is pretty great actually.#2018-12-1319:14borkdudeI’m not a gamer, sorry 🙂 why not post these to Youtube then?#2018-12-1319:14borkdudebtw, very cool and inspiring. can’t wait to hack something mutable now in Clojure 😛#2018-12-1319:14potetmUhh, so I’m thinking about posting to youtube or self-hosting#2018-12-1319:14potetmhaven’t decided yet#2018-12-1319:15potetmThanks for the feedback! It’s much appreciated!#2018-12-1319:15borkdudecool. valuable tutorial. I think I might try day 9b in the Christmas break.#2018-12-1319:16borkdudeI first saw this mutable approach here. Very similar solution I think: https://github.com/kolov/adventofcode2018/blob/master/day9-marbles/src/main/scala/example/Main.scala#2018-12-1319:16borkdude
case class Marble(var left: Marble, var right: Marble, value: Int)
#2018-12-1319:17potetmI honestly don’t know how to do it efficiently w/o mutability. I’m sure there’s plenty of higher polynomial solutions.#2018-12-1319:17borkdudeThese dequeue data structures do exactly this? I didn’t look into those#2018-12-1319:18borkdudeI tried it with plain vectors first. it works, but sloooow#2018-12-1319:18potetmAlmost. You have to build a rotation fn in. But they’re structured so this operation is pretty efficient.#2018-12-1319:18potetmYeah, I saw immediately that was an issue. Went off and thought about it for a while before starting.#2018-12-1319:19potetmThen come to find out java has a much better solution built-in 😛#2018-12-1319:19borkdudeyeah, but advent of cljc has to work on Node as well 🙂#2018-12-1319:19borkdudemaybe node also has something like this, but may require a lib#2018-12-1319:19borkdudeyour solution probably works out of the box#2018-12-1319:53meikemertschWas fun. Thanks a lot!#2018-12-1320:44gklijsWith java you can work with 'native' intarrays and get the solution down to 33 ms.#2018-12-1320:45gklijsWouldn't surprise me if there was an even faster way to calculate it using some mathematical model.#2018-12-1318:45pesterhazyFound the bug - now it works https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle13.clj#L78#2018-12-1318:47pesterhazyIt's not that the puzzle description was unclear - but I still failed to grasp the rules for collision detection. Somehow I feel an imperative solution would have been more obvious#2018-12-1318:50pesterhazyI made multiple mistakes of conception when choosing the pairs for collision comparison - which sadly worked for p1 but gave an incorrect answer for p2#2018-12-1318:50pesterhazyI wonder what conclusions to draw from this, other than the fact that I'm dense 🙂#2018-12-1318:51benoitdebugging is part of the process 😉#2018-12-1319:02pesterhazy@me1740 always look on the bright side...#2018-12-1319:35taylorI went with an imperative solution b/c it seemed most straightforward late at night#2018-12-1319:38fellshardIt's not too bad w/ pure functional code, either; I usually end up with tagged results, e.g. [:ok carts] or [:collided colls]#2018-12-1319:38fellshardNot much different than using reduced#2018-12-1319:54meikemertschThis day was a big piece of work. Not hard. Just tiring and long. But fun 😄 Finally something that even I can manage#2018-12-1320:10markwI've burned too much time on this problem... this code works on the sample input and a few others I created but chokes on the actual input - I can't find the bug.#2018-12-1320:37pesterhazyA "concise" solution for day12: https://www.reddit.com/r/adventofcode/comments/a5eztl/2018_day_12_solutions/ebmfcqc/#2018-12-1320:50fellshardAhhh, APL; ever a source of delight and horror. To be fair, it's probably a fantastic fit for a number of these problems.#2018-12-1320:45markwFigures... i struggle for hours, post, and 30 min later find the bug#2018-12-1320:47markw#2018-12-1321:34magic_bloat@pesterhazy Had the exact same problem - it worked for the example, but took three attempts at getting the collision detection exactly as described to make it work for the actual puzzle.#2018-12-1322:34fellshardIt made the recursion annoying, because you really can't solely update carts in-place, since each cart depends on the result of the cart before it. I ended up using straight loop-recur over reduce this time because of that.#2018-12-1322:38benoitYes, that was my main bug too. A cart might have disappeared because of a collision. I solved it by checking that the cart was still around before trying to move it. So I could continue to reduce.#2018-12-1323:17fellshardYou know, you're right. Could've done it by just flagging the collided carts instead of removing them. Would've made some things easier.#2018-12-1323:23pesterhazyThat’s what I did - set a flag and clean up in a second pass#2018-12-1323:29fellshardI might give that a shot, much cleaner than the index fiddling I'm doing.#2018-12-1400:24misha@pesterhazy https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle13.clj#L139-L147 opieop#2018-12-1400:34Ben GrabowI'm not sure if I had more than 2 carts headed to the same point on the same tick, but I did have a bug when a moving cart collides with a cart that hasn't yet moved on the current tick. (The not-yet-moved cart was not being deleted correctly.)#2018-12-1400:36Ben GrabowYou might try using group-by and (map count carts-generations) to verify that the cart collection cleanly removes exactly 2 carts instead of 1 or 3 at a time.#2018-12-1401:16misha> moving cart collides with a cart that hasn't yet moved just fixed that one opieop#2018-12-1401:20mishaI just did loop/recur, could not come up with anything readable but not excessively wasteful with seq api#2018-12-1401:26mishalooks reply https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day13.clj#2018-12-1402:49Average-userI think Is pretty readable, and not that long: https://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day13.clj#2018-12-1403:18mfikesDay 13: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_13.cljc#2018-12-1403:43taylorhttps://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/13.clj#2018-12-1404:35taylorday 13 animated https://www.youtube.com/watch?v=hnDNNvy8gww#2018-12-1404:48Average-userNice#2018-12-1406:09meikemertschMy part2 examples for day 14 make no sense#2018-12-1406:09quollmine make sense, and I can pass them, but I can’t make it work on my puzzle input#2018-12-1406:10meikemertschDoes someone have part1 solved and can send me just the descriptions please??#2018-12-1406:10quollI’ve done part 1#2018-12-1406:10quolldescriptions of what?#2018-12-1406:11meikemertschpart 1 and 2. The thing is that I probably need your part 1 input to understand the part 2 input because I guess we have different examples#2018-12-1406:12quollDM#2018-12-1406:12meikemertschThanks a lot#2018-12-1406:16taylorThis one didn’t feel too hard, except it took me a while to understand part 2 objective #2018-12-1406:16meikemertschI suspect we have an error.#2018-12-1406:16meikemertschCould you explain part2? My examples just give me the 5 five digits of each of the 10 digits from part two. That doesn’t seem right#2018-12-1406:17taylorYou have to keep generating recipes until the sequence of individual digits from your input appear as scores #2018-12-1406:18meikemertsch🙈 I still don’t get it#2018-12-1406:18taylorIt’s not very well described either #2018-12-1406:20taylorIf your input is 1982, then you have to keep generating recipes until your sequence of recipes contains a subsequence of [1 9 8 2]#2018-12-1406:21meikemertschone of my examples is “92510 first appears after 18 recipes.”#2018-12-1406:21meikemertschthere’s no 18 there?!#2018-12-1406:21taylorYeah the examples don’t make sense to me#2018-12-1406:21taylorI didn’t even bother running them #2018-12-1406:22meikemertschwhy five digits?#2018-12-1406:22taylor:man-shrugging:#2018-12-1406:23norman@U0A7TVBLN what it means is that the sequence ending “92510” has 18 prior recipe numbers#2018-12-1406:23taylorMy input was six digits#2018-12-1406:24meikemertschwhat would it look like for an input of 2?#2018-12-1406:25normanThe first sequence ending in 2 would be 37101012#2018-12-1406:25normanso it would appear after 7 recipes#2018-12-1406:26meikemertschoh!!! Backwards!!!#2018-12-1406:26meikemertschI think I got it now#2018-12-1406:28meikemertschThanks for the help!!#2018-12-1406:25quollis there anything odd about part 2?#2018-12-1406:26quollI ran my attempt over the 4 digits sequences in the examples, and it works fine. I run it over my 6 digit puzzle input, and it’s still going.#2018-12-1406:26normanYour number will be very high#2018-12-1406:27normanI’m still running part2, and I’m debating making more optimization or just waiting#2018-12-1406:27quollyeah… but it’s a very tight loop, and it’s been going an hour#2018-12-1406:27quolland will my sequence exhaust the heap?#2018-12-1406:28quollperhaps I rewrite it in C 🙂#2018-12-1406:30baritonehandssubvec really sped it up for me#2018-12-1406:30normanI’m not sure how far. I’m tempted to look at other peoples number for guidance#2018-12-1406:30baritonehands21s#2018-12-1406:30taylorPart 2 finishes in a few seconds for me using vectors#2018-12-1406:31normanhmm - I must be making a serious mistake in something. I’m only getting about 10k iterations/sec#2018-12-1406:32norman(Thread/sleep 1000)#2018-12-1406:33normanthat’s my debugging sleep so I can inspect the output#2018-12-1406:33normanha#2018-12-1406:43meikemertsch🙈#2018-12-1406:46quoll@U3DAE8HMG, are you still here?#2018-12-1406:55fellshardKeep in mind you can have up to two digits appended to the end; you can't just check the very end of the vector for the pattern!#2018-12-1407:03quollyes, I’d remembered that, but my 1am coding made a mistake with it. So while I was checking for more than just the very end, I wasn’t doing it right#2018-12-1407:03quolland indeed, that was the problem#2018-12-1407:04quollsince my input ended in a 1#2018-12-1407:41fellshardYeah, I did a dumb with that as well, a slipped paren#2018-12-1406:28meikemertschThanks for the help. I understand the problem now#2018-12-1409:04helioshm, also for me part2 is taking long. I'm using subvec and I'm also not repeating the lookup in the middle of the vector, but only at the end#2018-12-1409:04heliosI wonder what more I could do#2018-12-1409:05plexus@helios you want to share what you have? I can take a quick look#2018-12-1409:06heliossure#2018-12-1409:06helios
(ns adventofcode.2018.day14)

(def day-input 846601)
(def day-input-vec [8 4 6 6 0 1])

(set! *unchecked-math* true)

(def initial-state {:workers #{0 1}
                    :table   [3 7]})


(defn iteration [{:keys [workers table]}]
  (let [scores (map (partial nth table)
                    workers)
        recipe-sum (reduce + scores)
        new-recipes (if (< recipe-sum 10) [recipe-sum]
                                          [(quot recipe-sum 10) (rem recipe-sum 10)])
        new-table (reduce conj table new-recipes)]

    {:workers (mapv (fn [index] (mod (+ index (inc (nth table index)))
                                     (count new-table)))
                    workers)
     :table   new-table}))


(defn compute-score-after [n]
  (subvec (->> (iterate iteration initial-state)
               (drop-while #(< (count (:table %))
                               (+ 10 n)))
               first
               :table)
          n (+ n 10))
  )


(defn contains-sequence-at-end? [table sequence]
  (let [c1 (count table)
        c2 (count sequence)]
    (and (>= c1 c2)
         (= sequence (subvec table (- c1 c2)))))
  )


(defn solution2 [input]
  (->> (nth (iterate iteration initial-state) (count input))
       (iterate iteration)
       (drop-while (comp not #(contains-sequence-at-end? (:table %) input)))
       first
       :table
       (drop-last (count input))
       (count)))
#2018-12-1409:06helios@U07FP7QJ0 a gist is better maybe: https://gist.github.com/Heliosmaster/4971270311f00f3f8af1ccb7c0d29adf#2018-12-1409:13plexusLooking at it from Visualvm it seems your bottleneck is in iteration. table is always a vector, right? In that case you should avoid nth, as it will treat the vector as a seq and walk it element by element. Use get instead.#2018-12-1409:17fellshardYou're testing for the pattern at the end, but you're adding not just one, but possibly two digits at the end.#2018-12-1409:19helios@U1YPTG4UF right, i should check twice to be sure#2018-12-1409:19heliosbecause only the first digit might be sufficient#2018-12-1409:19heliosthanks#2018-12-1409:29heliosand also when that happens, I was off-by-1 with the final solution 😄#2018-12-1409:41borkdude@U07FP7QJ0 Is that right, I thought nth on vector is comparable to an array lookup: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java#L161#2018-12-1409:47plexusI guess you're right!#2018-12-1409:54plexusit's still spending a lot of its time in those first few lines of iteration, just doing the map+`reduce` to compute the score...#2018-12-1412:00heliosthe reduce on the scores should be very fast (it's just two values)#2018-12-1412:00heliosand also map should just operate on two scores#2018-12-1413:12Average-userIs (set! *unchecked-math* true) really necessary?#2018-12-1413:11benoitMine takes 34s w/ subvec 😞 https://github.com/benfle/advent-of-code-2018/blob/master/day14.clj#2018-12-1414:07mishanot relevant, but this could be just def https://github.com/benfle/advent-of-code-2018/blob/master/day14.clj#L14-L17#2018-12-1414:12benoitabsolutely 🙂#2018-12-1413:49taylorI’m getting ~10s for part 2 w/vectors, subvec, loop, recur#2018-12-1414:03misha"Elapsed time: 36315.651048 msecs" not optimized for performance p2 (somewhat readable though)#2018-12-1414:04mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day14.clj#L53-L72#2018-12-1417:45Ben GrabowI stole your adjust-idx function and it gave me a 10x speed up. Seems like my run cost was dominated by the rem function call to wrap the index back into the correct range. Successive subtraction is far cheaper. Now I get 2-3 seconds for part 2, down from 25-30 seconds.#2018-12-1417:53mishanice time! adjust-idx probably could be a bit faster with loop in it instead of seqs, but I didn't bother to test it out#2018-12-1418:11Ben GrabowI retract everything! I introduced a typo when using adjust-idx that resulted in my algorithm finding the wrong answer, which appeared much earlier in the sequence. So the execution overhead didn't change significantly, I was just running through 1/10th the iterations. I'm back above 20 seconds! :man-facepalming:#2018-12-1418:26mishaopieop#2018-12-1416:52quollI got 4.3s in the end (2am) 😳 I had an optimization to only look when one of the last 2 digits matched the final digit of my input, and I messed it up, which is what kept me up late. But when it worked, it was fast#2018-12-1417:18misha@quoll nice#2018-12-1417:26quollI wanted to avoid unnecessary subvecs, so I finished my loop with something like this pseudocode:
(if (= last-input-digit last-digit-added)
  (test-the-trailing-subvec recipes input)
  (if (> last-value-added 9) ;; we know that the final input digit is 1
    (test-the-second-last-trailing-subvec recipes input)
    (recur recipes first-elf second-elf)))
#2018-12-1419:03fellshardThat's probably a lot cheaper...#2018-12-1417:59potetmhttps://www.twitch.tv/timpote#2018-12-1419:41meikemertschDang I missed it. But I also needed a day off programming. Did today’s part 2 literally at work so I would have the evening free while I was waiting for a build (several times) containing some fixes from one of my devs. This was my last working day today so there was no pressure to start anything new#2018-12-1419:54potetmNice! Yeah I’ve had to take a few days from AoC myself. Glad to have a little lead time before the stream 🙂#2018-12-1419:13fellshardOne idea I had, that may be vaporware - you can 'replay' strings you've seen before, up to the point where one of the elves wrapped around to the beginning. Since those substrings have already been seen, the pattern could only show up at the boundary between that memoized string and the current recipe string. This would probably accelerate as you got further down the line... Then again, might be the cost of holding all that in memory / calculating all these strings would be inordinately costly. Managing them would certainly be a pain.#2018-12-1419:21pesterhazyMy day 14: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle14.clj#2018-12-1419:22pesterhazyProudly unoptimized#2018-12-1419:33taylorvery concise 😚👌#2018-12-1420:46mishabut what does all of it mean? kappa#2018-12-1421:18magic_bloatIs it wrong that my first response to being told that my answer is too big is to try (dec answer) ?#2018-12-1421:18magic_bloatAnd then not fix the bug...#2018-12-1421:20markw@magic_bloat wrong: probably effective: yes#2018-12-1421:49markwnote to self... if you use (take-last) on day 14, you're gonna have a bad time.#2018-12-1501:05taylorhttps://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2018/14.clj#2018-12-1503:56mfikesDay 14: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_14.cljc#2018-12-1504:20Average-userI havent had time to do day 14 and day 15 is coming#2018-12-1504:20Average-user😟 #2018-12-1505:38quollI just looked at Day 15. It feels like CS homework. “Implement an A* algorithm.” Not really fun#2018-12-1506:32tayloryeah I don’t think I have time in my life to do this one :man-tipping-hand:
#2018-12-1506:38taylorreminds me of a http://codingame.com competition but less fun#2018-12-1508:23normanI think it’s a fun problem, but there’s really too much going on here to finish quickly. I’m 2 hours in and I’m not quite getting the move selection right. I think I need finish in the morning.#2018-12-1509:52gklijsIt would have been more fun if the explanation was less explicit and the actual algorithm a bit more easy. Still it's doable, so I'll will.#2018-12-1510:08gklijsJust looked at the times for the first 100 to get it right, around 15 minutes for almost any day, but today over 2 hours#2018-12-1515:18meikemertschMy brain is fried. I have a solution but it works really slow for bigger dungeons. I suspect one line of code to be the culprit for making it so slow. Does anyone have the time to check this with me?#2018-12-1515:19meikemertsch(filter (sets/union free enemies)) This is the line of code I suspect will cause trouble for large sets “free”. “enemies” is usually small.#2018-12-1515:25meikemertschoh. and sets is (:require [clojure.set :as sets])#2018-12-1516:37Ben GrabowI tried out tufte yesterday and it seems easy to use out of the box for profiling. https://github.com/ptaoussanis/tufte Wrap the code you want to profile in the p macro and you should be able to see what's hogging the most time.#2018-12-1517:13meikemertschthanks#2018-12-1515:44helioswow, it's almost 10 hours after the game and then only 835 people solved it completely, compared to the thousands from yesterday 😄#2018-12-1515:44heliosit's a PITA problem 😄#2018-12-1515:47gklijsI just got the first part, almost the second but have to go, was the first time I was one of the first thousand to solve the first#2018-12-1515:47gklijsAnd with all that state very happy to do it with java..#2018-12-1516:19magic_bloatI've been doing it for about 4 hours, still bug fixing part 1. Grrr.#2018-12-1517:35drowsyi finally finished day 15 and it's pretty rough and slow, but I'm definitly not eager to touch it any further... https://github.com/IamDrowsy/advent-of-cljc/blob/slow/src/aoc/y2018/d15/iamdrowsy.cljc#2018-12-1523:05mfikesWow. I might save day 15 for some other day. WTF.#2018-12-1523:10markwOpened up laptop last night, read day 15, closed laptop.#2018-12-1523:11mfikesThat problem will likely cost $1000 to solve, in terms of time. You could buy a new laptop.#2018-12-1523:12markwmeanwhile stuck on part 2 of day 13, I’ve looked at this over and over and can’t find the bug… any help would be appreciated! https://gist.github.com/Solaxun/1b4b7ada84b936d43fbee04ede0062f4#2018-12-1523:53Ben GrabowLine 66, :locs should be :loc. If you have any collisions that should happen on the first tick they'll get missed. I don't see anything else obviously wrong, so hopefully that's it.#2018-12-1523:57markwyou have GOT to be kidding me… i looked for hours and missed that#2018-12-1523:57markwthat was it.#2018-12-1600:01Ben GrabowWhen I'm debugging these problems, especially with a loop, I'll do a println of each loop parameter and run through the first ~5 iterations manually checking that everything looks right. Usually I'll use the small sample data set from the problem description too. Would have caught this typo.#2018-12-1600:02Ben GrabowGlad I could help you fix it!#2018-12-1600:03markwThanks for the help … yeah belive it or not i did do several runs with the sample input#2018-12-1600:03markwi had helper functions not shown in the gist for printing the track#2018-12-1600:03markwbut no collisions happened on the first tick so I didn’t notice#2018-12-1600:05Ben GrabowI mean print c, cs, full? and new-cars inside your loop, to ensure you got the mechanics of the loop correct. Often mistakes will not manifest obviously in the intended output, but if you look directly at the internal implementation the problem will be more obvious.#2018-12-1600:07markwyeah fair point … printing full? i would have noticed the nil at the start#2018-12-1600:07markwi was focusing on printing all the wrong things#2018-12-1600:08markwthanks for the help, who knows how long i would have stared at that aimlessly#2018-12-1523:12markwDay 15 reminds me of day 11 from 2016 IIRC - the elevator problem#2018-12-1523:13markwthat and the molecules for 2015 were just a beating#2018-12-1601:21mishadude, 2015 molecules are awful, but interesting! but today's one is just zzz#2018-12-1601:21mishaGC overhead limit exceeded#2018-12-1601:21mishaopieop#2018-12-1602:01fellshardThis feels like a day 24 one in previous years, but day 15? yikes#2018-12-1602:01fellshardMaybe the assumption is that the weekend is a good time for a big one#2018-12-1602:12Average-userI might do day 15, but if there is other problem like this one this year I may quit the whole thing#2018-12-1602:24potetmsame^ — or at the very least skip it#2018-12-1602:39markwthis is by far the most difficult year… at least for me#2018-12-1602:40markwI think it’s a combination of just more difficult puzzles, but also I’ve noticed that compared to prior years where part 2 is usually a layup, this year that is not always the case#2018-12-1603:04misha
(assert (= (f1 input) 196200))
"Elapsed time: 4399.123038 msecs"
#2018-12-1603:05mishap2? I'll just let it run overnight and submit result. totally not worth it, although I have an optimization in mind.#2018-12-1603:13misha
p2 "Elapsed time: 538665.073576 msecs"
#2018-12-1603:33Average-userthats day15?#2018-12-1603:37benoitDay 15: https://github.com/benfle/advent-of-code-2018/blob/master/day15.clj I am not sure why my Part Two does not work. Probably something stupid because it worked on all the examples.#2018-12-1603:38benoitFunctional programming is not the best for simulations 🙂#2018-12-1603:39misha@lucaspolymeris 15#2018-12-1604:36fellshardOkay, not deleting this time. data.priority-map is definitely busted 😞#2018-12-1604:38fellshardSpecifically, it really seems to behave oddly with the way I'm using it, and I'm not sure what about my keys and values is causing pop / dissoc to break#2018-12-1604:39Ben Grabow@fellshard Can you use sorted-set-by instead, where the set contents are the items and the sort fn is the item->priority fn?#2018-12-1604:39fellshardLooks like I'll have to. Was trying to avoid resorting each time 😞#2018-12-1604:40fellshardGoing for a classic priority queue sorted-heap approach, but that doesn't seem to be something anyone has implemented reliably in Clojure, at least not with any of those key words.#2018-12-1604:40fellshardMaybe an issue in getting a persistent impl? Dunno.#2018-12-1606:52normanI guess day 15 really took a toll on people.#2018-12-1607:09normanWell, hope to see some renewed activity here for day17.#2018-12-1608:19fellshardI jumped ship to 16, that was much more fun 🙂#2018-12-1608:20fellshardMaybe I'll see about continuing 15 tomorrow, my brain's happily fried. The wrinkle in this problem was a fun one to figure out, it took me a few attempts to find a working algorithm.#2018-12-1608:37markw16 wasn’t too bad… but I took the lazy way out on part two and just one by one eliminated anything that didn’t have a unique result#2018-12-1608:38markwmanually that is… maybe tomorrow i’ll code it.. i always feel dirty/guilty doing it by hand#2018-12-1608:57namenu@markw same here 😅 I'm thinking of it to solve with core.logic later.#2018-12-1617:00uosli gave core.logic a try with solving day 7, but I don't think it was much improvement. (and I still couldn't figure out how to get the ordered steps without using elimination with everyg) https://github.com/uosl/advent-of-code/blob/master/src/aoc2018/07.clj let me know if you use it so I can check it out!#2018-12-1708:47namenugreat! i'll have to dig into your code 🙂#2018-12-1609:01markwI’ve been meaning to play around with that at some point.. never done any logic / prolog stuff before#2018-12-1609:01markwyeah tonight i needed a quick win after the past couple puzzles…#2018-12-1609:48gklijsAnyone stuck on day 15, there is a corner case I ran into which is not tested in the examples. When there are multiple targets at the same distance, you should pick the path to the enemy closest in reading order and not the part starting with a step closer in reading order.#2018-12-1610:33fellshardI believe that is stated in the problem definition, if not in the examples, though. This is definitely the kind of problem where it'd help to have a good catalogue of examples to run through, though.#2018-12-1610:37gklijsIt is, but there are so many rules, it's easy to miss one and have the priority a little different. For my data the difference was only 12 HP the elf's had less.#2018-12-1615:53pesterhazyMy day 15: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle15.clj#2018-12-1615:53pesterhazyAnd my day 16: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle16.clj#2018-12-1615:56pesterhazySkipped a day and took me a while to catch up - I didn't want to open up Slack again before being all caught up, to avoid spoilers#2018-12-1616:06pesterhazyI thought the roguelike was a lot of fun, but it takes some time#2018-12-1616:09pesterhazyWow, only 2200 people finished day 15, down from 6000+#2018-12-1616:11pesterhazyIn day 16 I was bitten by partition again, which silently drops the last group if it isn't complete. I really feel partition-all should be the default#2018-12-1616:22pesterhazy10 people finished day 15 in less than an hour !#2018-12-1616:45uosli'm glad day 16 was a fun problem, in comparison to the previous one which I didn't even read through after seeing the comments here...#2018-12-1616:46normanha#2018-12-1616:47normanPeople get frustrated easily. I don’t love the problem, and ended up finishing part1 in the morning. It was a bit more fun without the “I need to figure this out so I can get to bed” pressure#2018-12-1616:48normanIt really wasn’t hard, it was just annoying to figure out what the problem was asking. (and annoying when you didn’t have a test case that demonstrated what you were doing wrong)#2018-12-1616:50uoslmaybe i'll give it an attempt next year. i just don't feel like spending 6 hours on that this weekend ^^#2018-12-1616:51norman1/3 of that is coding 2/3 of that is figuring out the instructions. If you can find a good restatement of the problem into english, I bet you can get it quickly#2018-12-1616:53uosli guess it's a bit like the flower pot problem then? i spent a lot of time rewriting that as i gradually learned how those rules applied#2018-12-1616:55normanMaybe. I thought that one was very clear. I never had any doubt about what to do - just how to do it. For day 15, I often didn’t understand what the problem was asking to do#2018-12-1616:58pesterhazyFWIW I think the instructions have been clear for most (all?) days almost to a fault#2018-12-1616:59pesterhazyWhich doesn't mean that I didn't misread them - but that's on me for being hasty#2018-12-1617:00normanObviously some people understood 15 out of the gate and got it relatively quickly.#2018-12-1617:02pesterhazyI think this type of problem will be hard to phrase unequivocally, no matter how good of a writer you are#2018-12-1617:04pesterhazyDay 15 was almost too verbose - in some places the description felt like it was reiterating what it just said. But of course in other places, I needed to have the logic repeated to me to get it into my head#2018-12-1618:44fellshardThe more I think about it, the tighter the pathfinding could be. It really does turn into a simple BFS, priority sorting by [distance, position, ancestor] (where ancestor is the tile you would move to in order to approach position)#2018-12-1618:47pesterhazyI took it as an opportunity to learn how A* works #2018-12-1618:47pesterhazyWhich was fun - it’s an elegant algorithm #2018-12-1618:49pesterhazyGot to use java.util.HashMap and j.u.PriorityQueue for the first time #2018-12-1617:39meikemertschI might be odd but I enjoyed day 15. It was a ton of work, granted, but I had fun and learned a lot. I guess for more experienced people it felt more like homework…. Day 16 was cool because I knew exactly what I wanted to do#2018-12-1617:40meikemertschAnd it helped me with a problem on 4clojure that I hadn’t done before#2018-12-1618:11mfikesDay 16: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_16.cljc#2018-12-1618:20pesterhazyNice use of fixed-point#2018-12-1618:29uoslfirst defmacro i've seen here [=#2018-12-1618:33mfikesHah. And, if you look closely, you will see that I'm using defmacro in ClojureScript. :thinking_face:#2018-12-1618:35pesterhazyThe fixpoint trick reminds me of sickpea#2018-12-1618:37mfikes@U06F82LES I got stuck on that part (not seeing how to proceed), but took a peek at your solution to get unstuck#2018-12-1618:37mfikes(I was stuck on the point that my intersections were doing nothing, but I failed to see there was a singleton that could be leveraged.)#2018-12-1906:09quollThe problem with falling behind (Xmas parties are a thing at this time of year) is that I think I’m doing something clever only to discover that someone else did it a few days before I did#2018-12-1906:10quollI nearly used a fixpoint, but decided it was easier to see when I’d cleared all of the ambiguities#2018-12-1906:14quollwell… sort of the same. I kept reversing my map, because each time I did, new singletons emerged. Bijective mappings are like that 😄#2018-12-1618:32pesterhazyBTW I came up with a pattern. I have emacs running on the left half of the screen and a terminal with rebel-readline on the right. Whenever I reload the namespace, my test function gets re-run automatically: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle16.clj#L140#2018-12-1623:58mishareduce all the things!#2018-12-1623:59mishadid anyone actually use core.logic for day16? I spent half of the day neck-deep in tutorials and videos, and implemented solved "mapping" with a loop and a bunch of recurs instead kappa#2018-12-1701:47taylorthis book is really useful for learning it https://mitpress.mit.edu/books/reasoned-schemer#2018-12-1700:01mishano regrets#2018-12-1700:03misha@mfikes I almost went multimethods way exclusively to write this line, but then didn't kappa https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_16.cljc#L54#2018-12-1700:05mishacase is way more obvious, and no need for open system#2018-12-1700:19taylorI just looked at day 16 and it reminds me of a chapter in the reasoned schemer about Bitwise math#2018-12-1700:21taylorSeems like the difference between the register and immediate instructions would make it more difficult to model though #2018-12-1701:24fellshardSince 'assembly simulations' are a recurring theme year over year, I've made myself a toolkit of techniques for creating a quick-'n'-dirty parser + interpreter. It's handy to know the pattern for things like that.#2018-12-1701:24fellshardhttps://github.com/armstnp/advent-of-code-2018/blob/master/clojure/src/advent_of_code_2018/day16.clj#L10#2018-12-1701:25fellshardThe way I think of it is to use a uniform function signature: given an 'address' and a set of registers, return a value. Then I have one function - immediate - that just uses the 'address' as a value and ignores the registers, and another - register - that uses the 'address' to retrieve a value from the registers.#2018-12-1701:36mishawoah, verbosy#2018-12-1701:55fellshardYeah, I don't golf my solutions. I prefer verbose but comprehensible, I can always refactor later.#2018-12-1701:58fellshardThat macro in your solution is quite tight, though 🙂#2018-12-1709:38mishathat's mfikes' macro#2018-12-1709:53fellshardOop! You're right, thanks#2018-12-1702:00Average-userFor that 16 part2 I really would have liked to be using Prolog#2018-12-1702:05taylorI’d like to see a logic program for this one too, but I kinda doubt it’d be any more concise/obvious than e.g. mfikes’ solution#2018-12-1702:18taylormaybe b/c a purpose-built constraint solver for a particular problem is easier than describing the constraints in a more general solver#2018-12-1702:23fellshard16 lvars binding op-code to operation, such that no counter-examples for that binding exist? Seems it'd be straightforward if all you needed in your database is a suite of counterexamples#2018-12-1702:42taylorI was imagining most of the complexity being in writing goals for each operation#2018-12-1702:43taylorThough I also imagine you could “cheat” by using non-relational goals/predicates too#2018-12-1702:43Average-userThe idea of logic programming is to describe what you want, not how you will get what you want. So ideally it would be more obvious, but not necessarily more concise#2018-12-1702:46taylorFor example, in the chapters on bitwise math in the reasoned schemer, it takes quite a bit of work to setup all the prerequisite relational goals#2018-12-1703:00normanWell, I was going to check out https://github.com/lambdaaisland/trikl based on an earlier recommendation of it a few days ago, but it’s not on clojars … 😞#2018-12-1703:12potetmnot on github either?#2018-12-1703:13potetmlooks like all of lambdaisland is gone#2018-12-1703:33normanI’m not sure, but it’s disappointing that the only way to consume a project would be deps.edn.#2018-12-1703:35potetmhow do you do that if it’s not on github?#2018-12-1703:35potetmlol nm — the link you provided has a typo 😛#2018-12-1703:41normanOh - that’s odd. Not sure how that happened… 🙂#2018-12-1704:01Average-userlook at this#2018-12-1704:01Average-userhttps://github.com/Yomguithereal/react-blessed#2018-12-1707:22lilactownI’ve run into a few broken things in react-blessed in the past that put me off of it 😕#2018-12-1704:09normanI think someone posted that too. I’m not in cljs for on the aoc stuff, which is where I wanted to try this. But, I think I’m going to try and find a way to try this at work for some tooling, since on most days I write more js than clj. (and we’re trying to find some places to re-introduce cljs)#2018-12-1707:24lilactownyou could clone it and install it locally#2018-12-1707:36normanYes, there’s many things I could do to work around the unfortunate decision, but none of them are very satisfying.#2018-12-1708:26normanDay 17 - my code really shouldn’t be this slow…#2018-12-1714:45mishaday 17, no transients, no deqs.
"Elapsed time: 150.130027 msecs"
"Elapsed time: 115.159781 msecs"
#2018-12-1715:33potetmHey! People who are learning clojure and doing AoC! Last week I did a code review on stream, and I found it to be a fun and interesting exercise. https://www.twitch.tv/videos/349004355?t=55m30s If anyone wants me to do the same for their AoC code, please let me know! I won’t do one every day (and I won’t do one today), but I’d like to do one a couple times a week if enough submissions roll in.#2018-12-1715:55norman150ms has me beat by … a lot. I’m doing one point per iteration and I’m running in 8min total. Besides filling more than one point per iteration, I’ll have to do a performance pass this morning for sure…#2018-12-1716:13mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day17.clj#2018-12-1716:15misha1 iteration is 1 Y step for me, after which you either backtrack to Y-1 (no outlets in one of the puddles), or descent to Y+1 (all puddles have at least 1 outlet)#2018-12-1716:19mishathere is a bit of waist, when, say, out of 5 puddles only 1 has no outlet, so next (backtrack) iteration you scan all 5 of those for outlets again (against new "walls" updated with settled water). But that's like 2 incs and 2 lookups per puddle, which is essentially 0#2018-12-1716:04borkdudeThese are the scores for Advent of CLJC so far. Note that I only implemented the scoring a few days ago, so I have to re-run a lot of solutions to be able to register a score. I might get to that in a couple of days. https://gist.github.com/borkdude/d7f42d4110e8a330d1d70f9242b14496#2018-12-1716:27ihabunekit took me WAY too long to do todays task#2018-12-1716:27ihabunekhere's a text visualization https://gist.githubusercontent.com/ihabunek/295c9ede42f0ce8e983ce9e5114979eb/raw/440e78df6d54ceb5b7de934b152feec55054b5c2/aoc2018.day17#2018-12-1716:27ihabunekyou'll need to zoom out#2018-12-1716:28ihabuneksolution here: https://git.sr.ht/~ihabunek/aoc2018/tree/master/clojure/src/aoc2018/day17.clj#2018-12-1716:28ihabuneknot very tidy but i need to work/sleep#2018-12-1717:59potetmhttps://www.twitch.tv/timpote#2018-12-1718:48pesterhazyI'm stuck on day17 p1 - my code works on the sample but not the full input 😞#2018-12-1718:49pesterhazyMy answer is too high: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle17.clj#L51#2018-12-1719:49Ben GrabowThe spring is at x=500, y=0. I'm not sure it matters but it looks like you might have the x and y values flipped? I see that your ordered-pairs are [y x], so that's fine, but I also see (visit [puzzle-min-y 500] :down) which doesn't seem right.#2018-12-1720:39pesterhazy@UANMXF34G I'm starting from [0 500] now, which should be correct#2018-12-1720:39pesterhazyI don't think that's it...#2018-12-1720:40pesterhazyI guess it's possible that the whole tree-walking approach is flawed and only happens to work on the small sample#2018-12-1720:45Ben GrabowI considered doing some kind of tree-walking thing until I realized that it's actually a DAG not a tree. Two outlets can fill up the same pond, so they need to know about each other.#2018-12-1720:48pesterhazyyeah I discovered that as well but thought if I remember whether the square was settled or not, I can re-use that information: https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle17.clj#L105#2018-12-1720:49pesterhazyI can't figure out where the flaw in the reasoning is#2018-12-1721:00Ben GrabowI wish I could help more, but it's really difficult to tell what you're doing inside visit. It would help to break it down into steps and pull a bunch of that code out into smaller functions.#2018-12-1721:00pesterhazyThis person has an (even more) imperative solution, with a similar approach to mine: https://www.reddit.com/r/adventofcode/comments/a6wpup/2018_day_17_solutions/ebyq6mj/#2018-12-1721:01pesterhazybut the logic is quite different#2018-12-1721:02pesterhazyyou're right that my visit function is a mess of course#2018-12-1719:36Average-userI was wondering if it would be possible to implement day 15 with core.async#2018-12-1722:35Ben GrabowAny tips for tracking down a stack overflow on LazySeq realization? I get to a depth of around y=800 before my algorithm dies.#2018-12-1722:39gklijsTry to use recur, https://clojuredocs.org/clojure.core/recur the extra calls are re-used so don't add up to the stack.#2018-12-1722:40Ben GrabowI am using recur everywhere, as far as I can tell.#2018-12-1722:40markwwhat specific line of code is causing the overflow?#2018-12-1722:41Ben GrabowHaven't tracked down the line of code yet. The stack trace gives me an endless sequence of
[clojure.core$seq__5124 invokeStatic "core.clj" 137]
               [clojure.core$concat$fn__5215 invoke "core.clj" 717]
               [clojure.lang.LazySeq sval "LazySeq.java" 40]
               [clojure.lang.LazySeq seq "LazySeq.java" 49]
               [clojure.lang.RT seq "RT.java" 528]
#2018-12-1722:43markwhave you created any lazy seqs yourself? or just using via built-in e.g. map, iterate etc.#2018-12-1722:43Ben GrabowNot rolling my own.#2018-12-1722:44Ben GrabowI am doing merge-with concat in several places to merge some maps. Since I see concat in the stacktrace I am suspicious of those.#2018-12-1722:44pesterhazyNever use concat with lazy-seq #2018-12-1722:45Ben Grabowhttps://gist.github.com/bgrabow/7641f00f27a2632b7e597116dab31eab#2018-12-1722:45pesterhazyit's a known footgun#2018-12-1722:45pesterhazyhttps://stuartsierra.com/2015/04/26/clojure-donts-concat#2018-12-1722:46pesterhazyI use into instead of concat wherever I can#2018-12-1722:58Ben GrabowWell it's a lot slower with into instead of concat, so maybe that's a good sign :rolling_on_the_floor_laughing:#2018-12-1801:51Ben GrabowIt took me the better part of the afternoon to notice that some of my outlets were getting duplicated, leading to O(2^n) runtime as the depth increased. I never tracked down the exact source of the duplicates, but I suspect it was related to multiple outlets feeding into the same pond. I took the lazy way out and turned my outlets data structure into a set.#2018-12-1806:13gklijsI 'killed' outlets when they would end up in a pool.#2018-12-1801:51Ben GrabowI think this is where my stack overflow came from, when I tried to concat some monstrously large lists of outlets.#2018-12-1801:52Ben GrabowFinally working though! https://github.com/bgrabow/advent-of-cljc/blob/master/src/aoc/y2018/d17/bgrabow.cljc#2018-12-1805:03norman@pesterhazy It’s probably a bit late, and maybe hard to implement with all that mutability, but if you can dump out your world state visually, it ought to be (relatively) clear where the problem is. Almost all my problems came from incorrectly deciding flow/rest, and it was usually easy to see exactly which squares were being decided incorrectly.#2018-12-1806:03normanI was surprised at the cycle time for 18#2018-12-1806:08baritonehandsMine runs really slowly, not sure the best way to speed it up#2018-12-1806:15baritonehandslike 100/sec#2018-12-1810:54meikemertschIf mine runs for 13s to give me the 100 entries after dropping 1000, ist that then slower than yours?#2018-12-1810:54meikemertschI am a beginner and want to know how slow I am :thinking_face:#2018-12-1813:08pesterhazysounds about the same as my (completely, proudly non-optimized) solution#2018-12-1807:49gklijsIt's game-of-life like, it will stay at a repeating pattern pretty soon probably.#2018-12-1807:55gklijsSpoiler from the kotlin slack, repeating pattern can take some time. https://streamable.com/2ud78#2018-12-1808:08fellshardMine was at ~500 steps, it pays off not to make assumptions about how early the cycle starts 😞#2018-12-1809:13pesterhazyloved this one - beautiful patterns#2018-12-1811:32ihabuneki animated mine in ascii#2018-12-1811:32ihabunekhttps://imgur.com/a/L3VZbO8#2018-12-1809:08pesterhazyMy day 17 https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle17.clj#2018-12-1809:08pesterhazyand my day 18 https://github.com/pesterhazy/advent2018/blob/master/src/advent/puzzle18.clj#2018-12-1809:09pesterhazyDay 18 was a breeze, but 17 I felt was horrible to implement in anything resembling idiomatic Clojure#2018-12-1809:10pesterhazyI ended up porting a Python based solution to Clojure (that is, Java with Clojure syntax)#2018-12-1810:23ihabunekfinally a relatively easy one. 🙂 went with elixir today, but if anyone wants to take a peek: https://git.sr.ht/~ihabunek/aoc2018/tree/master/elixir/lib/day18.exs#2018-12-1812:48mfikesA little late, but Day 17: https://github.com/mfikes/advent-of-code/blob/master/src/advent_2018/day_17.cljc Note, to run this, I had to increase the stack size in the JVM.#2018-12-1813:06pesterhazy@mfikes nice, you managed a purely functional solution for a problem lending itself to imperative solutions#2018-12-1813:07pesterhazyon the jvm btw the imperative (but still recursive) solution I posted doesn't blow the stack#2018-12-1813:11mfikes@pesterhazy Yes. If curious, I initially had it doing the spill left and right and putting both of those results into a map. That wasn't working on the real problem because it would branch out recursively too much (much like a naive Fibonacci), and wouldn't complete even if let run over night. The fix in this case was to take the results of spilling left and pass them into the function that spills right, eliminating the 2-way recursive aspect.#2018-12-1814:58pesterhazy@mfikes yes this is very interesting to me given that I tried, and failed, for a few hours yesterday, before going with a super imperative approach#2018-12-1814:59pesterhazykept me up all evening 🙂#2018-12-1815:06ihabunek@mfikes I'm finding your solution a little difficult to follow, since it's quite dense with logic, how well are you able to parse your own code e.g. an year from now?#2018-12-1815:07ihabuneki tend to break things into smaller functions and write some docs, for myself if noone else 🙂#2018-12-1815:07ihabunekbtw, my solution: https://git.sr.ht/%7Eihabunek/aoc2018/tree/master/clojure/src/aoc2018/day17.clj#2018-12-1815:08mfikesYeah, I agree; I didn’t have a chance to clean up day 17 to make it super readable.#2018-12-1815:09ihabunekah, it's always a matter of available time, and AoC is not too high priority for most people#2018-12-1815:09ihabuneki enjoy reading your solutions, since i usually pick up some tricks i haven't thought of#2018-12-1815:12mfikesMy opinion: The initial code you write is often not quickly grokkable because it is simply messy. Once you clean up the mess, it is still not quickly grokkable because it is using way to many words to say what it is saying. If you then golf it a little, you can improve understanding by using fewer bigger words to convey your idea. The balance is to not golf it too much were it becomes opaque. There is some sweet spot between overly verbose and overly golfed where I find code most readily consuable.#2018-12-1815:12mfikesSame thing happens with English (or any other writing)#2018-12-1815:14ihabunekfor more complicated problems i almost want to start the solution with a dictionary - explain what words mean in the context of the problem, for this one, i used "spring", "water", "flow" which are not exact but could be defined, and that would make the program easier to read#2018-12-1815:14ihabunek(if used consistently)#2018-12-1815:14mfikesYes, the right choice of names makes the code much more readily understanable.#2018-12-1815:15mfikesA well chosen name is better than a long comment explaining something 🙂#2018-12-1815:15ihabunekyes, very true#2018-12-1815:15ihabunekand also very difficult 🙂#2018-12-1815:15mfikesBut I agree, my day 17 is quite opaque right now 🙂#2018-12-1815:16ihabunekthere's only so much time available in a day#2018-12-1816:32potetmGonna have to cancel today’s stream. I should be back tomorrow.#2018-12-1818:07markw@ihabunek Peter Norvig always does that in his solutions (his PAIP book, Ipython notebooks etc) - always starts with "vocabulary" for the problem.#2018-12-1818:12ihabunekCool, I'll have a look #2018-12-1818:31pesterhazyFinding a vocabulary at the beginning requires a pretty good understanding of the problem space though#2018-12-1818:31pesterhazyWhich of course you don’t always have #2018-12-1818:35markw@pesterhazy Yeah that's a fair point - I think that's part of why it helps though... You have a chance to loosely sketch out the problem before starting to code it, and in some cases that can save you some trouble down the line.#2018-12-1818:35markwEveryone is different though, for me I can't start typing until I have my idea initially thought out, usually on paper#2018-12-1819:53Average-userMy day17 solution is too slow#2018-12-1820:40Average-user
adventofcode-clj-2018.day18> (time (part-2))
"Elapsed time: 29776.153121 msecs"
165376
#2018-12-1820:40Average-userHow long it takes yours?#2018-12-1903:05mishahttps://clojurians.slack.com/archives/C0GLTDB2T/p1545057939705200#2018-12-1903:05mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day17.clj#2018-12-1903:40misha2015 macbook pro, 2.2 i7#2018-12-1903:42mishaoh, I see you probably meant 18:
Loading src/adventofcode/2018/day18.clj... 
"Elapsed time: 197.051339 msecs"
"Elapsed time: 6098.122681 msecs"
Loaded
#2018-12-1821:08Average-userhttps://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day18.clj#2018-12-1822:08magic_bloatJust finished 17 - took ages, had to make too attempts. Annoyingly my first attempt was looking very close to being right, so I stuck with it for ages before bailing out and trying a new approach.#2018-12-1822:09magic_bloatDefinitely recommend taking the time to do a visualisation for these sorts of things. There's no way I would have spotted my bugs without drawing the pictures.#2018-12-1822:09magic_bloathttps://github.com/bloat/aoc2018/blob/master/src/net/slothrop/aoc2018/day17-2.clj#2018-12-1902:55Average-user@mfikes Your solution to day 17 running in jvm, throws stack overflow almost immediately#2018-12-1912:05mfikesRight, you need to increase the stack size to 2 M#2018-12-1902:57Average-userWorks fine with sample input though#2018-12-1906:02normanGot started late on day 19. First part was trivial. Part 2… Wait? Try and optimize code? Look for a trick? Hmmm#2018-12-1906:19Ben GrabowOh sweet release, done with day 15.#2018-12-1906:35normanSo, I had #19 spoiled. So dumb. Basically, everyone cheated, which is to say, everyone looked at their input, figured out what their input was doing, and solved that problem#2018-12-1908:12fellshardYou're basically supposed to break the assembly apart for this problem, I believe. There was a similar one like this last year.#2018-12-1908:12fellshardOnce you've 'decompiled' it, you can arrive at an answer in a much, much more reasonable manner.#2018-12-1908:39normanI didn’t get that far last year, but I’ve been warned about that one. I would feel better if the problem statement was “figure out what your code is doing and write that code” even if the amount of “work” is the same#2018-12-1908:54fellshardYou'll notice a similar pattern with several problems this year, at least: start small in part 1, then scale unreasonably high in part 2, forcing you to rethink / optimize.#2018-12-1906:38normanMaybe I should reconcile myself to this not being a programming challenge, but being a puzzle challenge in which you’ll write code to solve the problems. But that’s not really what I signed up for. At least day 15 was, in the end, still a programming problem.#2018-12-1906:40Ben Grabowhttps://github.com/bgrabow/advent-of-cljc/blob/master/src/aoc/y2018/d15/bgrabow.cljc#2018-12-1907:52mishayou could just not= it here: https://github.com/bgrabow/advent-of-cljc/blob/master/src/aoc/y2018/d15/bgrabow.cljc#L115-L121#2018-12-1907:59mishahttps://github.com/bgrabow/advent-of-cljc/blob/master/src/aoc/y2018/d15/bgrabow.cljc#L190-L196
(let [players (concat (repeat 10 :g)(repeat 10 :e))]
  (time (dotimes [_ 100] (not-empty (filter #{:e} players))))
  (time (dotimes [_ 100] (some #{:e} players))))
"Elapsed time: 0.537247 msecs"
"Elapsed time: 0.272839 msecs"
#2018-12-1908:01mishahttps://github.com/bgrabow/advent-of-cljc/blob/master/src/aoc/y2018/d15/bgrabow.cljc#L210 just (map-indexed vector)#2018-12-1906:43Ben GrabowI'm pretty proud of the way I did the pathfinding. Totally functional approach, and the pathfinding function itself is lazy, letting its caller decide when to stop searching farther. I am starting to really appreciate iterate with the termination condition farther up the call stack, instead of loop recur for these simulation problems.#2018-12-1907:42markwwell… there goes an hour. I misread the problem and thought that the initial register pointer was also the initial value of the pointer#2018-12-1909:38meikemertschinitial register pointer is the first row? what do you call the initial value of the pointer? I’m not sure if I might make the same error#2018-12-1907:43markwThat and forgetting to change the starting register pointer from the test input to actual input#2018-12-1907:44misha@norman "1h in" is late? d#2018-12-1908:40normanYes.#2018-12-1910:52ihabunektoday's task was very similar to last year's assembler thingy#2018-12-1913:22ihabuneki annotated the assembler code (major spoilers) https://gist.github.com/ihabunek/3ce189a597e207ee9f35ad2d5e82bcb6#2018-12-1914:30tayloryep, very similar to day 23 last year https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2017/23.clj#2018-12-1914:33ihabunekyeah, i solved that one, that's why today's was pretty easy for me 🙂 https://github.com/ihabunek/aoc2017/blob/master/resources/day23-annotated.in#2018-12-1913:41baritonehandsMy favorite for day 19 was that I had named all the functions on day 16, so the code was just:
(defn parse-line [line]
  (let [[opcode & args] (str/split line #" ")]
    (into [(symbol "aoc.dec16" opcode)] (map #(Integer/parseInt %) args))))
And to call just resolve the required symbol:
(let [[sym a b c] (instructions ip)
              op-state (assoc state ip-register ip)
              next-state ((resolve sym) op-state a b c)]
#2018-12-1919:59fellshardSame, was delighted that the code was so easily reusable.#2018-12-1913:42baritonehandsStill haven't figured out part 2#2018-12-1913:42baritonehandsI was able to speed it up 10K times, but it still didn't finish overnight#2018-12-1915:03namenuhttps://github.com/namenu/advent-of-code-2018/blob/master/src/year2018/day19.clj I had a tough time disassembling the code...#2018-12-1915:26benoitUnfortunately I had to stop adventofcode 😞 It was taking too much of my time as the problems got more complex. I would like to say I will do them later but I doubt I will 🙂#2018-12-1919:16ccannsame#2018-12-1920:00fellshardThe time crunch starts getting harder as it goes on. Glad you could join as far as you could!#2018-12-1915:28ihabunekthis year seems harder than previous#2018-12-1915:31taylorI had to stop too, between work and family the problems were taking too long 😞#2018-12-1917:56potetmhttps://www.twitch.tv/timpote#2018-12-1918:04markw@ihabunek I feel the same... I've done all years and this is by far the most difficult#2018-12-1918:37normanNothing this year strikes me as particular more difficult than last year - just longer and more puzzle-ish.#2018-12-1918:38normanBut, I have NOT done all the years, so maybe there has been a trend towards more difficult problems#2018-12-1923:10pesterhazyYeah pretty much stuck on day 19#2018-12-2000:00fellshardTrying to brute-force the second part?#2018-12-2006:02gklijsIf you print each step you can see a certain pattern. It could take very long for part 2 to complete if you don't change the program.#2018-12-2008:17pesterhazyOk will try that again#2018-12-2008:17pesterhazyI tried disassembly on paper but that wasn’t easy at all#2018-12-2004:04Average-userhttps://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day19.clj#2018-12-2004:05Average-userVery similar to day 23 of 2017#2018-12-2005:04normanDay 20… Where to begin…#2018-12-2005:59gklijsAt room 0,0 with 4 optional doors?#2018-12-2007:23normanThat’s it!#2018-12-2007:10fellshardQuite enjoyed this one. Had to backtrack a bit once I realized I was parsing into a difficult-to-wrangle format.#2018-12-2007:28normanAgain, my solution is really slow… It seems to be making progress, but…#2018-12-2007:57normanHmm. I had to cache/memoize a bit. That sped it up a lott, but It doesn’t feel like I should have needed to do that. Maybe it’ll be more obvious in the morning.#2018-12-2008:17normanI couldn’t sleep until I figured this out, despite being too tired to actually think. Whenever I alternate, push [pos, pattern] for each alternation onto the search stack, which can cause a lot of duplicate work to be done. Adding in the cache check reversed the duplication, which really shouldn’t have been there. That probably makes no sense to anyone but me, but I at least I can let myself sleep 🙂
#2018-12-2008:57mishamemoize + store set of visited rooms in each path:
"Elapsed time: 1402.048955 msecs"
"Elapsed time: 1255.330936 msecs"
#2018-12-2008:58mishagood thing, it is a "tree", not a graph#2018-12-2010:07fellshardInteresting, I didn't even check to see if any of the paths ever looped back on themselves#2018-12-2010:13mishaevery branch in examples is either terminates ))))$, or loops to the previous point (NEWS|)... after doing a circle#2018-12-2015:23normanI don’t think tracking the visited rooms is sufficient - you have to know you haven’t been to the same room with the same remaining pattern to search#2018-12-2019:43fellshardI'd recommend breaking the solution up into multiple stages. #2018-12-2009:03meikemertschArgh! All examples of part one work with my solution but of course the big one doesn’t 🙈#2018-12-2013:06meikemertschAh. I think I know what I did#2018-12-2009:07mishahad a different issue, massively misunderstood p2, and wasted like extra hour on it#2018-12-2010:13mishaevery branch in examples is either terminates ))))$, or loops to the previous point (NEWS|)... after doing a circle#2018-12-2018:39Average-user
(time (part-1))
"Elapsed time: 39457.156774 msecs"
3314
#2018-12-2019:08mishamemoize it, @lucaspolymeris#2018-12-2019:24Average-userDon't know what memoize could workhttps://paste.ofcode.org/iKWt9afh7cWZg5UtPWhXRq#2018-12-2019:28Average-userIf you analyze the code, the only function that takes real time is nodes-depth#2018-12-2019:44misha(filter (complement seen) (remove seen)#2018-12-2019:45mishamove might be used many times with same args#2018-12-2019:46Average-userI always forget remove, but will just change readability, not performance I think. But thanks anyways#2018-12-2019:47Average-usermove?#2018-12-2019:47misha(defn move [dir [x y]]#2018-12-2019:48mishaif you have shared seen - make it transient#2018-12-2019:48Average-userahh right. But the only function that uses move is build-graph. Which takes:
(time (count (build-graph (clean-input))))
"Elapsed time: 77.78829 msecs"
10000
#2018-12-2019:49mishaI tracked seen per branch, so could not make it transient, but my move repetitive usage is noticable#2018-12-2019:56misha
(reduce conj seen front)
                 (reduce conj ds (map (constantly depth) front))
into might speed these 2 up, since it does transient under the hood, if possible.
#2018-12-2019:58Average-userI might try to update neighbors, since I will never use one key more than once#2018-12-2020:01mishaso you are doing exhaustive search, and then - select?#2018-12-2020:06Average-usernot sure what you mean. nodes-length returns the minimum distance between the root and every other node#2018-12-2020:07Average-userinto doesn't change much btw#2018-12-2020:08mishabut you assign those distances to every known room first#2018-12-2020:46Average-userwell here is my day 20, is not that efficient but it is concise, I think https://github.com/Average-user/adventofcode-clj-2018/blob/master/src/adventofcode_clj_2018/day20.clj#2018-12-2021:06baritonehandsI like how it came using some string manipulation and the reader:
(defn parse-input [input]
  (-> input
      (str/replace #"[\^]" "[")
      (str/replace #"[\$]" "]")
      (str/replace "|" " | ")
      (read-string)))
[ENWWW (NEEE | SSE (EE | N))]
#2018-12-2021:06baritonehandsstill working on actually processing that for the solution though#2018-12-2021:08baritonehandsoops, left the regexes even though I no longer need them#2018-12-2023:49norman@lucaspolymeris I don’t think yours works. Try “^N(E|)N(E|)N$”#2018-12-2023:50normanor even “^N(E|)N”#2018-12-2100:23Average-userIm only with my phone now, I'll try it later. But there might be some off by ones errors in small inputs#2018-12-2100:33normanNo - it’s actually not your code, it’s that the stack based approach doesn’t work except for on the sample input#2018-12-2101:48Average-userIs not stack based#2018-12-2101:49Average-userI think is just a coincidence of names#2018-12-2101:49Average-userIt worked with my input (not sample)#2018-12-2100:19normanOr even ^N(N)N$#2018-12-2106:21normanI think I’ve lost interest in aoc entirely. I feel compelled to finish, but today is another non-coding puzzle. YAWN#2018-12-2106:35gklijsI don't like it eiher#2018-12-2107:46normanI’m going to sleep on part 2. Maybe I’ll care in the morning. Maybe not. Maybe this is how everyone felt after day 15.#2018-12-2108:08fellshardIt does take some code to get part two in a reasonable time. I don't mind as much that the puzzles take different forms; I end up using a lot of code to verify behavior, etc#2018-12-2108:13misha@norman I don't think ^N(N)N$ is a valid input (within day's rules): (N) does not loop back to where it started, so )N can't follow it.#2018-12-2108:15mishayeah, today's puzzle is meh#2018-12-2108:17mishastill waiting for today's (day 21) part 2 solution to finish 1st loop 💤#2018-12-2108:17mishaas I write this, it is done opieop#2018-12-2108:21mishasome day21:P2 stats to help others to debug:
instructions count: 2474020011
loop length: 10711
solution int: 13192622
"Elapsed time: 848641.379538 msecs" = 14 min (with prn, so slower than it is)
#2018-12-2108:47fellshardI started by building the graph in full, then doing a standard BFS w/ 'visited' set, and it completes almost instantly. Are you combining the parse with the search? And does the 'loop' assumption hold in all cases? #2018-12-2108:49mishaare you talking about day 21? : ) because I am. if "yes" how would you build instructions graph w/o simulation?#2018-12-2114:26fellshardOops, for some reason I thought this was about day 20 still. :) #2018-12-2114:59Average-userI'm starting doubt some section of my code for day 20. Would someone send me their input and expected results?#2018-12-2115:06mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day20.clj#L90-L96#2018-12-2115:21borkdudeNo solutions for Advent of CLJC day 15 yet. Was that a hard day?#2018-12-2118:25meikemertschThat was the elf-goblin battle. It was a ton of code to write. Looked like very many people disliked the problem.#2018-12-2923:10nikolahttps://github.com/nikolakasev/clojure-playground/blob/master/src/advent_of_code_2018/dec15.clj, feedback on readability is welcome, I'm learning Clojure while doing AoC.#2018-12-2115:22potetmjust long#2018-12-2115:23borkdudecurrently re-running solutions submitted so far, so their times are recorded#2018-12-2115:23borkdudehttps://circleci.com/gh/borkdude/advent-of-cljc#2018-12-2115:45borkdudeall scores so far. data science anyone? https://gist.github.com/borkdude/d7f42d4110e8a330d1d70f9242b14496#2018-12-2120:42norman@misha There wasn’t a rule that things had to loop back to where they started. It just simply happened that the input didn’t#2018-12-2120:42normanWhich is to say, to solve your input, you didn’t actually need to solve the programming challenge#2018-12-2201:24tbrooke@potetm — Have the old videos scrolled off of Twitch? — I’m still back on day 4#2018-12-2201:59potetm@tbrooke They have. I have the recordings I’m planning on posting on my site soon.#2018-12-2201:59potetmMy code is posted at https://github.com/potetm/advent-of-code#2018-12-2206:34normanHow I spent the last hour of my life:#2018-12-2206:34normantarget: 14,796#2018-12-2206:35normanOh, my region is 14796 x 14796…. That’s kind of big ….#2018-12-2206:35normansigh#2018-12-2206:39norman14x796 is much more manageable#2018-12-2207:46fellshardI'm gonna have to finish part two tomorrow; I don't think I can rely on creating a static graph with JGraphT, I need to be able to expand it on the fly. 😞#2018-12-2208:46normanThings I re-learned today: it’s really hard to memoize a recursive anonymous function….#2018-12-2212:38namenuIs day22 pt2... A* again?! 😨#2018-12-2212:39ihabunekseems so, but the map changes based on tool used#2018-12-2213:33mishawasted hours, and solution passing tests returns wrong result after 20 minutes dafuq#2018-12-2213:34mishareddit says dijkstra#2018-12-2213:56tbrooke@potetm - I’m still working on comparing my failed attempt at 4 with your solution - in looking back through the thread here I noticed you highlighted a discussion in #10 so I plan to jump around and go to #10— keep highlighting good ones or ones that follow others — I am at the level where I can get started but usually end up stuck with most of the problems and I need the video to get through#2018-12-2215:24normandjikstra (weighted BFS) works but is kind of slow. You may need to cheat the dimensions or use A*,#2018-12-2215:25normanI my new holiday spirit of of writing garbage code for AoC I did the the former, but I may switch over after I clean up and commit because it’s an interesting search problem#2018-12-2215:27normanI do like the twist of the tools here. I kind of makes a 2d grid into a 3d grid#2018-12-2215:30drowsyand representing it as a 3d grid actually makes the solution pretty straight forward.#2018-12-2215:31drowsyhttps://github.com/IamDrowsy/advent-of-cljc/blob/master/src/aoc/y2018/d22/iamdrowsy.cljc#2018-12-2215:32drowsythere's probably alot of potential to optimize, but it runs in about 2,5 secs for part 2#2018-12-2216:06normanYou beat me: “Elapsed time: 5045.311258 msecs”#2018-12-2217:03normanAnd it looks like your effective X search is larger than mine too… It looks like the main difference is I visit one node at a time and you visit all the nodes for time T at the same time, which seems to provide some efficiencies#2018-12-2217:21drowsyright I'm just storing which nodes are reachable after n seconds, advancing the seconds until the target is in this set.#2018-12-2217:30gklijsI'm not sure whether I have an off by one error, or my solution is 'better' than the approved one. The example runs correct, but on my data the output is 1088, while the accepted answer was 1089.#2018-12-2218:00normanMaybe you are really good at changing tools 🙂#2018-12-2218:01normanAre you allowing your search to go beyond the target [x y]?#2018-12-2218:27mishait would return longer path then, not shorter. I also got shorter results#2018-12-2218:46gklijsProbably a bug then. When I filter the routes more aggressively I do get the answer, and it's a solution that takes less steps.#2018-12-2220:29misha@drowsy used your approach of sets 1 distance at a time, after I wasted half a day waiting "per-xy" to complete, with all the different filters and sorting and stacks/lists/queues combinations.#2018-12-2220:34mishaand it doe not accept an answer kappa#2018-12-2220:50mishait is off by 4! can't even blame off-by-1™#2018-12-2220:58gklijsFrom a Kotlin slack channel came the awnser, apparently when you change the tool, it has to be valid in the current one. So for example you can't put away the torch in a rocky place to move into a wet place. Or put your rock climbing gear in a narrow area to move to a rocky one.#2018-12-2220:59mishahm, looking into it#2018-12-2221:02mishayep, that did it#2018-12-2302:36drowsy@misha yeah one of the important things is to have the set of what valids moves really are. Thats why the 3 dim solution really shines. It's easy to create a set of all the valid points of [x y tool] (including valid tool switches) and always filter you possible moves by them,#2018-12-2417:49mishathat's the line: https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day22.clj#L102#2018-12-2304:45fellshardUgh, finally finished day 15. That round-counting thing is a pain to weave in, I just ended up ignoring the edge case (last unit's turn finishes the match), and that worked fine for my input.#2018-12-2304:57fellshardAnd actually used earmuffs for the time to weave in the elf attack values! It's kinda gross, but I don't need to extend or maintain this later, so...#2018-12-2308:41normanI got a super late start today. Part 1 was trival. Part 2… seems like it’s too late for thatt#2018-12-2316:26Average-userFor day 23 part-2. I came up with something: In theory you can only check points that are in the surface of at least one sphere. The problem is that given a point (p) and a radius (r) the points that are in the surface of that sphere are in the order of r*r. and radius are quite large in the input#2018-12-2316:52gklijsThere is a theory the points with the most spheres coincide with one of the corners. But my data don't seem to support that..#2018-12-2317:01Average-usernot necessarily the corner, but with the surface of one. But yeah, I read some theories about corners being enough, but I don't think is correct#2018-12-2317:07Average-userWith my input the corners approach doesn't seem to work#2018-12-2317:16gklijsWith mine neither, but the surface is huge 😞#2018-12-2317:16Average-useryes is too much. Maybe the edges?#2018-12-2317:17Average-userThere are still huge though#2018-12-2317:19Average-userIm gonna try to find the best corner, and then walk to origin#2018-12-2402:07Average-userMaybe there is a way of transforming the set of points, into an equivalent one, with points closer and smaller radius#2018-12-2402:07Average-userAnd then check the surfaces#2018-12-2404:34fellshardI considered starting from a 'center of mass', maybe see if 'all nanobots weighted same' and 'all nanobots weighted by radius' made any sense#2018-12-2408:43gklijsI solved it now, by first picking the best corner, then from there looping both logarithmic and linearly till it doens't improve anymore.#2018-12-2411:17gklijsTurned out best corner had little value, just searching from the origin went almost the same time. 3 cycles more to find the correct answer, but not the 6000 evaluations to find the best corner.#2018-12-2415:10Average-userIn my case, there is no neighbor of the best corner that has is in range of the same or grater amount of nanobots, so a walk is not possible I think#2018-12-2417:35gklijsIt's no walk I do, it's about 13 cycles of jumping all over the place from 2^0-2^30 and that in all detections.#2018-12-2419:17gdevincenzihey folks! beginner clojurist here. If someone could give me a few pointers on how to improve my day 9 code, I would be very thankful. I can't seem to find a fast enough approach. https://github.com/gdevincenzi/advent-of-code-2018/blob/puzzle09/p09/zipper.clj#2018-12-2420:10misha@gdevincenzi "trick" to day9 was deque (double-ended queue) data structure#2018-12-2420:11gdevincenziI'm not sure how to implement one in a functional way, but will try to find out more about it#2018-12-2420:13mishasomeone has a deque implementation as a lib. I used mutable java one: https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day09.clj#2018-12-2420:13gdevincenzithanks 👍#2018-12-2420:14mishawas a very good reminder how actually careful you should be with mutable things, god bless rich#2018-12-2422:24gklijsYou don't need deque for day 9, it's just pointers forward, and sometimes you need to know witch state you where in to get back.#2018-12-2502:05Average-userThey are talking about day 9#2018-12-2511:51gklijsThat's what I meant#2018-12-2507:32normanAll done - hooray#2018-12-2507:40mishaday 23 2 harold#2018-12-2507:45normanHonestly, I lucked my way through that one at the repl. It’s the only one I’m not sure I could do from scratch again. I still don’t know what a correct algorithm is. 😞#2018-12-2507:55mishaI am reusing today's solution for 23/2 right now : )#2018-12-2507:55mishaat this point I'll accept anything under 30minutes, will see how it goes#2018-12-2508:09mishaout of 1000, 978 ranges intersect#2018-12-2515:22Average-user@norman Which algorithm for connected components did you use?#2018-12-2515:23Average-user(for Day25)#2018-12-2515:27normanFor search? Just a simple bfs https://github.com/orb/advent2018/blob/master/src/advent2018/day25.clj#L36#2018-12-2515:29normanI’m looking at ubergraph at the moment though https://github.com/Engelberg/ubergraph#2018-12-2515:30normanThat’s probably worth having in the toolbelt#2018-12-2515:36Average-usermy solution runs in 2s#2018-12-2515:38Average-useryours takes over a minute#2018-12-2515:40normanYeah. It was 1am when I got started. I’m really surprised it runs 🙂#2018-12-2515:40normanat all#2018-12-2515:40Average-user
(defn connected-with [x graph]
  (loop [gs graph, cs #{x}]
    (let [ng (mapcat #(get gs %) cs)]
      (if (empty? ng)
        [cs gs]          
        (recur (reduce dissoc gs cs) (reduce conj cs ng))))))

(defn find-connected
  "Graph should be a map from nodes to their neighbors"
  [graph]
  (loop [gs graph, ac #{}]
    (if (empty? gs)
      ac
      (let [[cs ngs] (connected-with (ffirst gs) gs)]
        (recur ngs (conj ac cs))))))
This is an algorithm to detect connected components of a graph that I came u with past year, since there also was a problem of finding connected components. Don't know how good is it. But I compared the time it takes with http://clj-me.cgrand.net/2013/03/18/tarjans-strongly-connected-components-algorithm/ . And there is almost no difference
#2018-12-2515:41normanAll the work in my solution is that nest for loop. O(n^2).#2018-12-2515:42Average-userI'm wondering if by some chance I accidentally implemented an already known connected components algorithm. Or something very similar#2018-12-2615:45misha
(defn distance [[x0 y0 z0] [x1 y1 z1]]
  (+ (Math/abs (- x0 x1))
     (Math/abs (- y0 y1))
     (Math/abs (- z0 z1))))

"Elapsed time: 9046.938164 msecs"
(defn distance [[x0 y0 z0] [x1 y1 z1]]
  (+ (Math/abs ^long (- x0 x1))
     (Math/abs ^long (- y0 y1))
     (Math/abs ^long (- z0 z1))))

"Elapsed time: 291.773856 msecs"
opieop
#2018-12-2616:36fellshardYep, I've learned to turn on reflection warnings so I can fix ones in the critical path. I know CIDER will point them out when it's enabled, other tools might as well#2018-12-2616:48thegeezI learned this lesson with ^Character on day 5: https://github.com/thegeez/clj-advent-of-code-2018/blob/master/src/advent2018/core.clj#L389#2018-12-2617:02misha@U06D9RGQM woah, you don't mess around with namespaces kappa#2018-12-2616:44normanI made the same discovery on the same function…#2018-12-2616:46norman(defn distance [p1 p2] (reduce + (map #(Math/abs ^int (- %1 %2)) p1 p2)))#2018-12-2616:48normanThis was day25 where there’s a 4th dimensions and the numbers were low. I guess long is probably better in general, and spliting out the operations would also give a speed up#2018-12-2616:54mishawas optimizing and cleaning up arjuns 23-2 solution here and there: https://github.com/arjun27/advent-of-code-clojure/blob/master/src/advent/2018/day23.clj https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2018/day23_2.clj#2018-12-2616:55misha@norman you can (defn distance [^ints p1 ^ints p2] there#2018-12-2617:29normanReally?#2018-12-2617:34normanI didn’t know ^ints was a thing, but it doesn’t help anything here#2018-12-2617:35mishaactually it is way slower, but primitive hint ^ints is for arrays of primitives#2018-12-2617:40mishaactually, ^ints even throws execution a bit off, as it expects it to be arrays, so having ^int and ^ints at the same time ends up being slower than just ^ints#2018-12-2617:13mishac++ guys are laughing at us opieop#2018-12-2618:53gklijsPerformance wise? On peak performance on some of the exercises the JVM might be faster.#2019-01-1221:55borkdudeTIL vector-of: https://clojuredocs.org/clojure.core/vector-of maybe this would come in handy for performance optimizations in Advent of Code?#2019-01-1222:39Chaseas part of my programming/clojure learning I was hoping to try out some advent of code problems. i followed the online communities as it was happening live and it seems super fun. how would you recommend a beginner to set up a project to do this? something like lein new app advent? Would you do that for each day or just once and then have like a day-1.clj file inside the src directory? Are the problems pretty advanced?#2019-01-1222:39Chasewhere do I put each day's input files?#2019-01-1222:42Chaseand I found a couple github's of various clojurians' solutions. is there anyone (or multiple) you would consider used simple, idiomatic clojure that a learner could learn from?#2019-01-1222:46borkdude@chase-lambert you can fork https://github.com/borkdude/advent-of-cljc/ and get started right away#2019-01-1222:51Chaseoh cool! And I'll get to learn about forking github projects. thanks!#2019-02-0515:41potetmnot sure who all pinged me re: VOD for my AoC stream (because of Slack history dropping)#2019-02-0515:41potetmthey’re now available: https://potetm.com/videos.html#2019-02-0515:42potetmapologies for the wait 🙂#2019-02-0515:48borkdudeawesome 🙂#2019-02-0520:17Chase@potetm Hey, I'm looking forward to checking these out! Right now, your site seems to be stuck at the loading phase. Not sure if this slack is sending too much traffic or something.#2019-02-0523:07potetm@chase-lambert Doubtful. It’s hosted on AWS S3+Cloudfront.#2019-02-0523:07potetmAre you on a particular video?#2019-02-0523:34ChaseIt works perfectly for me now, of course. Disregard!#2019-02-0602:04ChaseI'm already liking it, I think I'm going to take a crack at the day's puzzles myself before watching and then see the different approach.#2019-02-1118:18ChaseI still can't get past part 2 of Day 1. Lol! Yeesh. I was hoping I would be farther along in my skills by this point. Ok, hopefully this shows what I'm trying to get at:
(defn part2 [data]
  (loop [seen #{}
         freq 0]
    (if (contains? seen freq)
      freq
      (let [seen (conj seen freq)
            freq (reduce + (cycle data))]
        (recur seen freq)))))
#2019-02-1118:20ChaseI figure I have to keep a running tally of frequencies and then compare the current frequency to that. That made me think I probably want a set right because it can't have any repeats. Now that I write it out though, not sure that will be necessary. But something isn't working in my else clause (obviously the meat of the function). Any tips on where I'm going wrong here.#2019-02-1118:30dpsutton
(defn first-duplicate
  ([l] (first-duplicate l #{}))
  ([l seen]
   (let [[head & tail] l]
     (if (contains? seen head)
       head
       (recur tail (conj seen head))))))
make a function that does what you need. here's a simple loop until it gets something already seen
#2019-02-1118:32dpsutton@chase-lambert ^#2019-02-1118:46Chasethank you. I'll try and process this. Reflecting on the process, I'm realizing I just have a vague notion of some of these concepts and then just blindly flailing about it in the repl.#2019-02-1122:55potetmmy life tho#2019-02-1122:55potetmmy life tho#2019-02-1122:59potetm@chase-lambert I did a version of your approach here: https://github.com/potetm/advent-of-code/blob/master/src/advent_2018/day_1.clj#L32#2019-02-1122:59potetmYou can watch the vid here: https://potetm.com/video/aoc-2018-d01.html#2019-02-1200:26Chaseyep, that is still the plan! I will try to complete as much as possible for each day and then watch the corresponding video after or when I'm stumped hard. It was fun seeing you take a different approach than I did for part 1 and learn about mapv already. And I'm encouraged my approach for part 2 sounds somewhat on track.#2019-02-1214:56potetmOn the right track, for sure 🙂#2019-02-1217:41Chaseok, first video was awesome! Here are my questions and notes if you ever get a little time: 1) mapv : I didn't realize map was creating a lazy seq because my repl always gives me the result immediately. At a meta level is that something I should be thinking about more? Like, when could that be an issue, is there a time when I will have an error because map hasn't "realized" it's seq? 2) I used Integer. instead of Parselong I have mixed feelings on having so many different paths to the same result. Which is better for which scenario and is that just something gained with experience or is there a good best practices guide? 3) If I had known about reduced and reductions I think I may have solved it! I was pounding my head trying to figure out how to get each step of the reduce and have that be my freq (what you called acc). Good stuff! 4) I like your whole recursion v reductions v seq abstractions approach to idiomatic clojure. That being said, I love your part-2-reduce+seq the most. That one seems so clear and what I was trying to do in my head. The transducer stuff was over my head. I admit I was chuckling when you were doing the duplicates function and kept mentioning "don't worry about understanding the logic here, but you just need to flip this expression with this one." How can you do that without understanding the logic?! lol! 5) Just a couple general tooling things I observed that I was curious about: When you put in str/split-lines it looks like Cursive included the dependency automatically in your ns declaration. True? I wonder if Cider can do that. Since I only used split-lines once I just used the full ns version. I was going to ask your philosophy on that but I imagine that's partly dictated by it being done for you easily. Your bottom right frame. It seems to be acting like a scratch buffer connected to the same repl. Or is that just how Cursive's repl looks? Sorry for the book. Let me know if I should edit these down considerably or send as pm's. This channel doesn't seem to busy any more. This could be a great learning resource, thank you again!#2019-02-1217:44dpsutton1) lazy is usually fine. just never use a lazy sequence to do side effects. ie (map create-user [{:username "bob" ...} ...]) 2) from the javadocs, "The string is converted to an int value in exactly the manner used by the parseInt method for radix 10." so it seems equivalent. I kinda prefer a method named "parseX" because its a bit more clear what it is meant to do rather than the constructor. 3) will come in time. your arsenal grows each time you practice and read other code#2019-02-1218:06Chasethat all makes sense to me. thank you!#2019-02-1218:41Chasewait, maybe I am confused about something. In the solution I mentioned:
(defn part-2-reduce+seq []
  (reduce (fn [seen acc]
            (if (contains? seen acc)
              (reduced acc)
              (conj seen acc)))
          #{}
          (reductions + (cycle d))))
How is that (reductions + (cycle d) turning into the single value getting passed back into acc?
#2019-02-1301:49potetm@chase-lambert reductions terminates when (reduced acc) gets returned.#2019-02-1301:50potetm1) mapv is not lazy. It returns a vector immediately. map is lazy.#2019-02-1301:51potetmI mean, lazy evaluation is not something you should have to consider constantly, but you do need to know about it.#2019-02-1301:53potetmThe biggest gotcha is probably with side effects. For example, (map print [1 2 3]) — works in the REPL, won’t work in the middle of a fn.#2019-02-1301:55potetm2) (Integer. "123") and (Integer/parseInt "123") do exactly the same thing. You can confirm this in the Java source code.#2019-02-1301:56potetmI prefer Integer/parseInt & Long/parseLong because I find it to be more explicit.#2019-02-1301:56potetmI also default to longs instead of ints because that’s what clojure does.#2019-02-1301:57potetm3) Thank you!#2019-02-1301:58potetm4) I understood the logic 🙂 I thought about skipping it entirely, but it’s good to know that you can use existing clojure fns as a starting point for what you need to do.#2019-02-1302:00potetmfwiw - duplicates gets used quite a bit. I even introduced it into my professional code base not long ago and have used it multiple times there.#2019-02-1302:00potetmThe code might have been difficult to follow, but the abstraction is solid.#2019-02-1302:02potetm5) Yeah cursive inserts the ns require for me. I really don’t know anything about Cider.#2019-02-1302:05potetmYou must require namespaces before you use them. You got lucky because clojure.string is brought in by clojure.main.#2019-02-1302:07potetmThis is kind of a gotcha at the REPL, because things like clojure.pprint get required on REPL startup but not on clojure.main.#2019-02-1302:07potetmBest practice is to put all of your requirements in your ns declaration.#2019-02-1302:09potetm5.b) Yeah the bottom right is a REPL buffer. I don’t use it very often, but it can be nice for small one-off forms.#2019-02-1302:14potetmI’m glad you found it helpful! I’m more than happy to continue answering questions here. My only other thought would be reddit so people could search it via google later. Feel free to post a link/links and have discussion there if you like.#2019-02-1316:39ghadifyi (Integer. "123") is deprecated#2019-02-1316:40ghadiper the Java API#2019-02-1316:40ghadiInteger/parseInt is the sauce#2019-02-1316:50dpsutton@Deprecated(since="9") apparently the docs from java 7 are the top result. thanks!#2019-02-1316:58ChaseThis was all great information folks, thank you! Integer. is out. parse... is my new best friend#2019-02-1317:02ChaseI also like that defaulting to Long/parseLong because it's the clojure default. I think I found that Integer. method on an old stackoverflow answer#2019-02-1317:04dpsuttonwhat is the clojure default?#2019-02-1317:05ghadilong#2019-02-1317:06Chasepotetm mentioned above that he uses Integer/parseInt and Long/parseLong but between those two he would choose parseLong by default since that is what clojure uses.#2019-02-1317:07dpsuttonoh the default integer type for clojure. gotcha 👍. ( I was confused by what you meant by clojure default)#2019-02-1317:09Chaseif you really grilled me, I would be confused by what I'm saying too. hahaha#2019-02-1317:11Chaseok, you got me. What is the actual difference between a Long and an Int in clojure?#2019-02-1317:12Chasefrom what I can gather, Longs can be much larger?#2019-02-1317:13dpsuttonLongs are 64 bits and therefore in memory are much larger. The increased width can handle a larger range of values#2019-02-1317:14dpsuttonlongs are what the reader returns unless an even bigger size is required.#2019-02-1317:35Chasecool. I'm still in the newbie wonderment phase trying to grasp just how fast computers run all these damn calculations. It spits out the answer for that part2 problem we were discussing immediately. so fast.#2019-02-1317:37gklijsThere was someone solving ALL solutions in some milliseconds if I remember correctly, in C#2019-02-1317:38ChaseI saw that! The entire advent in less than a second. I've seen it in C++ and Rust. crazy stuff.#2019-02-1516:44Chaseso I solved part 1 of day 2 but it looks kind of hacky to me. Any suggestions?
(def data
  (->> (slurp "resources/y2018.d02.txt")
       (str/split-lines)))

(defn double-letter? [s]
  (some #(= 2 %) (vals (frequencies s))))

(defn num-of-doubles [coll]
  (get (frequencies (map double-letter? coll)) true))

(defn triple-letter? [s]
  (some #(= 3 %) (vals (frequencies s))))

(defn num-of-triples [coll]
  (get (frequencies (map triple-letter? coll)) true))

(defn part1 [coll]
  (* (num-of-doubles coll) (num-of-triples coll)))

(part1 data)
;; => 6200
#2019-02-1516:47Chaseand I'm struggling with part 2 again. I remember doing this simple spellchecker tutorial: https://www.bernhardwenzel.com/articles/clojure-spellchecker/ so was thinking this "levenshtein distance" could get me there. It's not working though as even the first string is saying it has a match with a 0 distance. But that isn't right. But now I can't get my brain off this strategy! If it continues to elude me I'll check out @potetm's video and other people's solutions. I'm thinking part 2's are going to be a bit outside my current ability but not sure when to call it and try to learn from others or keep fighting it. I don't know if spending days on one solution is fruitful at my level.#2019-02-1516:54erwinrooijakkersI remember I started with Levenshtein distance too but that was really slow#2019-02-1516:55erwinrooijakkersI implemented what the question asked for directly#2019-02-1516:55erwinrooijakkersCompare two strings character by character 😉#2019-02-1516:56Chasethat's actually been one of my fears. I actually technically solve a problem but don't realize it's so inefficient that I gave up on it too soon.#2019-02-1516:56erwinrooijakkersAnd I sometimes spent like more than a work day on an exercise#2019-02-1516:56Chasebut then maybe i should keep searching for a better solution anyways right? I think I read all problems should be able to be solved in less than 15 seconds or something.#2019-02-1516:57erwinrooijakkersGood to push yourself but if you get frustrated look for a hint 🙂#2019-02-1516:57erwinrooijakkersOr walk away for a bit#2019-02-1516:57Chaseyeah, i do take long walks. my version of "hammock" time#2019-02-1516:59Chasei'll mull over your approach about comparing two strings character by character. thanks#2019-02-1516:59erwinrooijakkers🙂 good luck!#2019-03-0421:17Mario C.@potetm Did you still have your videos from the advent of code?#2019-03-0421:34Chasehttps://potetm.com/videos.html Not to step on his toes or anything. The videos are great!#2019-03-0421:49Mario C.Thank you! I went on twitch but couldn't find the videos there. I thought he had removed them#2019-03-0423:19potetm@mario.cordova.862 They expire from twitch 😕#2019-03-0423:20potetmtook a while, but I eventually got them to my site — hope they’re helpful#2019-03-0423:20potetmfeel free to ping here w/ comments/questions!#2019-11-0816:22pesterhazyOnly 3 more weeks until AoC 2019. Who's in?#2019-11-0816:51gklijsNot sure yet, did them all last year, all with Java, some with Rust or Clojure. Want to do them all with Squeak this year, but not sure if I have enough time.#2019-11-0817:03borkdudeI'd really like to but I remember the past few Advent of Codes and it was a bit of a burden on my day job and sleep, so I think I'll skip this year, spending my free time on other side projects.#2019-11-0817:07spfeifferStill stuck somewhere in mid-2016 😉#2019-11-0820:03nateI'll likely do the same thing I did last year (and the year before)... peter out after about a week#2019-11-0822:59rjrayTough call. I loved doing 2018 (first AoC, and first time solving really obtuse problems in Clojure). But I'm more loaded-down this year (halfway through a Coursera specialization, working on a vanity-project website, and planning an April wedding), so I'm not so sure. Last year was mostly harmless, except for one day (the Rogue-like combat one, 15, I think?) that just wrecked me.#2019-11-0823:04potetmwe’ll see#2019-11-0823:23Mario C.@potetm Will you be doing videos of the solutions? If so plz let us know!#2019-11-0823:23potetm@mario.cordova.862 Can do!#2019-11-1115:50namenuI'm in #2019-11-1218:14fingertoeI will probably start at least.. @nate and I can compete to see who makes past problem 7.#2019-11-1219:30Mario C.Last year I was pretty new to Clojure when AoC came around. I want to see how I will fare this year after about a year and a half of experience with clojure 😅#2019-11-1420:43Björn EbbinghausSame procedure as every year. 1,5 weeks, until I notice that I am supposed to work. 😅#2019-11-2906:08mpcjanssenAnyone created a clojure leaderboard for 2019 already?#2019-11-2908:38pesterhazy@mpcjanssen I was thinking the same thing. Looks like there is adventofcode-clojurians from last year but not sure if they can be reused?#2019-11-2908:39pesterhazyI also tried to create a new one (for Berlin) but couldn't figure out how to create a named one - I can only create a private leaderboard without a name it seems#2019-11-2908:39pesterhazy:thinking_face:#2019-11-2908:56borkdudeboards can be re-used#2019-11-2908:59pesterhazyAlthough I'm still a remember, maybe some others want to join again? I don't remember the join code for adventofcode-clojurians#2019-11-2909:00pesterhazy@borkdude are you doing doing this year's in babashka ? 😃#2019-11-2909:05borkdude@pesterhazy lol... I'll probably spend my time improving babashka instead 🙂#2019-11-2909:07borkdude@pesterhazy from this channel's info: Happy Advent 2018! | https://github.com/adventofcode-clojurians/adventofcode-clojurians | Join the private leaderboard with code 217019-4a55b8eb#2019-11-2911:01pesterhazyAha! That’s easy:-)#2019-11-2912:52mpcjanssenI did it with crystal last year, this year in clojure. It's a good way to use a language for something real.#2019-12-0110:19pesterhazyFirst puzzle: https://github.com/pesterhazy/advent2019#2019-12-0111:04mpcjanssenMy entry: https://github.com/mpcjanssen/aoc2019#2019-12-0120:38dmarjenburghI didn’t know you could use Clojure in a Jupyter notebook. Nice#2019-12-0111:12mpcjanssenAlthough (iterate) seems perfect for this puzzle.#2019-12-0111:16namenuI've tried to induce recursion formula to get the sum of the sequence, but it was slower than I expected because it requires factorizations. 😓 https://github.com/namenu/advent-of-code/blob/master/src/year2019/day01.clj#2019-12-0114:10snorremdStarted with a transducer + recursive function solution for the second task. But after seeing the iterator based one I switched out the recursive function. https://github.com/snorremd/adventofcode2019/blob/master/src/day1.clj#2019-12-0114:57Chaseoh man, I was able to complete both parts in about 20 minutes today! Might not sound like much but this time last year, that would have been a tough ask. Thank you Clojure slack for all the help! That was so satisfying inputting correct answers on the first try. This is fun!#2019-12-0115:11Chasenow we shall see how quickly the difficulty ramps up#2019-12-0118:43meow
(def FILE "../data/1.txt")
(def data (~>> FILE file->lines (map string->number)))

;; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
;; Solve

(fn (step n) (~> n (quotient _ 3) (- 2)))
(fn (score n) (apply + (unfold negative? identity step (step n))))
(def A (~>> data (map step) (apply +)))
(def B (~>> data (map score) (apply +)))
#2019-12-0118:49dpsutton@slack1899 what language is that?#2019-12-0118:51kenjTIL you can’t just shove #(/ % 3) into a -> threading macro, even though you can normally shove functions that take a single arg. No idea why…#2019-12-0118:54kenjat this point I realize #(/ % 3) was unnecessary for a ->, but still 🤷#2019-12-0118:54dpsuttonBecause that’s expanded at read time to (fn [temp] ...) so it gets threaded as (fn thread-value [temp] ...)#2019-12-0118:56kenjahhh, that makes a lot of sense#2019-12-0118:56kenjthank you!#2019-12-0118:56dpsuttonProbably catches everyone at some point #2019-12-0119:04meow@dpsutton this is Racket but I couldn't help but snoop around the other Lisp channels I'm a part of#2019-12-0119:04meowI only use Racket for practicing algorithms and puzzles and toys#2019-12-0119:08erwinrooijakkersMine 🙂 https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day1.clj#2019-12-0119:10erwinrooijakkersAh iterate#2019-12-0119:14kenjwhat’s annoying is that since the mass->fuel calc is lossy, you get different results if you calculate on the fuel requirements for the sum of all mass, as opposed to calculating the fuel requirements for each module of mass and summing the fuel results#2019-12-0119:36kenj#2019-12-0119:37kenjI always realize how much I stink at Clojure after reading other people’s code 🙂#2019-12-0119:37kenjis there any real advantage to using transduce over reduce?#2019-12-0123:28potetmspeed & memory#2019-12-0123:29potetmfewer allocations for intermediate structures#2019-12-0123:30potetmbut unless you’re wanting to learn to use transducers, it doesn’t matter for this problem#2019-12-0123:42gbouvierMy transducer version took 3 times as long to run as my reduce version. Maybe with more data or fns in the transducer compose it would swing the other way?#2019-12-0200:37potetmway too little info to comment#2019-12-0200:38potetmpost a gist w/ the 2 versions + the method used to time?#2019-12-0202:16tbrooke@potetm Are you doing your videos this year?#2019-12-0202:55potetmIf I do, it’ll have to be after the advent season 😕
#2019-12-0202:55potetmtoo busy at the moment#2019-12-0203:57pepashey folks, I’m very new to clojure. decided to go through the advent of code stuff to get some practice! here’s day 1: https://gist.github.com/cellularmitosis/269d593919a7337219f8df7c5a5df648#2019-12-0204:59mpcjanssen@jasonpepas you might want to use quot instead of Math/floor. I had the same, but quot is easier.#2019-12-0205:30rutledgepaulvhttps://github.com/RutledgePaulV/aoc2019/blob/master/src/aoc2019/day2.clj#2019-12-0206:40Jett DurhamI suppose I ought to share my repo, given my current slot in the leaderboard 😅 https://github.com/thejettdurham/advent-of-code-2019-clj I’m a Senior Frontend Engineer working in React(+Native) by day, and wannabe Clojurist by night. I don’t have formal CS training, so Advent of Code gives me the opportunity to help fill in those gaps in the fundamentals. 😁#2019-12-0207:19fingertoe@mpcjanssen @jasonpepas I used int instead of quot or Math/floor without any problem.. Seemed to coerce a ratio to it’s next lowest integer.#2019-12-0207:57mpcjanssenWhat I like about the iterate based solutions is that they clearly separate the step function between states and the terminating condition. This is great for debugging.#2019-12-0208:38fellshardTrying to focus a bit differently this year. I'm solving for speed first, then focusing on visualizing the problem/solution. This has a side-effect of encouraging me to find CLJC solutions for rapid porting to the Quil sketch host. http://www.quil.info/sketches/show/0622589e4acd61f73d86eff09064deff308553905d58dfc10448cf244ce9fa24 http://www.quil.info/sketches/show/d804ff390bc3f0bf59ba151699b5930e82158efc95765b5c81f188eec0e648a3#2019-12-0208:45mpcjanssen@fellshard that is very cool#2019-12-0209:18pesterhazyMy second puzzle: https://github.com/pesterhazy/advent2019/tree/master/src/advent#2019-12-0209:23pesterhazyI have a feeling that Intcode will stay with us for a while#2019-12-0210:31karlismy solutions for the day: https://github.com/skazhy/advent/blob/master/src/advent/2019/day2.clj second one took two coffees to figure out without bruteforcing 😄#2019-12-0211:49dmarjenburghCan you explain? Why is the output linear in the noun variable?#2019-12-0212:51karlisafter some testing I noticed that if I change is constant if I bump the "noun" variable#2019-12-0210:33fingertoeMy solution: https://github.com/jreighley/aoc2019/blob/master/src/aoc/aoc2.clj I suspect my handling of the 99 op code passed my tests but needs some further thought Not used to the mutation risk..#2019-12-0213:46tschadyhttps://github.com/tschady/advent-of-code/blob/master/src/aoc/2019/d02.clj#2019-12-0213:59dpsuttonis there a mistake in day2 examples? 1,1,1,4,99,5,6,0,99 becomes 30,1,1,4,2,5,6,0,99 it highlights the 30 and the 2 as new values. but there can only be one single instruction run because position 5--the second opcode-- is a 99 and the machine halts?#2019-12-0222:57fingertoeIt’s sorta Greek to us Clojurists, but mutability causes that 99 to be replaced by a 2.#2019-12-0223:01fingertoeI am pretty sure by code didn’t think that through either.#2019-12-0214:11rutledgepaulvthe first step is to replace 99 with 2. add registers 1 and register 2 and put into register 4 (5th position)#2019-12-0214:15dpsuttonthanks. i did a partition-by 4 rather than allowing for dynamic instructions. part 1 still worked 🙂#2019-12-0214:26mishaI assoced to (state res-idx) rather than to res-idx and part 1 worked too. I wonder if that was a deliberate trap or unintentional.#2019-12-0214:30Average-userhttps://github.com/Average-user/adventofcode-clj-2019/blob/master/src/adventofcode_clj_2019/day02.clj#2019-12-0216:01misha
(def enum-pairs
  (letfn [(pairs [i] (map (fn [j] [j (- i j)]) (range (inc i))))]
    (mapcat pairs (range))))
wtf opieop
#2019-12-0220:44genmeblogLooks like (quite not optimal) list comprehension. I would use for here. Especially when we know that > Each of the two input values will be between 0 and 99, inclusive.#2019-12-0306:20mishait is lazy infinite positive quarter of a xy plane. Sweet, but yeah, ranges are known, so for is more readable and sufficient here#2019-12-0306:52Average-userI wasn't sure if those values where necessarily bounded. But yeah.#2019-12-0217:50genmeblogAnd mine https://github.com/genmeblog/advent-of-code-2019/blob/master/src/advent_of_code_2019/day02.clj#2019-12-0219:54chrisblomMine for day 1 and 2: https://github.com/ChrisBlom/advent-of-code/tree/master/src/adventofcode/2019#2019-12-0221:02Alex JacksonHi all, I'm using aoc to learn me some clojure this year. here's my solution for day 2: https://github.com/jacksonal/advent-of-code-2019/blob/master/src/advent_of_code_2019/day2.clj any comments or criticisms welcome. I've never written a line of clojure outside of messing around in the REPL a little bit. I especially struggled with figuring out how to best use (for) although it sounds like there is a non-brute force solution.#2019-12-0221:11genmeblogHi Alex. Some use of language comments. 1. def should go outside your defn. Use let inside your functions. 2. for can be combined into one. This way you can avoid flatten 3. (nth seq 0) equals first 4. I think in this task subvec is not necessary. 5. Instead of vector use just [] 6. (into (vector) map ...) can be substituted with mapv#2019-12-0221:12genmeblog7. (not (nil? x)) can be substituted with (seq x)#2019-12-0221:13Alex Jacksonah cool these language comments are great. thank you#2019-12-0221:14fingertoeNice looking code. The only serious “Beginner” hallmark that I see is the user of the def inside of the int-compute function. It’s pretty rare to see a def within a defn — usually we use let bindings in that spot. I think most folks would use the def on it’s own to slurp the input data, then pass that as an arg to the int-compute.#2019-12-0221:14tschady :let and :when in the for loop can help clear it up#2019-12-0221:15tschady
(defn part-2 [input]
  (let [magic-output 19690720]
    (first (for [noun  (range 100)
                 verb  (range 100)
                 :let  [tape (run-tape input noun verb)]
                 :when (= magic-output (first tape))]
             (+ verb (* 100 noun))))))
#2019-12-0221:15genmeblogAlso, since a lot of code is already around, take a look at it.#2019-12-0221:19genmeblog8. One more advice (nth vector k) can be replaced by (vector k) eg. ([0 1 2 3 4] 3)#2019-12-0221:38val_waeselynckAlso consider using destructuring on op-seq, and case rather than (if (== ...)). = should usually be favoured over ==.#2019-12-0221:41val_waeselynckhttps://clojurians.slack.com/archives/C0GLTDB2T/p1575321553081900?thread_ts=1575320523.080100&amp;cid=C0GLTDB2T Some consider this bad practice though. It's clever, but may be overly general, obscuring the type of vector and increasing the risk of breakage.#2019-12-0221:43val_waeselynckhttps://tonsky.me/blog/readable-clojure/#2019-12-0221:56genmeblogYes, yes, in general you're right. But in this case, when code is short and vector type is used consciously it can be helpful.#2019-12-0222:00genmeblogAnyway. In contests like this plenty of performance tricks will be used to make algorithms efficient enough. Some of such ticks can be considered bad style.#2019-12-0306:27misha
(get [] 1)
=> nil
(nth [] 1)
Execution error (IndexOutOfBoundsException) 
([] 1)
Execution error (IndexOutOfBoundsException) 
#2019-12-0222:06rjrayAs long as we're sharing repos: https://github.com/rjray/advent-2019-clojure#2019-12-0300:58Sam NMy day 2. Based on other solutions, I need to learn to use for a bit better, but happy overall. https://github.com/SNordlinger/advent2019/blob/master/2/clj/src/comp.clj#2019-12-0301:21bentrentMy day AOC (up to day2) : https://repl.it/@ben_w_trent/aoc2019 Lessons learned: (for [x (range 99) y (range 99)] [x y]) Did not know about for for generating sequences 😄. I was doing some super complex combinatorics and thought that there HAD to be a better way. Glad there is#2019-12-0302:19taylorAlso beware range is exclusive upper bound but I think the problem calls for inclusive range#2019-12-0302:20bentrentAh, cool. Well, my solution was under 99 :).#2019-12-0302:28taylorSame 😌#2019-12-0302:20dpsuttonday 2 was a bit simpler since there was only multiplication and addition involved. and they chose quite easy numbers to solve it#2019-12-0303:06dpsuttonpart 2 is a particularly nice way to add core.logic as well#2019-12-0303:25potetmorder of operations tripped me up at the end#2019-12-0303:25potetm#lisplyfe#2019-12-0303:25potetmI’ve brain-dumped all order of operations rules#2019-12-0303:25mnespor
(ns advent.day02.day02
  (:require [clojure.math.combinatorics :as combo]))

(def blah (combo/selections (range 100) 2))
#2019-12-0308:55erwinrooijakkersGets only half the combinations 😉#2019-12-0315:47mnesporIt gets 'em all, doesn't it?
advent.day02.day02> (combo/selections (range 3) 2)
((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2)
#2019-12-0303:51kenjone thing that came up in my brute force search was it wasn’t clear what the best way to break from the search was. I ended up using some, but is there a better way to basically do:
for i in coll:
  if i == search_item:
    return i
#2019-12-0303:52kenjthus avoiding searching the rest of the collection?#2019-12-0303:52kenjI’ve read the docs a bunch of times and :when and :while still confuse me for for#2019-12-0308:55erwinrooijakkersI did like this: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day2.clj#L37#2019-12-0308:56erwinrooijakkersfor is lazy so when you get the first it terminates early#2019-12-0319:38kenjI thought since sequences are lazy, they might "chunk"? After thinking about it, I think that might be true even for my some usage. The only way to avoid chunking is using reduce/`reduced`, or maybe bypass chunking with lazy-seq?#2019-12-0322:23erwinrooijakkersWhy would chunking be a problem?#2019-12-0402:49kenjBecause chunking would eval until 32 possible matches are found, or the source coll is exhausted, then first returns to first one. This would be the opposite of termination at the first found.#2019-12-0304:15tschadyreduced can exit early from a reduction#2019-12-0304:31fellshardOoh, good idea re: core.logic. I'll have to try it, definitely cleaner than for ...#2019-12-0304:39lilactown@risinglight one thing you can take advantage of is the fact that for is lazy#2019-12-0304:39lilactownSo instead of “breaking” from a for loop, you instead can read each element from the sequence it produces until you get your result#2019-12-0304:40rutledgepaulvusually if i want to break i’d reach for loop/recur, or as mentioned reduce/reduced#2019-12-0304:41lilactownugh I can’t remove the preview on mobile#2019-12-0304:43lilactowngithub .com/Lokeh/advent-2019/blob/master/day2.org#part-2 (pasting it again so that Slack won’t show the rich preview... which I can’t delete on mobile)#2019-12-0304:47lilactownreduced is also fine but if your data can be reasonably done using for, then take-while is usually a better answer than turning to reduce and reduced#2019-12-0304:54kenjtake-while seems like the wrong thing for what is essentially a find of a single item. some I guess is good enough, I was just annoyed I had to modify the pred to rerun the found value https://github.com/KennyMonster/aoc_2019/blob/737ec52c74fea4dc42f856b6b69cb73588e016ba/src/day_2.clj#L66#2019-12-0304:55kenjWould be nice to have the predicate just be a predicate in this particular case #2019-12-0305:00mchampineAnd… we’re off!#2019-12-0306:24misha@alex.lee.jackson aoc is not a good way to learn clojure. Maybe the first puzzle of each day is, but most of the 2nd ones steer you towards the loop recur pretty consistently, if you don't want to wait for results forever.#2019-12-0307:16namenuloop recur can be decomplected into state & reducing function. I'm curious if you prefer loop recur over a sequential approach. or is it only desireable on 2nd ones for performance reason?#2019-12-0307:34mishait ends up being the same amount of eager code, same early termination, a bunch of state "variables", but reduce is 2 things, 1 of which now has a very hairy fn signature and loads of destructuring#2019-12-0307:41mishabesides, most reduces are implemented via loop recur under the hood, so might as well just skip the middle man (especially in context of average aoc part 2 puzzle)#2019-12-0308:24namenuthanks for the explaination! 🙂#2019-12-0308:36mishanp. but if reduce fits nicely (whatever that means in the moment) - use it!#2019-12-0308:40fellshardFor me, depends on how much state I'm juggling. Too much and I'll reify it as a reduce fn.#2019-12-0308:56mishawow, I tend to loop too much coupled state instead. (in context of aoc. in another context: too much coupled state usually means you have issues somewhere else)#2019-12-0313:42genmeblogI checked my last years code and never used any loop. I used recur sometimes, once custom type to speed the things up. But never needed to use loop/recur. I suppose that what's crucial is a selection of best matching data structure to the problem and to the Clojure.#2019-12-0306:31rjrayDay 3 done. This has escalated.#2019-12-0306:31mishajust a bit#2019-12-0306:33mishacan't even hear CPU fan noises on take-while kappa#2019-12-0307:29mchampineDone. Whew. Thank goodness part2 was a small increment if you chose the right grid representation.#2019-12-0312:10yendawhich one did you chose? I went with a map of sets and changed it to a map of map for the part2 which was a small change#2019-12-0316:02mchampineI used a simple list of x,y pairs. Once I had the intersections I could just drop everything after that point and the remaining points were the path length. #2019-12-0316:12mchampineThat is, for each intersection point search the full path (ordered list of points) for it. All the points before it are the length of the path to get there. The shortest path wins.#2019-12-0308:39fellshardhttps://github.com/armstnp/advent-of-code-2019/blob/master/src/advent_of_code_2019/day3.clj http://quil.info/sketches/show/3045c99a9e8afbecc5e229977f6a828c0747e3073eb54b45111cd5e3717aa7db Using line segments instead of points made for easier viz, but harder solving. Heh.#2019-12-0309:49misha
:when (not (and (= (first segment-1) [0 0])
                (= (first segment-2) [0 0])))]
can be just (disj [0 0]) from all collisions 2 lines below
#2019-12-0309:51mishabesides, how do you know that [0 0] is only first in segment? and that lines do not go through [0 0] ever again#2019-12-0310:12fellshardThe problem statement explicitly says to ignore it. Otherwise, definitely just an assumption. 🙂#2019-12-0310:31mishayeah, it says ignore [0 0], but I mean, you assume it appears only on segment start, and no segment ends at [0 0]#2019-12-0310:32mishaso segment [[0 -2] [0 -1] [0 0]] might leak [0 0] into collisions set#2019-12-0315:48fellshardIt might; one of the keys to AoC is figuring out which assumptions you can make safely, sometimes the hard way. Sometimes your solution only works for your input, just because it doesn't challenge that particular assumption. The primary reason I expect there's no [0 0] collision is that it would be a 'trivial solution' to part 1, too easily accidentally guessed for a quick leaderboard time, even if by a fraction of people; that's just not how he operates.#2019-12-0308:39fellshardWhoops, left my reminder comment at the top#2019-12-0309:31mpcjanssenpart2 was actually easier today#2019-12-0309:35mpcjanssenProbably because I am storing separate points on the line#2019-12-0310:27uoslMy solution for today's part2 is sloow: "Elapsed time: 7919.040046 msecs" I'm getting flashbacks from last year when my part2 solutions were too inefficient to compute in time 😓#2019-12-0311:06mishastick transient in there kappa#2019-12-0312:13yendaor rather rethink your datastructures#2019-12-0312:15yendamine takes 75ms with maps#2019-12-0312:47uoslWould you mind sharing your solution? I'm curious how it looks with maps.#2019-12-0317:21yendahttps://gist.github.com/yenda/fcc8ae88ef5318b966b450bc7ed7802b#2019-12-0312:17yendadid you go with some lists/vectors?#2019-12-0312:25uoslyes, I went with a vector of all the coordinates for a line, then turned it into a set for running intersection#2019-12-0312:28mpcjanssensame here and same perf#2019-12-0312:44genmeblogfinally, day3 done https://github.com/genmeblog/advent-of-code-2019/blob/master/src/advent_of_code_2019/day03.clj#2019-12-0314:18mpcjanssenI am doing everything on my phone this year, would be much more difficult with other other languages. But works great with clojure and jupyter#2019-12-0314:19mpcjanssenInteresting (positive) side effects, I make more granular functions and think more before starting to type.#2019-12-0314:20genmeblogHardcore coding 🙂#2019-12-0314:22mpcjanssenHoliday time waster 🙂#2019-12-0314:24mpcjanssenLet's see how long I can keep it up#2019-12-0314:24genmeblogWriting anything on the phone (even simple messages) is so inconvenient that I can't even imagine editing the code.#2019-12-0314:25mpcjanssenThe trick is to type less (so think first) and a good soft keyboard helps.#2019-12-0314:25genmeblogFor sure. The idea to think more before typing is always beneficial#2019-12-0314:45tschady2019 day 3 is similar to 2016 day 1. Just absolute moves instead of relative turns. I wound up putting that code into a aoc.grid library.#2019-12-0316:52pesterhazyhaha, already planning ahead for 2020! 🙂#2019-12-0315:17fingertoeGot the first part done — running 500-700 ms. Traded the leaderboard points for sleep. Will finish part 2 later today..#2019-12-0319:00Mario C.Just finished day 3. This one was tedious. Gonna look at other solutions. I modeled my solution based on lines (two points) and intersections (points). Perhaps it may have been easier to build a grid.#2019-12-0322:34erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day3.clj not a masterpiece - don’t see how to improve the clojure or the performance. NOTE: peek instead of last to get last element of a vector led to running twice as fast.#2019-12-0323:01genmeblogNice solution. But I see you were lucky. Intersections can have negative coordinates and you should sum absolute values rather than filtering negative results (see manhattan distance definition).#2019-12-0323:05erwinrooijakkersAha so sum absolute values and remove zero?#2019-12-0323:05erwinrooijakkersThanks 🙂#2019-12-0323:25tschadydid you try using clojure.set/intersection and measure the performance? curious.#2019-12-0409:16erwinrooijakkersOh I did not#2019-12-0409:16erwinrooijakkersI will try that 🙂 hehe#2019-12-0409:16erwinrooijakkersDidn’t think about that#2019-12-0411:02erwinrooijakkersInitial: “Elapsed time: 1323.049568 msecs” With clojure.set/intersection “Elapsed time: 861.311297 msecs” 😉#2019-12-0411:02erwinrooijakkersFor part 1#2019-12-0323:15Average-userhttps://github.com/Average-user/adventofcode-clj-2019/blob/master/src/adventofcode_clj_2019/day03.clj#2019-12-0400:01fingertoeWasted a lot of time on silly misplaced parens error on this one. 😉 https://github.com/jreighley/aoc2019/blob/master/src/aoc/aoc3.clj#2019-12-0400:55Average-userHave you tried parinfer or parindent?#2019-12-0401:02fingertoeI use cursive and parinfer. It was my distance function that added the absolute values of the two vectors. Since it was all on the same line, it didn’t help
(+ (abs x)) (abs y)
instead of
(+ (abs x) (abs y))
The function was returning the correct number on the y deltas but 0 on the x deltas…
#2019-12-0402:03mpcjanssen@erwinrooijakkers nice tip, using peek instead of last shaved 500ms of the 7s.#2019-12-0403:04normanI'm getting a late start. Are we using the same leaderboard as last year?#2019-12-0404:28Average-userYep#2019-12-0403:05norman(or I could just look at channel topic, I suppose)#2019-12-0403:13dpsuttonI haven’t seen the same style this year @norman #2019-12-0403:15kenjOnly made it through part 1 of day 3 while slacking at work towards the end of the day… no one noticed the Clojure instead of Python on my screen 🤷 https://github.com/KennyMonster/aoc_2019/blob/c2dfdfffdc4447c34aa6a7c90b0a763d10da8713/src/day_3.clj#2019-12-0403:59fellshardThere's some days when I've needed a break to do some real programming and get my brain moving again before going back to 'real work'. So long as it hasn't cut into the hours I'm contracted to bill, anyway. 🙂#2019-12-0406:04namenusame here. puzzles are being opened amid of my work time 🤫#2019-12-0405:55mchampinePuzzle 4 was way easier than the last two. I count 8 lines of code for Part 1, with a single line altered to adapt the part 1 solution to part 2.#2019-12-0406:20mchampineActually, just a single character change for part 2. I have a test for repeated digits that looks like this: (some #(<= 2 (count %)) (partition-by identity (str n)) For part 2, just changing the “<=” to “=” was sufficient.#2019-12-0406:29mpcjansseni used frequency on the list of digits#2019-12-0406:33yuhanStill find it awesome how lisps allow you to do things like #((case part 1 <= 2 =) 2 (count %))#2019-12-0406:35mchampine@mpcjanssen ?? You mean frequencies? But that doesn’t care about order, so I don’t see how it would detect sequential duplicates differently than non-sequential ones..#2019-12-0406:37mpcjanssen@mchampine you are right. it did give the right answer though#2019-12-0406:37mchampineSurprising!#2019-12-0406:37mpcjanssenno because the digits are increasing#2019-12-0406:37mpcjanssenso any same digits are consecutive#2019-12-0406:37mchampineAhh.. got it.#2019-12-0406:38mchampineGood call.#2019-12-0406:38mpcjanssenrationalisation after the fact 🙂#2019-12-0406:38mpcjanssendid not completely think this through before#2019-12-0406:38lilactownyes the duplicate check can be pretty dumb if you take advantage of that#2019-12-0406:39lilactownI still used dedupe though for part 1#2019-12-0406:39lilactownhttps://github.com/Lokeh/advent-2019/blob/master/day4.org#2019-12-0409:57uosl
#(apply <= (digits %))
Damn, so simple!
#2019-12-0411:29yendawhy do you divide by 10000 though I don't get it why not something like (<= 100000 x 999999)#2019-12-0411:30yendaor (= 6 (count (str digits)))#2019-12-0415:55lilactownthe first one would probably have been better, yeah#2019-12-0415:56lilactownI wanted to avoid converting to a string if possible#2019-12-0406:45mchampineWow, using spec. Neat. Btw, you can do a quick and dirty digits conversion with (map read-string (map str (str 123456)))#2019-12-0406:52fellshardhttp://quil.info/sketches/show/4350261fceb6f0e6f385e23fcd9a8ca91623ffd813912ca79c47bfa51ad1a6f1#2019-12-0406:54mpcjanssenalso nice literal coding with org-babel#2019-12-0406:55mpcjanssenthe environments are as interesting as the code itself#2019-12-0406:57mpcjanssenfor mine https://github.com/mpcjanssen/aoc2019/blob/master/day04.ipynb#2019-12-0407:06mchampineYes, tried org-babel a while back. Pretty great stuff you can do. I was mixing bash, python, clojure, and LaTeX as I recall.#2019-12-0408:05dmarjenburghTodays one went pretty smooth https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L65-78#2019-12-0408:52karlisapart from the somewhat vague description for puzzle #2, today was quick & easy: https://github.com/skazhy/advent/blob/master/src/advent/2019/day4.clj#2019-12-0410:17roman01lahere’s mine https://gist.github.com/roman01la/c607849e71e6de11549976428cd3d6a6#2019-12-0410:51genmeblogOh, this is so great solution. Clever. I overcomplicated a thing this time.#2019-12-0411:15mpcjanssenSmart regex for increasing#2019-12-0412:28roman01laregex turned out to be much faster than parsing and comparing digits#2019-12-0414:26mishaI did (= (seq s) (sort-by identity compare s))) 10 times slower than regex#2019-12-0410:18roman01la@karlis indeed, it took me a while to decypher description of the 2nd part#2019-12-0410:33karlisneat use of frequencies! That's a method I only seem to use during advent of code 😄#2019-12-0411:29Charles FourdrignierTry a first time with "filter wrong values", but my predicates were pretty bad, so my evaluation "never" finishes. I re-write it in a dirty (but successful) way. https://github.com/Charlynux/advent-of-code-2019/blob/master/day04/day04.clj#2019-12-0413:02taylorI think each year there are a few problems like day 4 pt. 2 that seem almost intentionally vague… https://github.com/taylorwood/advent-of-code/blob/master/src/advent_of_code/2019/4.clj#2019-12-0415:31James AdamMine is ugly, but it works: https://github.com/rhinoman/aoc2019/blob/master/src/aoc2019/day4.clj#2019-12-0416:02tschadybug in num-to-digits for 0.
user=> (num-to-digits 0)
[]
#2019-12-0416:48James AdamIt doesn't like it when the first digit is 0#2019-12-0415:31jrwdunham@taylor nice digits func to convert an int to a seq of digits without string manipulations. I would have never thought to do it that way#2019-12-0418:38taylorthe only other place I’ve ever used this is in coding interviews lol#2019-12-0415:32James Adam@jrwdunham my solution initially used string manipulation, I got about 10x speedup when I cut out all of the type conversions 🙂#2019-12-0416:14misha
(time
  (let [MIN      382345
        MAX      843167
        int-vec  (fn [n] (->> n str (map str) (mapv #(Integer/parseInt % 10))))
        low      (int-vec MIN)
        high     (int-vec MAX)
        too-low  #(neg? (compare % low))
        in-range #(neg? (compare % high))
        pwds     (for [a (range 0 10)
                       b (range a 10)
                       c (range b 10)
                       d (range c 10)
                       e (range d 10)
                       f (range e 10)
                       :let [n [a b c d e f]]
                       :when (->> n frequencies vals (some #{2}))]
                   n)]
       (->> pwds
         (drop-while too-low)
         (take-while in-range)
         (count))))
"Elapsed time: 13.145288 msecs"
=> 290
#2019-12-0416:14mishatroll#2019-12-0416:16mishaJames'es times on my input and laptop are: "Elapsed time: 159.510294 msecs" "Elapsed time: 324.308817 msecs"#2019-12-0416:19misharoman's times: "Elapsed time: 227.731395 msecs" "Elapsed time: 172.91049 msecs"#2019-12-0416:31Mario C.Day 4 part 2 was written very poorly.#2019-12-0416:31uoslvery cool. using for like that to avoid the intermediate numbers#2019-12-0416:32Mario C.Not too fond of the 10 mins wait after submitting x number of wrong answers#2019-12-0416:34mishabtw, I understood part 2 immediately by looking at examples, don't know why so many were confused. (however, there were few similar requirements in previous years' puzzles, so I might have just recognized it)#2019-12-0418:41taylorI had a solution that worked for all the examples but not for my test input; took me like 6 submissions to get it right#2019-12-0416:35uoslsame here. although I tend to jam the examples into my tests before I think too much over the problem description#2019-12-0416:35Mario C.I thought I did too until my answers were wrong#2019-12-0416:35Mario C.222222 should or shouldn't be valid?#2019-12-0416:35uoslshouldn't#2019-12-0416:36uoslmaybe you're unlucky and got input data with an extra edge case#2019-12-0416:36Mario C.repeating 2 and its not apart of a larger group#2019-12-0416:36Mario C.its the only group#2019-12-0416:36uosloh no, now I'm confused. it should be#2019-12-0416:37uoslthere must exist at least one consecutive group with a length of 2+#2019-12-0416:37uosl^ this is part 1. part 2 is exactly 2 instead of 2+#2019-12-0416:37mishaalso this is why I did not use frequencies initially, because I recalled "2 but not 3+ in a row", and thought of letters, and did not figure out that there can only be 1 streak per digit, and can't be e.g. 11xx1x.#2019-12-0416:37mishaI think it should not, because it is more than 2 in a row#2019-12-0416:39misha@regen "at least one 2+" for part1, "at least one exactly 2" for part 2#2019-12-0416:40Mario C.Should 123455 work?#2019-12-0416:40mishayes, for both#2019-12-0416:41misha*unless outside the range#2019-12-0416:41Mario C.But isn't the 55 part a larger group of repeating?#2019-12-0416:41mishagroup is just same digit several times in a row#2019-12-0416:41Mario C.same reason 123444 didn't count#2019-12-0416:41misha444 is a group of 3: three 4 s in a row#2019-12-0416:42mishaconsecutively#2019-12-0416:43misha(partition-by identity coll) gives you groups : (partition-by identity "123444") => ((\1) (\2) (\3) (\4 \4 \4))#2019-12-0416:43Mario C.Thats not how I understood it. Which was my complaint since it was left up to interpretation#2019-12-0416:43Mario C.I figured 333444 should work#2019-12-0416:43Mario C.since the 33 or 44 are not part of a larger group#2019-12-0416:44Mario C.but you are making the case that it wont work since they are both groups of 3#2019-12-0416:45mishagroup of 2 is two of the same digits in a row. larger group is tree or more of the same digit in a row#2019-12-0416:45mishaI am, yes. 333444 should be invalid#2019-12-0416:45mishabecause it has 2 groups of size 3 each,#2019-12-0416:46Mario C.the two adjacent matching digits are not part of a larger group of matching digits.I understood this as: As long the repeating digit is not part of the largest group of all groups then it is valid.#2019-12-0416:47Mario C.So 122333 is valid and so would 222333#2019-12-0416:48Mario C.but not 123444 since the repeating digit is part of the larger group#2019-12-0416:48mishayes. here, 33____ and 33__ are two adjacent matching digits but both are part of a larger group of matching digits 333___#2019-12-0416:48mishasame for 44_ and _44 in 444#2019-12-0416:48genmeblog122333 is valid because has 22.#2019-12-0416:49Mario C.222333 has two groups. Each of size 3 meaning there is no larger group. Since they are both the same#2019-12-0416:49misha122333 is valid, because there is only 2 2 in a row, 222333 in invalid, because there is 3 2 in a row#2019-12-0416:50genmeblogNo, there are two larger groups.#2019-12-0416:50misha. (map count (partition-by identity "122333")) => (1 2 3) ;; has group of exactly 2 numbers (map count (partition-by identity "222333")) => (3 3) ;; does not have group of exactly 2 numbers#2019-12-0416:51Mario C.There we go. They should have just written that ^#2019-12-0416:51Mario C.> does not have group of exactly 2 numbers#2019-12-0416:52mishathis is why people here bragged about "part 2 was just 1 char diff commit!": (->> ... (some #(<= 2 %))) for part 1 and (->> ... (some #(= 2 %))) for part 2#2019-12-0417:02Mario C.Not for me. I kept thinking "Oh I get it now." Type the answer in and getting "Sorry wrong answer. Plz wait 10 mins before submitting again."#2019-12-0417:02Mario C.But wasn't going to bed until I got the goldie#2019-12-0417:02Mario C.first part was easy though#2019-12-0417:03mishahappened a lot to me in other puzzles. It is not in the aoc interests to make it obvious to you what needs to be done, hence lots of text, indirection in terminology, random bold font highlights, "by the ways", ambiguous examples#2019-12-0417:04jrwdunhamI wrote a crazy regex to get dec4/pt2 which i'm sharing for laughs. (Liking the concise and sane strategies I'm seeing here):#2019-12-0417:04jrwdunham
(def pattern
  (re-pattern
   (str
    "("
    "(^|[^1])11($|[^1])"
    "|"
    "(^|[^2])22($|[^2])"
    "|"
    "(^|[^3])33($|[^3])"
    "|"
    "(^|[^4])44($|[^4])"
    "|"
    "(^|[^5])55($|[^5])"
    "|"
    "(^|[^6])66($|[^6])"
    "|"
    "(^|[^7])77($|[^7])"
    "|"
    "(^|[^8])88($|[^8])"
    "|"
    "(^|[^9])99($|[^9])"
    "|"
    "(^|[^0])00($|[^0])"
    ")")))
#2019-12-0421:02fingertoeI always feel like I am cheating when I use regex. That never stops me from being tempted. (Including today)#2019-12-0417:05mishazeroes are invalid here opieop#2019-12-0417:05jrwdunhamright. still works though.#2019-12-0417:05mishabecause you filter them out earlier/later#2019-12-0417:06jrwdunhamfilter them out earlier, with yet another regex#2019-12-0417:06jrwdunham(filter (fn [d] (re-find #"(.)\1" d)))#2019-12-0417:06jrwdunhamoh, nevermind, that doesn't do it...#2019-12-0417:07mishaI'd like to see concise pattern including all of it: range, group size, ascendingness#2019-12-0417:07Average-userhttps://github.com/Average-user/adventofcode-clj-2019/blob/master/src/adventofcode_clj_2019/day04.clj#2019-12-0417:08Average-useradventofcode-clj-2019.day04> (time (part-1)) "Elapsed time: 19.688852 msecs" 1605 adventofcode-clj-2019.day04> (time (part-2)) "Elapsed time: 23.650609 msecs" 1102#2019-12-0417:10mishaslower and less readable kappa#2019-12-0417:28Average-userYep, i didn't thought about using for. But my solution is more general (not only for six digit length numbers)#2019-12-0417:28Average-userAnd is only slightly slower#2019-12-0417:45mishaof course! hence the trollface in my snippet )#2019-12-0417:07yuhan@misha I did a similar optimization to only iterate through non-decreasing digit-vectors 🙂
(defn incr [ds]
  (let [d (peek ds)]
    (if (= 9 d) ;; recursive
      (let [ds* (incr (pop ds))]
        (conj ds* (peek ds*))) ;; roll over using prev digit
      (conj (pop ds) (inc d)))))

(iterate incr [1 4 6 8])
;; => ([1 4 6 8]
;;     [1 4 6 9]
;;     [1 4 7 7]
;;     [1 4 7 8]
;;     [1 4 7 9]
;;     [1 4 8 8]
;;     [1 4 8 9]
;;     [1 4 9 9]
;;     [1 5 5 5]
;;     [1 5 5 6]
;;     ...)
#2019-12-0417:08Average-useradventofcode-clj-2019.day04> (time (part-1)) "Elapsed time: 19.688852 msecs" 1605 adventofcode-clj-2019.day04> (time (part-2)) "Elapsed time: 23.650609 msecs" 1102#2019-12-0417:08jrwdunhamhttps://github.com/jrwdunham/aoc2019/blob/master/src/dec04/core.clj#2019-12-0417:08mishayeah, but anything in user space is likely to be slower than for opieop#2019-12-0417:12yuhanI replaced the nested for clauses in your solution with (for [n (iterate incr [0 0 0 0 0 0]]) and got a 13.5 msec => 9.0 msec speed up#2019-12-0417:14mishawhat is incr? inc?#2019-12-0417:15yuhanthe recursive function I posted above#2019-12-0417:16yuhan(not great at naming things)#2019-12-0417:17mishais it consistent speed up? do you consistently get 13ms on my snippet? for me it fluctuates +-2ms#2019-12-0417:18mishaor did you just compare 9ms on your machine to 13 on mine? troll different code too!#2019-12-0417:19yuhanBoth on my machine with the same inputs#2019-12-0417:20mishanice#2019-12-0417:11jrwdunham@misha my un-aptly named monotonically-increasing? filter seems to be correctly filtering out the 0s#2019-12-0417:12mishaI pointed that out so you could speed up regex#2019-12-0417:13jrwdunhami see. See any way to make the regex more concise, with backreferences and lookahead/behind fanciness?#2019-12-0417:14mishanot even gonna try d#2019-12-0417:14jrwdunhamhaha.#2019-12-0417:14jrwdunhamYes, also not fast: part 1: Elapsed time: 485.806268 msecs; part 2: Elapsed time: 578.42914 msecs.#2019-12-0417:16jrwdunhamtaking out the 0s disjunct in the regex speeds things up by 50-100ms#2019-12-0417:18roman01laFor speed AND idiomatic code it's probably better to do it in Rust#2019-12-0417:20mishafor is idiomatic :)#2019-12-0417:46yuhangot it down to 3.6 ms using transducers 🙂 (measured using Criterium's quick-bench)#2019-12-0417:49yuhan
(defn day4
  [start end part]
  (let [dv     (fn [n] (mapv #(Character/getNumericValue %) (str n)))
        dv<    (fn [a b] (= -1 (compare a b)))
        startv (dv start)
        endv   (dv end)
        incr   (fn [ds] ;; increase digit vector until it satisfies non-decreasing condition
                 (let [d (peek ds)]
                   (if (= d 9) ;; recursive
                     (let [ds* (incr (pop ds))]
                       (conj ds* (peek ds*))) ;; roll over using prev digit
                     (conj (pop ds) (inc d)))))
        pw?    (fn [xs]
                 (some #((case part 1 
#2019-12-0418:00lilactownwow nice!#2019-12-0418:17jrwdunhamNice @qythium, about 1msec faster than @dmarjenburgh’s solution in my timing.#2019-12-0420:02normanDoing AOC last year was so much easier when I was on vacation for almost the entire month. I have a feeling I'm going to be playing catch up all month...#2019-12-0420:29fellshardYeah, I may need to curb my participation for a while. Too busy.#2019-12-0420:29fellshardBut I feel better about it knowing that I'm not aiming for leaderboard points. I'll learn what I'm aiming to, just more slowly.#2019-12-0421:21fingertoeSimple enough: https://github.com/jreighley/aoc2019/blob/master/src/aoc/aoc4.clj It’s not too often that I use ns without a :require. The separated-pairs? fn seems a bit hacky, but effective.#2019-12-0503:36dpsuttontypos and misreading just murdered me on part 1 of day 4#2019-12-0503:41dpsutton> 111122 meets the criteria (even though 1 is repeated more than twice, it still contains a double 22). i can't fathom how this meets the rule? "the two adjacent matching digits are not part of a larger group of matching digits". Aren't the two adjacent 1s that start the number part of a larger group of 4 matching 1s?#2019-12-0503:48fellshardThere just has to be a pair in the number that is not part of a larger group#2019-12-0503:49fellshardIt's 'exists', not 'all'#2019-12-0503:49fellshardThe 1s do not satisfy the condition, but the pair of 2s do#2019-12-0503:55dpsuttonThe two adjacent 1s are part of a larger group of 1s#2019-12-0503:55dpsuttonOh I see#2019-12-0503:55dpsuttonUgh#2019-12-0503:58kenjThat through me off as well for a good while
#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 lasts 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-0809:42pesterhazyI suspect that today's (relatively straightforward) puzzle is laying the foundation for future image-related puzzles#2019-12-0812:36erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day8.clj Is there a nicer pattern than reducing with a state parameter in the accumulator (as in (reduce (fn [[result highest :as acc] e] (if (> e highest) [(new-state e) e] acc) [nil 0]) )?#2019-12-0812:49mishaif you already use group-by on every layer, then just frequencies and sort-by it instead#2019-12-0813:48erwinrooijakkersThanks indeed 🙂#2019-12-0819:42chrisblommin-key and max-key can also come in handy in such situations#2019-12-0909:02erwinrooijakkersWow indeed. No need to sort-by and then first 🙂#2019-12-0909:03erwinrooijakkersBetter name would be max-by and min-by as mentioned in https://www.spacjer.com/blog/2016/01/12/lesser-known-clojure-max-key-and-min-key/#2019-12-0909:06erwinrooijakkers#2019-12-0819:42chrisblomhttps://github.com/chrisblom/advent-of-code/blob/master/src/adventofcode/2019/day08.clj#L19#2019-12-0820:49pastafari#spoiler for some. I went old school to figure out the letters 🙂 This is not necessarily a spoiler for everyone, there's a bunch of random inputs per the sub-reddit!#2019-12-0821:53mishanever even heard of min-key, and it was added in 1.0, wow#2019-12-0905:28Mario C.I was afraid of this. Another intcode problem >.<#2019-12-0905:53yuhanit feels like these Intcode problems favour imperative languages which can just bash at a mutable Turing machine tape 😕#2019-12-0905:55fellshardPerhaps. But you can always find ways to express it more neatly in Lisp. 🙂#2019-12-0905:55fellshardSeems likely to be the last, though, because we've now been told we have 'a complete Intcode computer' ...#2019-12-0905:55fellshardUnless we start making more chains of the things#2019-12-0905:56yuhanI wonder when there'll be a lambda calculus based puzzle 🔥#2019-12-0905:58fellshardIt is neat to see which bits of existing instructions I needed to make more robust#2019-12-0905:58fellshardMy memory access functions got abstracted away from the vector representation hard in this problem#2019-12-0906:00yuhanYeah, it was a really neat testament to Clojure's Associative abstraction that I could just substitute my vector representation of the tape with a hash-map, and pretty much zero refactoring#2019-12-0906:06fellshardI just ended up extending the vector if setting beyond range#2019-12-0906:07fellshardBut if it was truly sparse memory access, I'd definitely have to push it to either a map or a bunch of map-indexed blocks (0-999, 3000-3999, etc.)#2019-12-0906:07fellshardBut I reaaaally didn't want to go full B-Tree 😛#2019-12-0906:07fellshardAnd it seemed to work fine#2019-12-0906:14yuhanAll I did was v -> (into {} (map-indexed vector v)) , solved a NPE by giving get a default value, and everything else automatically worked, it was quite magical#2019-12-0906:16mpcjanssenmuch longer run time?#2019-12-0906:17fellshardShouldn't be, since you're only modifying one entry at a time; should be mostly reused per each tick#2019-12-0907:02fellshardHmm. The visualization's getting to the point where it's minimally useful, I suspect. And the size of the vector's making re-rendering every cell each frame rather prohibitive.#2019-12-0907:51mpcjanssenargh , reading opcode 9 adjusts the base#2019-12-0908:13fellshardhttp://quil.info/sketches/show/a86e31254e4e2b7275aa6363279390b7d369d44b0dfd5d6da33f8039e9163fb9 - Color only, since the memory size is far larger and it starts slowing down frames - and don't have the time to implement a 'dirty cells only' routine#2019-12-0909:45mpcjanssenhmm seems i keep failong the input test. opcode 203 this should store the input relative to base right?#2019-12-0909:49gbouvieri.e. if base is 10 and the instruction is 203,-5 store the input value in index 5#2019-12-0909:50gbouvierIt is a postition, I messed this up by trying to store at the index of the value at index 5.#2019-12-0917:52pastafariThis has been painful even on Day 5, but destinations are always to be treated as values!#2019-12-0909:48uoslI'm having the same problem, with the puzzle input outputting 203. I've tried storing the input at many different ways, but no luck#2019-12-0914:09Average-userIt happened the same to me, I was forgeting to implement mode 2 for write arguments of opcodes 1 2 3 7 8#2019-12-1120:36uoslThanks! After looking at your message and my code a few hundred times I finally got it working [=#2019-12-0909:48rjrayFunny, I'm stuck at the same point.#2019-12-0909:54mpcjanssenseems very likely#2019-12-0909:54mpcjanssenso a target has also rel to base addressing#2019-12-0909:55gbouvierIf the quine works for you (with it's 204), maybe try another simple example? 109,12,203,-5,204,-5,99 Simply appends the given input and outputs it.#2019-12-0923:21erwinrooijakkersThanks#2019-12-0909:55mpcjanssenso you take the immediate value and add it to base for 203#2019-12-0909:57mpcjanssenyep thats it#2019-12-0909:58mpcjanssensame change is needed for all storing ops#2019-12-0910:00gbouvier👍 Nice, I'm not sure how to think about this. Up until today, I was treating outputs as a special case and always using the immediate mode. Today, after refactoring, I realized I could handle my args as always pointing to a position and just pointing to the argument position in the case of immediate mode. Makes it so I can handle all the args generally, and operands (as opposed to outputs) are just fed through an additional (nth) right before they're needed, but for an output, they're already representing the positional value.#2019-12-0910:01mpcjanssenyes! part 1 done#2019-12-0910:06mpcjanssenthe target adress behavior has been a source of pain in all intcode puzzles#2019-12-0910:06mpcjanssenpart 2 is trivial after part 1#2019-12-0910:07gbouvierYeah, I wonder if it's even possible to finish part 1 and not be able to complete part 2.#2019-12-0910:18meikemertsch😂 I ran to work after completing part 1. I couldn’t complete part 2 so far 😂#2019-12-0910:22gbouvierI guess the tests in part 1 aren't adequate then.#2019-12-0910:25meikemertschI meant that I literally saw the message about getting the star and left without even reading part 2 😉 I did that on my way and will have to wait for tonight to get back to my code#2019-12-0910:27gbouvierAhh, that makes sense. In this case at least, it shouldn't be a lot of work for you to finish part 2.#2019-12-0910:28meikemertsch😁#2019-12-0910:29meikemertschsounds like using different input and go get it… a shame not to have done it directly. 🤷:skin-tone-2: but I was already late for real life 😉 And I have seen problems before that also seemed to only need a different input but then created out of memory errors and such… (see e.g. 2016, day 16)#2019-12-0916:26fellshardIn the Reddit thread, he said it should be a freebie, but part 2 might find some wrinkles in your implementation.#2019-12-0913:05tschadyI don’t understand what makes day 7 p2 halt#2019-12-0913:08meikemertschI had the same problem#2019-12-0918:54pastafariwhen all the amplifiers have halted the circuit is halted?#2019-12-0919:33meikemertschyepp#2019-12-0913:05tschadywhy not feedback forever? Or do the outputs start to decrease?#2019-12-0913:09meikemertschtry this thread, if you want the same explanation I got: https://clojurians.slack.com/archives/C0GLTDB2T/p1575701095380500#2019-12-0913:12tschadygot it, thanks#2019-12-0913:13meikemertsch:thumbsup::skin-tone-2: you’re welcome. This made a solid knot in my brain 😂#2019-12-0913:38tschadyfeels like the job - spend more time trying to understand requirements than writing code#2019-12-0913:48meikemertsch😂#2019-12-0914:28Charles FourdrignierGot the same problem. :D @U1Z392WMQ Is it ok now ?#2019-12-0921:09tschadyhaven’t tried yet, day job. I think it’s more about blocking when you’re expecting input, writing out current state, then resuming when you have some. I’m not going to do channels, I think it should work.#2019-12-0921:10tschadybut honestly, I missed that from the requirements wholly#2019-12-0921:14Charles FourdrignierYou're on the right way, but be careful to meaning you put behind "blocking". For the requirements, in my first (and probably second and third ^^) read, I miss this sentence. > If the amplifier has not yet received an input signal, it waits until one arrives.#2019-12-0915:21potetmya’ll#2019-12-0915:21potetmclojure is so great#2019-12-0915:21potetmwe it said we needed non-contiguous memory#2019-12-0915:21potetminstead of a vector for state, you can pass in a map#2019-12-0915:21potetmdone#2019-12-0915:22potetm(I was using subvec, so I did have to change to map over a range. But everything else Just Worked™.)#2019-12-0915:48mpcjanssenHow did accessing elements not in the map just work and give 0?#2019-12-0916:13meikemertschget/get-in allow for a default value if an entry in a map doesn’t get found (see <https://clojuredocs.org/clojure.core/get-in> for reference)#2019-12-0916:16mpcjanssenI switched from vector to map and indeed I had to add a default 0 to all direct map access. I was just curious if I missed something like a default non existing value#2019-12-0916:28potetmNo, but it was trivial. I shadowed get in my let binding.#2019-12-0916:28potetmhttps://github.com/potetm/advent-of-code/blob/master/src/advent_2019/day_5.clj#L20#2019-12-0922:32mpcjanssenAh smart#2019-12-0916:36roman01laGotta catch up with all of you, here’s my day 8 https://gist.github.com/roman01la/7e505fa83e74b4730d74f096f6172fff#2019-12-0916:58James Adam@potetm I cheated -- I still passed in a vector, but did a (into [] (concat program (take 999 (cycle 0)))) and just kept increasing the amount of 0s I was adding to the "memory" vector until it passed. I did this because I'm lazy and I hate the vm problems in AOC.#2019-12-0917:04mishaso "memory starting at 0" is not a looping indexes around, zzz#2019-12-0917:11potetmI just assumed it was gonna blow out any arbitrary pre-fill#2019-12-0917:14mishaI tried wrap first: (- idx (count mem)), but then just moved on with my life kappa#2019-12-0919:21pastafariThe broken test outputs from the BOOST program were super helpful to narrow things down.#2019-12-0919:30rjrayNo kidding.#2019-12-0919:30rjrayFINALLY have this done. All I will say, is that part 2 is trivial once you have part 1.#2019-12-0920:05chrisblomMy day 9: https://github.com/chrisblom/advent-of-code/blob/master/src/adventofcode/2019/intcode.clj#L80 I also forgot to set the mode for the write parameter, too bad the tests did not detect it.#2019-12-0920:20pesterhazysame problem with relative writes for me - Eric could have mentioned that in the description#2019-12-0920:20pesterhazyI assumed that because mode 1 doesn't exist for writing, only mode 0 does - but that's not the case#2019-12-0920:21pesterhazydefensive coding (checking that the mode is well known in the code for set) would have caught this#2019-12-0920:22pesterhazyit's interesting - type checks or unit tests wouldn't really have helped here, although a simple (asset (= mode 0)) would have#2019-12-0920:24fellshardYeah, I had to run back to day 5 to check the wording of how output addresses are handled; he didn't say 'they are always positional mode', but rather 'they are never immediate mode'#2019-12-0920:26pesterhazyYou could say it's a trap 🙂#2019-12-0920:24pesterhazyMy day 9, if anyone is curious in a Typescript solution: https://github.com/pesterhazy/advent2019/blob/master/typescript/src/puzzle09.ts#2019-12-0920:25pesterhazyModern Javascript shines here, with bigints and generators#2019-12-0920:25pesterhazy(By choosing JS/Typescript I'm getting out of my comfort zone deliberately)#2019-12-0921:03pastafariHere's my solution: https://github.com/pastafari/adventofcode/blob/master/advent-2019/src/advent_2019/sunny_with_a_chance_of_asteroids.clj#2019-12-0923:24erwinrooijakkersWith help from the hints here (thanks) about read and write mode I managed to finish: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day9.clj Could be shortened if numbers could be turned into IFns that look themselves up in a map, but I read that that’s not possible in Clojure (but that it is in cljs)#2019-12-1004:46misha(map-indexed (fn [i v] [i v]))
(map-indexed vector) 
#2019-12-0923:24erwinrooijakkersI thought this C-program was quite impressive: https://topaz.github.io/paste/#XQAAAQC8AwAAAAAAAAARmknGRw8TogB3OyPPwW5K8Q8ohQvj8m6aN9NF2fZ8/o142/5WV7MqG8RTK2VSNa3x2bM8/7SYpXtGF4Efk4b3Z0SBAAazyD6u1GDRuhwtstC1t5xBIhAxCw3whYRkg2X4zfxzL93LWh0KH40imye38vUpNF46A53RrSCUhVNM67EDzUzoTvi1XFq3AW/bqtuyB9QcNEh9D3Aw4Vsif8iArGZI0TUVJu2cJVPeNs/fXkL8P8+ad2eOIqJujeN65N2jwv2tUad/SqZ6s1oZpn1e7L6rlXC9mVzXdKk+BVNhsAyPN1upzNXL2qtSP2/DwhgCCLB+tOiVP/D+i8AoDmDtbCgpuM95Qa4o8vHoftfERDN73gXMPcJQQbFYbYF203VjKpwM2cxcyNdl37rRKtn8utE0pEjEfrBRpAoUobxNTryVM9UW8+1xCs8bR1qe2k7ye1ufFHxQga67bYozd0ra12ZP/9QYYmZRVozkQdb70xd/wi+P/biIYTLqplnZi8AFbwoyX87t6+LrQboy6J5VwFf5bnnR1u9LhyhUC8CTqnBa2L1Jo1jyxKUS0Shwa2SLlnV90I7B19BX0SU9Wdc+x5O3mI/19b3+bqV6#2019-12-0923:28erwinrooijakkersVisualisation from reddit yesterday: https://preview.redd.it/d2xityozj8341.gif?width=904&amp;format=mp4&amp;s=c97ef3e9af23ae0ed5b6a962322c59ef4c41477a#2019-12-1001:58fellshardOooh, pretty. Is that using curses?#2019-12-1002:10Mario C.I kept getting the 203 error with day 9. All the tests cases worked. Even the ones made up by redditors but the actual input kept giving 203. Turns out it I left out the "2" in the condition for mode checking. Legit lost 4 hours tracking that down#2019-12-1004:18mpcjanssenYou were not the only one. 203 seems to have been the biggest stumbling block this day.#2019-12-1009:04JYou have an error on your 03 intcode with mode 2#2019-12-1022:00pesterhazyhehe, the error code is self-explanatory#2019-12-1002:10Mario C.Apparently (= val) is valid clojure#2019-12-1006:36fellshardToday, I realize how much basic trig I've forgotten.#2019-12-1008:00mpcjanssenFor part one I didn't need trig. Part 2 not so sure#2019-12-1006:37rjrayAyup.#2019-12-1007:19fellshardViz: http://quil.info/sketches/show/5d471cd687426dd3ffa006d6c50133e7aed9c984ccada11be36ea06ab5fc5970#2019-12-1007:21meikemertschso cool!!#2019-12-1007:49roman01laI don't get day 10 description, the very first example says only 1 asteroid is unreachable, but looking at the map it's clear there are two of them :thinking_face:#2019-12-1007:50meikemertschdo you mean the top right corner? that one is reachable#2019-12-1007:52meikemertschif there was an asteroid between the highlighted one and the top right corner, it would have to sit at a position with non-integer coordinates.#2019-12-1007:52meikemertsch“every asteroid is exactly in the center of its marked position”#2019-12-1007:54roman01laOh right, that makes sense. The map put me in Manhattan distance state of mind.#2019-12-1007:54meikemertsch:thumbsup::skin-tone-2: 🍀#2019-12-1008:47mpcjanssenMy laser already killed astroid 200 on the first round. Lucky I guess#2019-12-1011:16mpcjanssenPersonal challenge for today, make it fast#2019-12-1011:17roman01ladon’t forget about threads#2019-12-1011:17roman01lapmap all the things#2019-12-1011:18mpcjanssenWant to look more into reducing algorithmic complexity. Using more power is cheating 😉#2019-12-1011:19mpcjanssenCurrent solution is at least O(n^2)#2019-12-1011:21mpcjanssenI am checking all other asteroids to see if one is blocking the line of sight which is stupid#2019-12-1011:21mpcjanssenBetter to determine LoS and see if it has astroids#2019-12-1011:22mishagroup-by angle, sort-by distance#2019-12-1011:22roman01la@mpcjanssen what’s LoS?#2019-12-1011:23mpcjanssenline of sight#2019-12-1011:23mishaline of sight#2019-12-1011:23mishahow fast is fast for you?#2019-12-1011:24mpcjanssenright now it takes 16 secs want to improve to below 5#2019-12-1011:24misha"Elapsed time: 108.515633 msecs" "Elapsed time: 4.428149 msecs"#2019-12-1011:25roman01la🏎️#2019-12-1011:25mishahad "seconds" p1 solution, then re-implemented with angles#2019-12-1011:25mishaway less code, tests, and faster#2019-12-1011:28mpcjanssenany link#2019-12-1011:30mishawasted too much time on it, so did not clean up https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/2019/day10.clj#2019-12-1014:35Average-userInteresting, did something similar, you can use mod in your rotate function to avoid cond-> I think#2019-12-1019:57mishahow?#2019-12-1021:39ghadi@misha nicely done#2019-12-1011:32mpcjanssenah so group by angle and take closest gives the visible astroids immediately#2019-12-1011:36mpcjanssensmart, i would just be worried about floating point inaccuracies in the angles.#2019-12-1011:39yuhanit's the first time I've ever found clojure's Rational type to be useful :)#2019-12-1011:40mishathat "smart" solution cost me 2+ hours harold#2019-12-1011:41yuhanjust take the (/ dy dx) and count the frequencies#2019-12-1011:42yuhanwith the exception that opposite quadrants give the same gradient, so take the sign of dy and dx to disambiguate#2019-12-1011:43mishayeah, spent time on adjusting coordinate system as well#2019-12-1022:19rjrayAnd don't forget that one of dy or dx can be zero 🙂.#2019-12-1104:08mishaI left it to Math/atan2 : > * &lt;li&gt;If the first argument is positive and the second argument is > * positive zero or negative zero, or the first argument is positive > * infinity and the second argument is finite, then the result is the > * {@code double} value closest to &lt;i&gt;pi&lt;/i&gt;/2.#2019-12-1011:41mishatried to cycle outermost xys instead, but it was not granular enough, etc.#2019-12-1014:07mpcjanssen@misha with groupby orderby it goes from 16s to 300ms#2019-12-1014:08mpcjanssen@misha#2019-12-1014:10mpcjanssenproving again that improving algoritm beats brute force at any day#2019-12-1014:13mpcjanssensimpler too#2019-12-1014:35namenudone! Peeling asteroids clockwise from the inside was super easy with mapcat 😉 https://github.com/namenu/advent-of-code/blob/master/src/year2019/day10.clj#2019-12-1015:05namenuthere must be an floating point error because i didn't make rational number lowest form..#2019-12-1015:06namenumaybe we can avoid math functions at all.#2019-12-1015:26mpcjanssenHmm my original algorithm was n^3#2019-12-1016:41Mario C.So I am guessing day 10 is when the questions start ramping up.#2019-12-1016:43Mario C.I have intcode PTSD now so I am afraid to hack together solutions for the sake of solutions and feel the need to write a scalable feature-wise solution.#2019-12-1016:43Mario C.Although my part 1 day 10 was a hack brute force#2019-12-1020:46pastafariThe angles idea is great! Although I struggled with orienting the co-ordinate frame! @misha#2019-12-1104:11mishatook me awhile and a bunch of printing too#2019-12-1021:23fellshardFaffing around in the REPL let me figure it out by recollection and informed intuition. The quickest win for me was (thread for spoilers)#2019-12-1021:24fellshard|| to reverse the x and y arguments to atan2. || From there, you could convert the range by normal means.#2019-12-1021:25fellshardWhen you aren't familiar with the behaviour of a mathematical function, playing with it in the repl can sometimes be good enough. 🙂#2019-12-1021:58pesterhazyREPL driven math?#2019-12-1022:00fellshardPretty much - take a sampling of inputs, examine the outputs to make sure you're understanding your changes correctly. Here, I did a quick guess in my head as to what flipping the coordinates would do, confirmed it in the REPL, and fixed the issue wherein the range was still flipped and offset by 180deg. Quick sampling lets me vet how the function behaved at the edges.#2019-12-1022:02pesterhazyI also tried a bunch of example vectors, [0 1] [1 1] [1 0] etc to get a feel for how atan2 develops#2019-12-1022:03pesterhazyof course I still had to debug the code because I forgot to prefer closer asteroids#2019-12-1022:03pesterhazythings never work on the first run for me#2019-12-1021:28chrisblomMy day 10 solution: <https://github.com/chrisblom/advent-of-code/blob/master/src/adventofcode/2019/day10.clj>#2019-12-1021:30chrisblomCould be made more efficient, but it was fast enough for the input#2019-12-1021:32chrisblomLast years I remember that solutions already needed to be more efficient by day 10#2019-12-1021:54pesterhazyMy day 10: https://github.com/pesterhazy/advent2019/blob/master/typescript/src/puzzle10.ts#L1#2019-12-1021:56pesterhazyTook me a while today because (like last year) I had to read up on dot products and atan2#2019-12-1102:16erwinrooijakkersRough night after Ajax and a few beers#2019-12-1102:16erwinrooijakkers#2019-12-1107:24meikemertschwhat did you write it on? 😉#2019-12-1121:48erwinrooijakkers#2019-12-1102:17erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day10.clj#2019-12-1102:37Average-userThose are the answers to my input too#2019-12-1106:28fellshardMore intcode fusion fun!#2019-12-1106:53Average-userhttps://github.com/Average-user/adventofcode-clj-2019/blob/master/src/adventofcode_clj_2019/day11.clj Until today I just used day5 code, modify it a little and so on, but I've decided to make intcode.clj its own file ...#2019-12-1106:53Average-userI'll do it tomorrow though#2019-12-1107:11fellshardYeah, especially since he calls it 'complete' now#2019-12-1107:40mishaeven fewer reasons to touch that sht again kappa#2019-12-1107:41mishajust require day05 :as cpu#2019-12-1107:47fellshardAdd a couple of helper fns for extracting outputs and injecting inputs; honestly, may be worth converting fully to core.async#2019-12-1108:59namenuyeah, it's about time to break purity of intcode functions (maybe with core.async)#2019-12-1203:56Average-user> Yeah, especially since he calls it 'complete' now#2019-12-1203:56Average-userhow do you mean?#2019-12-1204:00fellshardThe beginning of 9-2, in highlights: > You now have a complete Intcode computer. So the relative base + mode + instruction were the last pieces. From here on out, I expect if the Intcode computer is used, it'll be composed with some other system, e.g. the amplifiers and paintbot we've already seen.#2019-12-1109:18uoslif I hear "intcode" one more time this december santa is gonna pay#2019-12-1109:21roman01laloooool 😀#2019-12-1109:31mpcjanssenmy part 2 text makes no sense#2019-12-1109:44mpcjanssenah partition count error#2019-12-1109:59mpcjanssenhttps://github.com/mpcjanssen/aoc2019/blob/master/day11.ipynb#2019-12-1110:03mpcjanssenstill a bit magical to see the asciiart appear#2019-12-1110:03mpcjanssencant wait to see the quill version from @fellshard#2019-12-1110:06mpcjanssentalk about synchronisity. Currently reading the joy of clojure. Just read: > To demonstrate this, let's build a robot object that has functions for moving it around a grid based on its current position and bearing.#2019-12-1110:59dmarjenburghKind of hard to keep up with AoC on vacation simple_smile . I can’t be bothered to refactor my code 😆 . I’m happy my core.async intcode solution works with n inputs, m outputs is any order https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L254-275#2019-12-1121:48erwinrooijakkersKind of hard to keep up with aoc during a work week 😉#2019-12-1118:05rjrayHmmm. I'm getting a "bad opcode" when I run part 1 on the real data, as it moves the PC (jumps) to a location whose value is not a valid opcode.#2019-12-1119:04rjrayNvm. Found it, was a lurking error in my input opcode that just hadn't been triggered in a previous day.#2019-12-1120:09uoslI finally completed day 7 part 2 after finding out > All signals sent or received in this process will be between pairs of amplifiers except the very first signal and the very last signal. To start the process, a 0 signal is sent to amplifier A's input exactly once. didn't mean that the 0 signal should be sent before the phase signal 😪#2019-12-1122:12erwinrooijakkersSuch awesome puzzles 🙂#2019-12-1200:09fellshardLotta folks don't dig the cpu simulators; they've always been my favs, and it's much more interesting to me now that he's using it to drive other systems. The integration aspect is its own set of neat challenges that he wouldn't have been able to put in a single day previously. The downside I can see is that it makes catching up very linear; skipping days isn't as simple this year as it was in prior.#2019-12-1200:19rjrayYeah, I'd agree with you on the fun-aspect of integrating the sim with other systems. I only finally today got around to extracting the intcode "machine" into its own namespace and refactored my day 11 code to use the imported machine. Figure we've got at least 6 more days that'll use the machine, maybe more.#2019-12-1200:21erwinrooijakkersDay 11: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2019/day11.clj#2019-12-1206:39mishanothing wrong with cpu simulator except too convoluted and verbose description of one, spread across 3 or 4 days, and like total of 15 pages of text. Even changes in requirements are not that bad comparing to this.#2019-12-1206:46mishaany part 2 ideas?#2019-12-1207:34rjrayDefinitely can't brute-force it. I ran out of memory on the second test data set (and I have 16Gb of physical memory). Gonna sleep on it and see if I can think of something in the morning.#2019-12-1207:58mpcjanssenmy velocities keep blowing up for part 1#2019-12-1208:02roman01laGuess the name of the task itself is known problem with existing solutions#2019-12-1208:13roman01lahttps://en.m.wikipedia.org/wiki/N-body_problem#2019-12-1208:21mishaI just read reddit for hints today opieop#2019-12-1208:22mishaslow though:
p1 input   "Elapsed time: 35.301894 msecs"
p2 sample1 "Elapsed time: 2.732321 msecs"
p2 sample2 "Elapsed time: 293.312654 msecs"
p2 input   "Elapsed time: 11600.599702 msecs"
#2019-12-1208:35mishaspoiler inside#2019-12-1208:37mishatotal cycle can be predicted from cycles of each of the axes, which are much shorter. Think frequency of a wave which is a summary of sine waves with different frequencies#2019-12-1208:38mpcjanssenah was almost there, needed to split by axis too#2019-12-1209:37mpcjanssennow some primw factor voodoo#2019-12-1210:48mpcjanssenam stuck example 1 works with my code exampen2 and my puzzle give way too high answers#2019-12-1211:20mishaanother spoiler: it is not (* x y z)#2019-12-1211:45mpcjanssenyou need to check when the whole x axis and vx isnrhe same for all moons#2019-12-1211:45mpcjanssenand you need some prime factor work indeed#2019-12-1211:52mpcjanssenbingo#2019-12-1211:57mpcjanssenmain observation. The equations of motion in each axis are completely independent#2019-12-1208:36mpcjanssenoh?#2019-12-1208:37mpcjanssennot for me 🙂#2019-12-1214:42mpcjansseninteresting. Changing the moons from maps to records reduces the part 2 runtime from 40 to 30 seconds#2019-12-1214:44mpcjanssenAny other performance tips?#2019-12-1215:02yuhanYou don't actually have to find the prime factorizations of each axis, just their lowest common multiple#2019-12-1215:02yuhanwhich you can use Euclid's algorithm for - LCM(a,b) = a*b / GCD(a,b)#2019-12-1215:07yuhanalthough I don't think that's the bottleneck - my solution for part2 runs in 680ms#2019-12-1215:14mpcjanssenThats indeed not thw borrlenexk#2019-12-1215:15mpcjanssenIt was a fun exercise though#2019-12-1215:15mpcjanssenhow do check if you reached the initial state?#2019-12-1215:17yuhanI just use = on a seq of [p, v] tuples#2019-12-1215:18yuhanlooking at your notebook, it's hard to read because of all the funky indentation#2019-12-1215:20yuhanI've only played around with Clojure notebooks for a while before, but the Parinfer plugin was essential for keeping some grasp on the parens: https://github.com/jelmerderonde/jupyter-lab-parinfer#2019-12-1215:21yuhanyour dv-ax function is simply compare#2019-12-1215:21mpcjanssenmy step is slow#2019-12-1215:22mpcjansseni am doing this on my phone so indentation is not the best#2019-12-1215:22yuhanah, that explains it#2019-12-1215:23yuhanyour addp is (mapv + p1 p2)#2019-12-1215:24yuhan30s on a phone with Clojurescript might not be that bad after all?#2019-12-1215:30mpcjanssencount on a lazy seq is slow?#2019-12-1215:31yuhancount forces the elements of the seq to be realised#2019-12-1215:32mpcjanssenif I remove the xount#2019-12-1215:32mpcjanssenand add a doall, its much faster#2019-12-1215:33mpcjanssendid you use recur or iterate?#2019-12-1215:33yuhaniterate#2019-12-1215:34mpcjanssenhow do you know the number of steps?#2019-12-1215:42yuhaniterate generates an infinite seq, I reduce over it and break using reduced when it cycles back around#2019-12-1215:43yuhanHere's some of the relevant bits
(def input
  (parse "<x=14, y=9, z=14>
<x=9, y=11, z=6>
<x=-6, y=14, z=-4>
<x=4, y=-4, z=-3>"))
;; => ((14 9 14) (9 11 6) (-6 14 -4) (4 -4 -3))

(def test-input
  (parse "<x=-1, y=0, z=2>
<x=2, y=-10, z=-7>
<x=4, y=-8, z=8>
<x=3, y=5, z=-1>"))
;; => ((-1 0 2) (2 -10 -7) (4 -8 8(3 5 -1))


;; * Part 2
(defn axis-step
  [pvs]
  (map (fn [[p v]]
         (let [nv (+ v (reduce (fn [acc [p']]
                                 (+ acc (compare p' p)))
                         0 pvs))]
           [(+ p nv) nv]))
    pvs))

(defn axis-period
  [ps]
  (let [vs (repeat 0)
        pvs (map vector ps vs)]
    (reduce (fn [cnt x]
              (if (= pvs x)
                (reduced cnt)
                (inc cnt)))
      1 (next (iterate axis-step pvs)))))

(for [ps (apply map vector test-input)]
  (axis-period ps))
;; => (18 28 44)

(util/lcm 18 28 44)
;; => 2772


(apply util/lcm
  (for [ps (apply map vector input)]
    (axis-period ps)))
;; => 282399002133976
#2019-12-1215:47mpcjanssenoww addp is just +#2019-12-1215:47mpcjanssenah and reduce for the count#2019-12-1216:15mpcjanssenmy phone is quite fast I am not much slower than the really fast solutions#2019-12-1216:53mishaoh yeah, I did not think to completely split the computation from for-all-axes-in-a-single-step into 1-axis-per-step#2019-12-1302:26Average-user@UCPS050BV But why do you assume that the cycle will include the first configuration?#2019-12-1304:28yuhanah, I interpreted the puzzle that way and it worked out - wonder if I just got lucky?#2019-12-1304:32yuhanAlso I strongly suspect the equations of motion are time-reversible, which would mean that for any configuration to repeat, all the previous steps leading up to it would also have to be repeated#2019-12-1214:54mpcjanssenhttps://github.com/mpcjanssen/aoc2019/blob/master/day12.ipynb#2019-12-1217:36dmarjenburghFinally one that required some puzzling 😃. I drew a graph of one of the moon coordinates that hinted towards a solution. https://gitlab.com/dmarjenburgh/adventofcode/blob/master/src/adventofcode/year_2019.clj#L277-314#2019-12-1217:46Average-userI got part 2 to run In about 3 seconds: https://github.com/Average-user/adventofcode-clj-2019/blob/master/src/adventofcode_clj_2019/day12.clj#2019-12-1217:47Average-user
adventofcode-clj-2019.day12> (time (part-2))
"Elapsed time: 2809.105945 msecs"
324618307124784
#2019-12-1223:38Mario C.I am working on Day 11 part 2 and I keep getting a weird drawing. Looks like a rabbit. I already set the first panel to white as per the instructions but still no actual word.#2019-12-1223:43fellshardHmm. I'd ask if there's something wrong with your turning implementation, but Part 1 should have rooted that out.#2019-12-1223:46Mario C.This would be my turning function
(defn move-bot
  [[face [x y]] outputs]
  (let [[_ turn] outputs]
    (if (empty? outputs)
      (do (println "OUTPUTS EMPTY standing still")
          [face [x y]])
      (case face
        :north (if (= turn 0)
                 [:west [(dec x) y]]
                 [:east [(inc x) y]])
        :south (if (= turn 0)
                 [:east [(inc x) y]]
                 [:west [(dec x) y]])
        :west (if (= turn 0)
                [:south [x (dec y)]]
                [:north [x (inc y)]])
        :east (if (= turn 0)
                [:north [x (inc y)]]
                [:south [x (dec y)]])))))
#2019-12-1307:22mishayou can leverage maps and vectors:
{:north [[:west  [dec identity]] [:east  [inc identity]]]
 :south [[:east  [inc identity]] [:west  [dec identity]]]
 :west  [[:south [identity dec]] [:north [identity inc]]]
 :east  [[:north [identity inc]] [:south [identity dec]]]}
#2019-12-1307:23mishaand then (get-in m [face turn])#2019-12-1316:19Mario C.Thats funny because I actually did this exact thing for another function
(defn get-input
  [[_ pos] grid]
  (let [color (get grid pos :black)]
    (get {:black 0 :white 1} color)))
Didn't think of using it for this! Good catch! :thumbsup:
#2019-12-1316:28mishayou'll get diff-functions though, instead of calculated values, so there will be extra apply step#2019-12-1301:36Mario C.Final found the bug. My IntCode heap was being set to null#2019-12-1301:37Mario C.surprised that didn't cause issues in part one#2019-12-1305:09fellshardoh my gosh he's insane#2019-12-1305:10meikemertschjust to confirm: We start with a stackoverflowerror? or am I broken?#2019-12-1305:37fellshardBroken, mine ran instantly in step 1#2019-12-1307:26meikemertsch😞 Thanks!#2019-12-1306:14fellshardWell. That was weird and fun.#2019-12-1306:15fellshardI was gonna add controls, but I discovered having a three-pixel margin of error just isn't that much fun 😛#2019-12-1306:15fellshardMaybe if I have it only increment when you click a button instead of on every frame#2019-12-1306:38fellshardhttp://quil.info/sketches/show/f35ebdfb776bb34d65a82c6d6599b4f3991d93dc80a880123f929e2cda836a64#2019-12-1307:06mishagot my own visualization too! kappa
"||||||||||||||||||||||||||||||||||||||
 |                                    |
 | # #     ## # ## ##  # # ##### # #  |
 | ##  #  ## ## ## #   #### #### #  # |
 |  #### ## ## ##  ## ###### ## #  #  |
 |   ##########   ##  ## #### ## ## # |
 |  ##  ##   ### # # ###   #  #  # #  |
 | #  ##   # ## #  # #### #####    #  |
 |  #   #    ####  #   ## #  ##  ## # |
 | # #    #    ## ###  ##  ##         |
 |  # ##   # ## # ### #   ##  # # ##  |
 | ###   ##   # ## ##### # ### ##   # |
 | ##  #  # # # #     # ## ##   #     |
 | ### ##   ## ## ##  #   ####  ####  |
 |   #   ## ##  # ## #  # #    #  ##  |
 |                                    |
 |                o                   |
 |                                    |
 |                                    |
 |                  -                 |
 |                                    |"
#2019-12-1307:14misha#2019-12-1310:08yuhanI wonder if it's even possible to complete Part 2 without some sort of visualization#2019-12-1310:38mishaI rendered last frame of part 1, And rendered animated part 2 after completing it, for giggles. But yeah, w/o any picture I don't see how could you figure out what to do, except port or run someone else's code.#2019-12-1310:40mishaunless "arcanoid" is the first thing that comes to your mind after reading "arcade station"#2019-12-1319:38fellshardIt is, I retrofitted my solution to execute without viz - the paddle logic can be extremely naive, and you don't need to hold on to that much additional state. But w/o the viz you won't learn very easily how the paddle behaves.#2019-12-1319:39fellshardWhen he mentioned 'ball', 'paddle', and 'blocks', I knew he was referring to an arkanoid-like at least.#2019-12-1306:51mishathis is how I got second star:
(#:adventofcode.2019.day05{:idx 439, :relbase 2239, :input [0], :output -1} #:adventofcode.2019.day05{:idx 441, :relbase 2239, :input [0], :output 0} #:adventofcode.2019.day05{:idx 443, :relbase 2239, :input [0], :output 10776})
Syntax error (NullPointerException) compiling at (day13.clj:91:1).
null
d
#2019-12-1306:55fellshardI've done that sometimes#2019-12-1306:55fellshardwhy check carefully for halt condition when you can careen off the edge and salvage the answer on the way down?
#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:33erwinrooijakkers
1. 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:47erwinrooijakkers
aocd > 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:01alekszelarkhaha, 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:50alekszelarkHere 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:03alekszelarkhttps://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:54alekszelarkso 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:50alekszelarkYeah, I loved it.#2020-12-0406:51alekszelarkLast year, the first a bit challenging puzzle for me was on day 10, then day 12.#2020-12-0406:54alekszelarkDay 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:13alekszelarkMy 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:03alekszelarka 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:43alekszelarkbtw, you could a bit simplify the spec for part 1#2020-12-0417:43alekszelark(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:09alekszelarkMy 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:19alekszelark@U0ESCTA1E yes, as Arne showed you could use some instead.#2020-12-0516:20alekszelark(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:31alekszelarkAnd 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:32alekszelarkMe 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:57alekszelark@U076FM90B Just realized from your solution, that splitting at row and col and then some math are not needed at all.#2020-12-0510:58alekszelarkI 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:30alekszelarkIt’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:32alekszelarkand 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:47alekszelarkI solved it literally how it says (spoiler) 😞#2020-12-0509:48alekszelark
(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:43alekszelarkfull solution https://github.com/zelark/AoC-2020/blob/3cc64ff25278f82d262c4c32c2eec4268c0997a5/src/zelark/aoc_2020/day_05.clj#2020-12-0510:44alekszelarkrefactored one https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_05.clj#2020-12-0511:09alekszelarkAnd 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:59alekszelarkYou 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:36alekszelarkThat’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&amp;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&amp;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:55alekszelarknot 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:03alekszelarkMy 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:30alekszelark@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:45alekszelarkvisualization >_< https://i.redd.it/gx6l9oavzp361.jpg#2020-12-0715:56alekszelark> 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:14alekszelark
(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:06alekszelarkAnd 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:57alekszelarkmight 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:32alekszelarkI’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:52alekszelarkmaybe 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:01alekszelarkHope 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:09alekszelarkMay 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:57alekszelarkDay 9 Answers Thread - Post your answers here#2020-12-0905:58alekszelarkJust 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:13alekszelark@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:29alekszelarkHere 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:33alekszelark@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:20alekszelarkAlso (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:28alekszelarkDay 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:27alekszelarkAnd 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:18alekszelarkRefactored 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:04alekszelarkBrilliantly!#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:31alekszelarkThe 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:31alekszelark(->> (frequencies (map - (rest adapters) adapters)) vals (apply *))#2020-12-1014:51alekszelarkhttps://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:05alekszelark@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:34misha
p2:
"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:26alekszelarkThere is a couple guys who recorded videos. You can learn from them a lot.#2020-12-1017:27alekszelarkhttps://youtu.be/9ITiZ88sljA#2020-12-1017:27andrea.crottiyeah but you should try by yourself first maybe#2020-12-1017:28alekszelarkand 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:24alekszelarkan 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:14alekszelark
touch 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:18alekszelarkat least you have to have {:paths [“src”]}, that’s enough to start#2020-12-1018:19alekszelarkan 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 1s 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 1s 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&amp;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:57alekszelarkHere 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:00alekszelark@vincent.cantin I tried, but it didn’t help much#2020-12-1116:03alekszelarkI 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:08alekszelarkSure!#2020-12-1116:08Vincent CantinIn this version, I tried to leverage the transducers.#2020-12-1116:17alekszelarkPart 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&amp;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:59alekszelarkDay 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:12alekszelarkThe 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:16alekszelarkEven 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:11alekszelarkhttps://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:07alekszelarkNot 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:00alekszelarkMorning 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:02alekszelarkDirty, but works https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_14.clj#2020-12-1407:31alekszelark@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:03alekszelarkI like floating-addresses approach#2020-12-1408:05alekszelarkgonna 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:11alekszelarkI’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:13alekszelarkYes 🙂#2020-12-1414:13alekszelarkpeople still like it https://twitter.com/alekszelark/status/1335185041962504192?s=20#2020-12-1414:17alekszelarkAlso 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:05alekszelark@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:03alekszelarkI 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:33alekszelarkhttps://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:48alekszelarkYes, 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:32alekszelarkA 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:51genmeblog
Capacity= 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:14alekszelarkYes, 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:29alekszelarkDay 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:08alekszelarkNot 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:40alekszelarkMy 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:09alekszelarkI 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:49alekszelark@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:53alekszelarkWho 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:49alekszelark@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:01alekszelarkYes, 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:03alekszelarkOhh :)))#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:30alekszelarkjuxt: 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:24alekszelarkdid 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:41alekszelarkYeah, 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:02alekszelark
(defmacro adjacent [n]
  (let [ds (repeatedly n #(gensym "d"))
        bindings (mapcat #(-> [% [-1 0 1]]) ds)]
    `(for [
#2020-12-1715:04alekszelarkit calculates adjacent locations for n-dimension space.#2020-12-1715:05alekszelarkYou 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:07alekszelark@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:35alekszelarkI 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:27alekszelarkYeah, 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:28alekszelarkbtw, 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:35alekszelarkalso, 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:43alekszelark[2020 Day 17] The hardest part. https://i.redd.it/k6tlppouvq561.jpg#2020-12-1717:44alekszelarkIndeed!#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:09alekszelark@U8MJBRSR5 today is your turn to teach us something 🙂#2020-12-1806:10Vincent CantinNot fair, I will ask a refund. 😉#2020-12-1806:10alekszelarkNice catch to use postwalk, I even didn’t remember about it.#2020-12-1806:12alekszelarkActually, 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:29alekszelarkHere 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.Symbols 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:52alekszelarkDay 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:58alekszelarkI solved it with regexs 😂#2020-12-1907:59alekszelarkthe 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:46alekszelark😁#2020-12-1909:58alekszelarkI wonder anyone else solved it without instaparse?#2020-12-1910:10alekszelarkMy 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:57alekszelarkmy 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:15benoit
This 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:16alekszelarkme 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:25alekszelark#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:36alekszelark> how did you create that visualization? @U65FN6WL9 https://regexper.com/#2020-12-2217:39alekszelark@U2PGHFU5U hahaha, did it by hands https://media.giphy.com/media/lCbSAbRrFEfkY/giphy.gif#2020-12-2218:08alekszelark@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:12alekszelarkstats 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:32alekszelarkYou’d better not see my code today :)))#2020-12-2013:35Vincent CantinPlease share ~ it’s fine#2020-12-2013:36alekszelarkI 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:32alekszelarkWith 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:34alekszelarkHere 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:58alekszelarkthat’s enough to check#2020-12-2017:00alekszelarkFirst 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:02alekszelarkDoesn’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:51alekszelark
(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:53alekszelarkEven 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
#2020-12-2022:28euccastro#2020-12-2022:29euccastromadness dot png#2020-12-2022:33euccastrohere I was trying to convince myself that I could do with just flips and transposes (i.e., no need for explicit rotations). I was silly/underslept enough to clutter the drawing with arrows in both directions even though all basic ops are their own inverses#2020-12-2022:41euccastro@U5P5Z5J23 there is no symmetry in the puzzle tiles; all borders are unique, even allowing for reversals#2020-12-2022:42markwYeah after much banging my head against the wall I came to the same conclusion.. and now I’m stuck#2020-12-2022:42markwevery square unique, every perimeter unique, every convolved perimeter unique.. .ugh#2020-12-2022:43markwand 8^144 choices 😕#2020-12-2017:45alekszelarkDid a visualization of part 2#2020-12-2110:28Alexandre GrisonDid one also, except I solved this one with Kotlin 😄#2020-12-2018:32JoeWow, I think I hit the wall on this one. End of the AOC adventure for me this year 😞#2020-12-2018:41nbardiuktoday was really work for 2 different days. Assembling jigsaw puzzle and pattern matching are different problems. I wrote 2x code compared to the longest previous day#2020-12-2022:23euccastroFor me, assembling the puzzle alone was work for 2 days. once that was done, scanning for monsters felt relatively straightforward#2020-12-2022:28euccastro#2020-12-2105:30Vincent CantinDay 21 answers thread - Post your answers here#2020-12-2106:15Daw-Ran LiouFor part 2, I just need to clean up the data a bit to figure out the answer manually 😛 https://github.com/dawranliou/advent-of-code/blob/master/2020/src/dawranliou/advent_of_code_2020/day_21.clj#2020-12-2106:16Vincent Cantinwow ! you are fast#2020-12-2106:16Vincent CantinI didn’t do the part 1 yet#2020-12-2106:17Daw-Ran LiouI’m sure I can clean up the logic more but it is what it is… Now time to go back to my day 20 lol.#2020-12-2106:57Vincent CantinI got my 2 stars ^_^ .  After I saw @U7PQH43PS finishing early, I decided to try again for another hour.#2020-12-2107:05Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_21.clj#2020-12-2107:07Daw-Ran LiouLove this: https://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_21.clj#L62-L64#2020-12-2107:09Vincent Cantin😄#2020-12-2107:50Charles Fourdrignierhttps://github.com/Charlynux/advent-of-code-2020/blob/master/day21/day21.clj#2020-12-2108:03peterc@U8MJBRSR5 Love your solution for part 1 😄#2020-12-2108:03petercSo simple but it works like a charm#2020-12-2108:15euccastrohttps://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day21.clj#2020-12-2108:16euccastro(yeah, I finally woke up early-ish and couldn't resist giving it a try)#2020-12-2108:18euccastroI was already looking into core.logic for the first part when my daughter woke up and the solution popped up in my mind while putting her to sleep again 😛#2020-12-2108:19euccastrocan't overemphasize the value of stepping away from the computer sometimes#2020-12-2108:19Vincent CantinI found my solution after running after the cat which kept interrupting me..#2020-12-2108:53alekszelarkhttps://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_21.clj#2020-12-2109:07nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day21.clj#2020-12-2111:15misha@U076FM90B need a util function for pruning already, yeah.#2020-12-2111:17mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day21.cljc#2020-12-2112:35Max DeinekoOne from a newcomer to both clojure and aoc: https://github.com/next-mad-hatter/adventofcode/blob/master/src/aoc_2020/day_21.clj Not in leaderboard or racing mode, there's definitely lots to learn from the solutions here for me 🙂#2020-12-2112:40benoitSolution to Day 21: https://github.com/benfle/advent-of-code-2020/blob/main/day21.clj#2020-12-2112:40benoitThis one was more reasonable than yesterday 🙂#2020-12-2112:41benoitThe only interesting bit is the use of the fixed-point method to identify the food containing each allergen.#2020-12-2112:43Vincent Cantin@U067R559Q I like your solution, and I think that my extension of group-by could have been useful to you in the parse-input function.#2020-12-2112:59benoitNice one @U067R559Q. A lot of work is done in the parsing function :)#2020-12-2113:00benoitI need to improve my parsing/regexp game.#2020-12-2113:10misha> newcomer to both clojure and aoc @
[clojure.algo.generic.functor :refer [fmap]]
tatatananana
#2020-12-2113:26Max Deineko@U051HUZLD is fmap something arcane or comes with some caveats? iirc I stumbled upon it at the very beginning of my looking at clojure while searching for a predefined way to transform a map's keys -- it seemed to me like something which would be a natural part of the standard library#2020-12-2113:37mishahave not seen it used in 5 years, but it looks useful. I think it is not a part of a stdlib because of transducers, and you very rarely just "map f over things and that's it". More often you then filter/remove/etc. over it, and only then pick a container for a result. @U9TGHG3LP#2020-12-2113:40mishare-pouring the map result into specific container after each step of a transformation is like anti-transducer, and it is useful only for a single step mapping#2020-12-2113:49genmeblogLate one: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day21.clj#2020-12-2114:06alekszelark@U8MJBRSR5 thank you. Yes, it could. 🙂 But I want to keep every solution as and independent one and relying only clojure stdlib and java interop sometimes. Maybe next year I’ll pick a different way.#2020-12-2115:47Vincent CantinMaybe next year it will be part of the stdlib (I am kidding, that's impossible)#2020-12-2117:04euccastroI feel silly having matched the parens of the "(contains ...)" part after seeing @U067R559Q just split with #"contains" and grab the words 🙂#2020-12-2117:05Vincent CantinIt's ok to be paranoid .. don't worry.#2020-12-2117:06Vincent Cantinthe ingredients are probably randomly generated, they may also be spelled "contains".#2020-12-2117:07Vincent CantinFor the same reason, I won't use read-string but edn/read-string#2020-12-2117:23euccastroone trick that seems to recurrently work in aoc challenges is to resolve constraints by sorting the entries by length at the beginning and assuming that the earlier ones will always be the first ones to resolve#2020-12-2117:24euccastroI guess that would be more robust if you sorted on every iteration (but then it would be no more efficient or pretty than searching for the already resolved items explicitly)#2020-12-2117:28euccastroseparating the allergens into their own entries from the beginning is a nice touch, @U067R559Q. I wouldn't have guessed that it would simplify things that much later on#2020-12-2117:29euccastroi.e., as opposed to keeping allergen sets by line#2020-12-2117:31alekszelark@U65FN6WL9 I’m glad you learned something from my code, I think that’s one reason why we all here. I always learn something new from other’s solutions.#2020-12-2117:32alekszelarkLast year I solved puzzles solely and wasn’t in this chat. I regret a bit about it.#2020-12-2117:37euccastroyeah I only started solving the puzzles (after having binge watched @U07FP7QJ0's videos) so I would be better primed to understand others' solutions#2020-12-2117:37euccastroI'm still mulling on (reduce into []) 😄#2020-12-2117:42euccastroso that would be like concat into a vector? but wouldn't frequencies work the same had you concatenated them before by using mapcat instead in (map (comp val first) foods)?#2020-12-2117:43euccastrosimilarly, @U8MJBRSR5, why are you coercing into a vector here: https://github.com/green-coder/advent-of-code-2020/blob/8b7814d5407a783e641b7b160e7672a12c4aa538/src/aoc/day_21.clj#L32 ?#2020-12-2117:45euccastro(my own solution needs some cleanup, I'm just making sure I'm not missing something subtle)#2020-12-2117:49alekszelark> but wouldn’t `frequencies` work the same had you concatenated them before by using `mapcat` Actually, yes. Thank you for pointing out!#2020-12-2117:54euccastroyw! another thing I don't fully understand is why do you invert the result map in narrow . it shouldn't matter since it's a 1:1 mapping. if you kept allergens as keys then you could use plain sort instead of (sort-by val) (then you'd need to (map second) , but that's no worse than (map first) I guess? but the main point to me is that it's a bit surprising that `narrow' inverts, on top of narrowing#2020-12-2118:03alekszelarkIt was originally built for day 16, over there it makes more sense than here.#2020-12-2118:08alekszelarkJust updated, now it got even simpler https://github.com/zelark/AoC-2020/commit/0f3b898fd1fce7b558239939814c941547e37b72#diff-81c48a0532316c42f7ff22c58f13917b8129fae2266d787458f41270948f4234#2020-12-2118:09Vincent CantinThe code on github is mainly what I wrote while running against the clock. The vec was not needed, but when I typed it I didn't know yet. I favor vectors over sequences because of the constant access time and fast subvec.#2020-12-2118:09alekszelark@U65FN6WL9 thank you for the code review ^_^#2020-12-2121:16erwinrooijakkersLate to the party: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day21.clj#2020-12-2118:11Vincent Cantin4 days to go !#2020-12-2118:46Average-userTried some Common Lisp for today, spent really long time debugging. The problem was that mapcan was doing some sideffect and modifying my list, something that would have never happend with mapcat , I still don't quite understand why, but I had to switch (mapcan #'f xs) to (apply #'concatenate 'list (mapcar #'f xs))#2020-12-2207:44Vincent CantinI would love to join the conversation, but I don’t know CL - sorry.#2020-12-2205:40markwtonight’s puzzle… reading comprehension#2020-12-2206:18Vincent CantinI was convinced that I was at my disadvantage, reading a very long text while having ADHD, but it turned out that I was not slower than others.#2020-12-2210:49Charles FourdrignierOn this one, I miss a detail which costs me at least 20 minutes. 😄#2020-12-2205:55Vincent CantinDay 22 answers thread - Post your answers here#2020-12-2205:55Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_22.clj#2020-12-2206:03petercNice! What was the run time for part2 for you?#2020-12-2206:04Vincent Cantin4.5 seconds on my computer, about half of anybody else’s computer. The code could me improved, I am sure.#2020-12-2206:08rjrayFinally, a pair for which Clojure is wonderfully suited… https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day22.clj#2020-12-2206:08rjrayPretty sure I can get that shorter. Tomorrow.#2020-12-2206:09rjrayAlso, the title of this thread is “Day 21 answers…” 🙂.#2020-12-2206:23petercahh I didnt look at your code yet, my part-2 answer was chugging along, so its probably not correct#2020-12-2206:47markwwaiting for part 2 to finish.. must have bug somewhere#2020-12-2206:47markwsample input worked as usual. I hope this isn’t another “Find the math trick” problem#2020-12-2206:50Vincent Cantin@markw no trick, it’s a pure “understand the question” problem.#2020-12-2206:53Average-userFor me the bug was that I was finishing the round when seeing a repeated configuration, but it has to be the game. Which, if one thinks about it, makes much more sense.#2020-12-2206:54Vincent CantinThis rules of avoiding repeating configuration is similar in the game of Go.#2020-12-2206:55Average-userhttps://github.com/Average-user/aoc2020/blob/main/src/day22.lisp CL again#2020-12-2206:56Average-userMine runs in 4sec. But probably changing lists to double-queueshould improve that. I missed clojure's queues#2020-12-2206:57peterc@markw did you check the infinite loop test case?#2020-12-2206:58alekszelarkUsed queue for decks https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_22.clj#2020-12-2206:59Average-userI see some queues there, nice#2020-12-2207:01Vincent CantinI avoided using a queue when I realized that it would not display its values in my REPL, I chose a vector instead.#2020-12-2207:04alekszelarkI firstly went with vectors, but after the part 1 had been solved I changed my mind.#2020-12-2207:05Vincent CantinWhat made you change your mind? Worry of performances regarding recursion?#2020-12-2207:08alekszelarkLots of subvecs, with pop it looks a bit nicer and simpler.#2020-12-2207:10alekszelarkTo be honest, they did scare me. Because last year at the same day was the hardest puzzle with a deck of cards as well.#2020-12-2207:38markw@U1NLKFVC4 yeah i checked for that… I thought I had found the problem when I realized I misread the rules for how many cards to include in a subgame (which insidiously gave the correct answer on test input even with the bug). But I fixed that, and also verified the infinite loop case is handled.. and it’s still running. I’ll try again tomm#2020-12-2207:46nbardiukToday was even fun, I was afraid of complex combinatorics part 2 https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day22.clj#2020-12-2210:09Daw-Ran LiouJust the part 1 so far: https://github.com/dawranliou/advent-of-code/blob/master/2020/src/dawranliou/advent_of_code_2020/day_22.clj#2020-12-2210:33misha630ms https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day22.cljc#L11#2020-12-2210:47Charles FourdrignierI should definitely look to queues ! Better performance and neater syntax.#2020-12-2213:48genmeblogaround 250ms for part2 https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day22.clj#2020-12-2214:14nbardiuktoday problem is hard to compare, different inputs have very different number of steps. Using the same code on my machine my input runs 1s, @U051HUZLD's750ms and @U1EP3BZ3Q’s 150ms#2020-12-2214:39euccastrotoday my daughter was definitely rooting for the crab! my solution runs in half a second 8-10sec (that's with me being lazy and using lists/sequences instead of vectors/queues) https://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day22.clj#2020-12-2214:52euccastro#2020-12-2214:56euccastro@U076FM90B you seem to interpret that a game should end when the deck of either player has already been seen? https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day22.clj#L40#2020-12-2214:56euccastromy interpretation is that the game ends only when both decks have been seen in a given round. it's curious that both approaches work?#2020-12-2214:59genmeblog> if there was a previous round in this game that had exactly the same cards in the same order in the same players' decks#2020-12-2215:00genmeblogif any of the player has been seen game stops#2020-12-2215:13nbardiukI have trouble interpreting this statement. I guess it does not make a difference in the end because player 1 wins regardless of what deck is repeated#2020-12-2215:14euccastrosee where the apostrophe is placed. I think that basically means you bail if you see a previous game state again#2020-12-2215:15euccastroyes, but maybe player 2 would have won if the game hadn't been aborted?#2020-12-2215:15euccastro(obvs. that isn't happening in your input, so who knows)#2020-12-2215:42mishaseen deck of only one player is enough to end game, not both players' decks at the same time.
(or (seen1 deck1) (seen2 deck2))
not
(and (seen1 deck1) (seen2 deck2))
#2020-12-2215:44misharegardless, you might want to run or option (as it terminates faster), and see whether you'll get a star#2020-12-2215:54benoitMy solution https://github.com/benfle/advent-of-code-2020/blob/main/day22.clj Why would you put this very important sentence in parenthesis 🙂 Wasted so much time. (the quantity of cards copied is equal to the number on the card they drew to trigger the sub-game)#2020-12-2217:18euccastroyes, I've just checked that the or version works in my data, and runs in under 1/3 of the time#2020-12-2217:20euccastromy interpretation is not even (and (seen1 deck1) (seen2 deck2)), but an even stricter (seen [deck1 deck2]) (e.g., bail out only if both decks have been seen together in the same turn)#2020-12-2217:27alekszelarkmy interpretation is the same#2020-12-2217:30petercyeah I implemented the stricter condition as well, though it is interesting to consider if the other player's deck will also be the same in the less strict case#2020-12-2217:31petercI get the same result as well using the less restrictive case, and my time goes from ~8s to under 1s#2020-12-2219:20alekszelarkI like this refactoring https://github.com/zelark/AoC-2020/commit/6894f49405522cde85b542ddfe923faa111ad80d#2020-12-2219:23Vincent CantinWhy not using range ? https://github.com/green-coder/advent-of-code-2020/blob/b1f99617fa9587fc1269c4eac5fc2adfd2a536b0/src/aoc/day_22.clj#L53#2020-12-2219:37alekszelarkAlso a good one 🙂 My first attempt to refact the function looked exactly the same. iterate dec is a bit more natural for me here, cause there is no need for some extra numbers.#2020-12-2220:16rjrayI must be learning from this experience, because my algorithm isn’t that much different than zelark’s (though I just used lists instead of queues or even vectors).#2020-12-2207:56Vincent CantinThe funniest part of today’s puzzle is that the crab won the card game. Twice.#2020-12-2220:18rjrayMust have been your data. For my data, I won the second game 🙂.#2020-12-2302:04Vincent Cantin... based on the sample data.#2020-12-2208:10Vincent CantinYeah, you know what? We should celebrate on the last day of the AoC. How about a Post-AoC online meetup party?#2020-12-2208:13alekszelarkThat’s a good idea. I also thought about something like that.#2020-12-2208:36nbardiukI am not big fan of parties but it would be nice to see everybody and say hi#2020-12-2208:38nbardiukWe could make a watch party of r/adventofcode visualisations and jokes#2020-12-2216:55markwWell after running all night my program did the honorable thing and committed seppuku#2020-12-2216:56markwI’m actually a bit stumped.. I track seen states, verified that on the test loop game, fixed the bug with taking n cards in the subgames, works on sample, hangs forever on actual input#2020-12-2216:57markwOnly other thing I can think of is that the confusion around or for seeing prior games. I interpreted that line as you need to see the entire game state (both decks) again#2020-12-2217:11euccastromaybe post your current code? or try someone else's solution on your input data? to double check you haven't been given something broken#2020-12-2217:26markwso bizarre.. so after changing to the interpretation of “seeing” a game as meaning either deck, it terminates… with the wrong answer. I’ll post what I’ve got, apologies for the mess as I’ve hacked it apart trying to fix it and it’s now pretty messy#2020-12-2217:40markwhttps://gist.github.com/Solaxun/92d3c438d290bc2a743f5d41d7bc4077#2020-12-2217:41markwmy input is hard coded up top#2020-12-2217:50alekszelark@markw ran my solution with your input, got 36463 with a strict condition#2020-12-2217:51markwok yeah i figured it was a bug in my solution#2020-12-2217:51markwprobably something obvious that i’m just not getting, but it doesn’t help that the test input works perfectly, line-by line#2020-12-2217:53alekszelarkI guess this condition in a wrong place (if (= winner :player1) , the game should instantly end if there was a previous round in this game that had exactly the same cards.#2020-12-2217:56alekszelarkthe test input doesn’t trigger that condition, that’s why it works.#2020-12-2218:06markwUgh… well that was dumb. Wins the game not the round… oops.#2020-12-2219:06Vincent Cantinhttps://twitter.com/luiyo/status/1341454365731774464#2020-12-2219:16ACI was thrown by (what seemed to me) as inconsistent use of “game” and “sub-game”#2020-12-2220:18rjrayMust have been your data. For my data, I won the second game 🙂.#2020-12-2220:18rjray#2020-12-2303:42Vincent CantinDay 23 answers thread - Post your answers here#2020-12-2308:04Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_23.clj#2020-12-2308:15rjrayI basically implemented a linked-list of numbers for part 2. Don't ask how many bugs I had to deal with. Tomorrow I'll consolidate parts 1 & 2 into smaller code. https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day23.clj#2020-12-2312:02nbardiukI've implemented double linked list/circle using maps, it is very slow but gives the answer in several minutes 😂 https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day23.clj#2020-12-2312:29euccastrohttps://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day23.clj#2020-12-2312:29euccastroplain arrays, slow but workable#2020-12-2312:56petercI implemented a linked-list using a dictionary, and recursed the list + pointer to the head and tail. part-2 took ~125s.#2020-12-2312:56peterchttps://github.com/peterhhchan/aoc2020/blob/main/src/aoc2020/day23.clj#2020-12-2312:59Vincent CantinThe solution I posted today is running part2 in 64 seconds, probably half on your computers. I am cleaning up the code and will see if I can improve its performance a little more.#2020-12-2313:01Vincent CantinI am counting on reducing the memory footprint to reduce as well the CPU cost, since the CPU cache becomes the bottleneck here.#2020-12-2313:27Vincent Cantindown to 57 secs#2020-12-2314:07Vincent Cantin@U076FM90B When the CPU cache does not contain the memory that the program needs, it loads the data from the central memory and place it in the cache. This is very slow compared to the CPU’s raw speed, it’s the same as if it went to take a coffee while waiting for the next bus to pass by.#2020-12-2314:23Vincent Cantindown to 25 seconds#2020-12-2314:47Vincent CantinBy using a transient linked-list and assoc!, it’s down to 16 secs.#2020-12-2314:48Vincent CantinI think I should stop now before I destroy my source code 🙂#2020-12-2315:34benoitIn the right thread this time. Solution with linked list in an int array (takes around 15s) https://github.com/benfle/advent-of-code-2020/blob/main/day23.clj#2020-12-2315:38Vincent Cantin@U963A21SL (doseq [_ (range n)] can also be (dotimes [_ n]#2020-12-2315:47Vincent Cantin@U963A21SL why (aset cups 0 ^int c4) ?#2020-12-2315:49benoitI keep the value of the current pointer in the first element. And if you move the next 3 elements, the next current pointer will be c4.#2020-12-2315:50Vincent CantinI see, no problem then#2020-12-2316:25Average-userhttps://github.com/Average-user/aoc2020/blob/main/src/day23.clj#2020-12-2316:25Average-userTakes about 1 minute, simulating a linked list with a map#2020-12-2316:26Average-user
$ clj -M day23.clj 
[68245739 219634632000]"Elapsed time: 53733.237706 msecs"
#2020-12-2316:29Vincent Cantin@UCJNB809E this can become 1 assoc : https://github.com/Average-user/aoc2020/blob/main/src/day23.clj#L13-L16#2020-12-2316:32Average-userYou are right, thanks. Always forget about that#2020-12-2320:36rjrayGoing to re-do my code, using some of the tips from here 🙂. I completely forgot about transient last night, or my part 2 might have run faster. It currently runs ~32 sec on my machine. I believe I can significantly shrink my code by rewriting part 1 using part 2's structure. (It will also help the line-count when I remove the debugging fn that I left in last night...)#2020-12-2321:07erwinrooijakkers@UCJNB809E can you elaborate a bit on “simulating a linked list with a map”?#2020-12-2321:19Average-user@U2PGHFU5U The entry of the map at i si the value which i is pointing to in my imaginary linked list.#2020-12-2321:20erwinrooijakkersI see:
(build input)
;; => {7 1, 1 5, 4 3, 6 2, 3 9, 2 4, 9 7, 5 8, 8 6}
input
;; => [6 2 4 3 9 7 1 5 8]
#2020-12-2321:20erwinrooijakkerswhat are those f and g doing?#2020-12-2321:20erwinrooijakkersand d#2020-12-2321:20erwinrooijakkersand r#2020-12-2321:24Average-userto not build the complete map of 1000000 entries, g just returns i+1 if the entry of the map at i is undefined#2020-12-2321:25Average-userd stands for destination, as in the problem specification. And f I think should be clear by its definition#2020-12-2321:27Average-userI also ended up changing the map for a vector. Now it takes half the time it did before. But as other people have done, is probably better to use other structures more suited#2020-12-2321:34erwinrooijakkersah i see#2020-12-2321:36erwinrooijakkerssmart#2020-12-2321:37erwinrooijakkersthanks for elaboration i learned something 🙂#2020-12-2321:55Average-userI'm sorry if I name things to vaguely. I really should get better at naming#2020-12-2322:49Max DeinekoTIL about rrb-vector, which worked fine for me in part 1 and broke in part 2 for some reason..  Well, I'm quite content with ~20s running time using int vector for storage. https://github.com/next-mad-hatter/adventofcode/blob/master/src/aoc_2020/day_23.clj#2020-12-2400:32euccastroso I got envious of all your sub-half-an-hour solutions using linked lists and I tried a solution myself. it seems very simple and runs in about 10 seconds (I did no profiling to see whether it can be further optimized yet): https://github.com/euccastro/advent-of-code-2020/blob/8d89563a8909dc1865c2108470b4a928a3394dd1/src/advent/day23.clj#L94#2020-12-2400:38euccastroand this little optimization cut it to under 3sec: https://github.com/euccastro/advent-of-code-2020/commit/4b48551440405efa8de1eef8010aba64ad836d6b#2020-12-2400:53euccastroha, I see I ended with essentially the same solution as @misha 🙂#2020-12-2414:52genmeblogI hate it, 2 days and 1s by mutating int-array https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day23.clj#2020-12-2415:04Vincent CantinYou redefined the term "persistence". Congratz.#2020-12-2305:47holymackerelsI'm about a week behind, trying to play catch up, but I managed to get my day 15 solution down to ~1.7s, my first solution took like 5 minutes#2020-12-2305:48holymackerelsah I found the thread 👀#2020-12-2306:13Vincent CantinThat puzzle should have been named “Crab, unchained”#2020-12-2306:52euccastromy naive solution for part 2 will take 7 seconds to iterate through 10 steps, so I'll give my dog a 7 million second walk#2020-12-2306:53Vincent CantinI did not even try the naive solution.#2020-12-2306:53Vincent CantinI go for the fast way, but it’s complicated to implement.#2020-12-2306:54Vincent CantinMany off-by-one issues to deal with.#2020-12-2306:54euccastrowell, I had a step function from part 1, so might as well#2020-12-2306:54euccastroit would take 81 days to finish 😄#2020-12-2307:21Vincent CantinI finished the impl, but I have a bug somewhere.#2020-12-2307:59Vincent CantinDONE ^_^#2020-12-2308:04rjrayI'm getting the wrong answer for the test input on part 2. Ugh.#2020-12-2308:05Vincent CantinMy bug was that I was doing 1 million rounds instead of 10 millions.#2020-12-2308:06Vincent CantinI should repeat to myself: RTFM !#2020-12-2308:09rjrayThat's OK. I just got a wrong answer because I submitted the answer from the test data instead of the real data.#2020-12-2309:24euccastroOK, with a simplish array-based implementation I got it down to 5 days. I guess I need to reduce copying...#2020-12-2309:25euccastroand figure out how to hint stuff for reflection and boxed math#2020-12-2309:25euccastromight not happen today#2020-12-2309:50erwinrooijakkersMine runs in 925 days in time for Christmas 2023#2020-12-2309:50erwinrooijakkersWill look for some help :)#2020-12-2309:51erwinrooijakkersI see that the use of a LinkedList would help, but not sure what to store where. This evening#2020-12-2310:11euccastrohttps://github.com/ptaoussanis/tufte helped me narrow the performance bottleneck down to how I'm searching for the index of the destination cup. a simple improvement to that got me down to one day#2020-12-2310:21euccastrook, got it down to 45 minutes, which is close to what I was expecting. I'll just let it run at this point...#2020-12-2310:22alekszelarkI’m done, but the part 2 was running a few minutes (~3). It was hard to implement and my code is dirty and full of side effects…#2020-12-2310:24alekszelarkI came up with this
(defprotocol ICircleNode
  (get-next [this])
  (get-val [this])
  (insert-after [this node])
  (remove-after [this]))
#2020-12-2310:37euccastroI suppose you have them indexed by val?#2020-12-2311:02Vincent CantinIn French, a linked list is called a "chained list"#2020-12-2311:02Vincent CantinI failed my pun about the crab, used the wrong word.#2020-12-2311:13euccastrohaha, after 45 minutes waiting I realized that I had fed it the demo input! at least I know it works now 😛#2020-12-2311:20euccastrosince I learned programming on my own from sources in English I don't know most technical terms in my own language 🙂#2020-12-2311:20alekszelark@U65FN6WL9 yes, I also have a map for that#2020-12-2317:46alekszelarkHere is my solution, I wrote it today morning, but polished only now. It runs under 2 minutes for the part 2. https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_23.clj#2020-12-2318:42alekszelarkAlso built a fast implementation with deftype and the same protocol. It runs under 20 secs. https://github.com/zelark/AoC-2020/commit/4da8a0b8f6086a5cd552e753a5881edac6798e43#2020-12-2406:35alekszelarkHaha, just noticed it was a wrong thread.#2020-12-2315:02misha#2020-12-2315:02misha
(:import [java.util Deque ArrayDeque]))
#2020-12-2315:04alekszelarkHow fast is it?#2020-12-2315:10mishano idea yet d but faster than vectors and lists ... I think#2020-12-2316:02alekszelarkHow did you solve it then?#2020-12-2316:02alekszelarkI mean what approach did you choose?#2020-12-2316:17mishaI did not yet, just got to it. The Deque was handy in aoc 2018, so I quickly solved p1 with it, but then it turned out to be misfit for p2#2020-12-2605:23namenuHere is an immutable version of it ;) https://github.com/namenu/data.deque#2020-12-2607:39mishaNiiice#2020-12-2317:55alekszelarkAbout Day 20: “I might be able to improve this code, but I have no desire to look at it again any time soon.” Found it in one’s notes.#2020-12-2318:27rjrayI resemble that remark 🙂.#2020-12-2319:24alekszelarkDay 24 answers thread - Post your answers here#2020-12-2405:51euccastrohttps://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day24.clj#2020-12-2405:59euccastroI lucked out on this one, since I'd worked with hex grids a while ago: https://wiki.call-cc.org/eggref/4/hexgrid [P.S.; NB I'm not using that coord system here, but a simpler one with y pointing northwest and x pointing east.]#2020-12-2406:04Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_24.clj#2020-12-2406:05Vincent CantinI was a game programmer, so I know my bestagon :-)#2020-12-2406:07Vincent CantinI wasted 20 minutes on >= 2 vs > 2 picard-facepalm#2020-12-2406:08Vincent Cantin@U067R559Q I was thinking about you when I saw that it was once again about neighbors.#2020-12-2406:11euccastroI missed this first initially so my solution2 was running forever and I got really scared that there was some combinatorial madness going on again 😄 https://github.com/euccastro/advent-of-code-2020/blob/9e9cabf2fcd8ea8383ec193696ec9ebdb81be400/src/advent/day24.clj#L84#2020-12-2406:14rjrayThanks to what I learned on day 17 from @U067R559Q's code (and for the fact that I have been taking notes each day), part 2 went faster than part 1. https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day24.clj#2020-12-2406:19alekszelarkAnd here is mine 🙂 https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_24.clj#2020-12-2406:27Vincent CantinAs expected, frequencies was frequently used.#2020-12-2406:33alekszelarkjust leave it here ^_^
(defn stepper [neighbours birth? survive?]
  (fn [cells]
    (set (for [[loc n] (frequencies (mapcat neighbours cells))
               :when (if (cells loc) (survive? n) (birth? n))]
           loc))))

(stepper neighbours #{2} #{1 2})
#2020-12-2406:34euccastrodescription of the coordinate system @U8MJBRSR5 and me used: https://www.redblobgames.com/grids/hexagons/#coordinates-axial#2020-12-2406:35euccastroonly our y points northwest#2020-12-2406:45euccastro@U8MJBRSR5 @U067R559Q nice touch on using re-seq to parse the line. I'll borrow that to remove my silly str/replaces 😄#2020-12-2406:46euccastroI guess I wasn't sure enough that re-seq would do the right (greedy) thing..#2020-12-2406:46Vincent Cantin> “There is a REPL for that”#2020-12-2406:46euccastrotrue true...#2020-12-2406:53euccastrosomehow that makes my code a bit slower... but I'll keep it anyway since it reads much better#2020-12-2407:56nbardiukafter revisiting the redblobgames article and choosing right coordinate system it was easy https://github.com/nbardiuk/adventofcode/blob/master/2020/src/day24.clj#2020-12-2408:35euccastro@U076FM90B now I feel silly for using drop and first to pick an element by index in a lazy sequence. somehow I though nth didn't work on those (?)#2020-12-2409:01alekszelarkA bit revisited my solution after @U076FM90B posted his https://github.com/zelark/AoC-2020/commit/61d33f71a38d146f74661ee497f13ead4fb1c553#2020-12-2409:02alekszelark@U65FN6WL9 I believe It’s a matter of taste here. I prefer drop and first#2020-12-2409:03Vincent Cantindrop and first works well with ->>, while nth needs ->#2020-12-2409:47erwinrooijakkersI used this one https://www.redblobgames.com/grids/hexagons/#coordinates-doubled and brute forced inefficiently by looping over all the points and their neighbours, and then finding their neighbours again. The answer does print after some minutes: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day24.clj#2020-12-2409:54alekszelark@U2PGHFU5U apparently I used the same coordinates#2020-12-2412:30benoitUsing coordinate system as well https://github.com/benfle/advent-of-code-2020/blob/main/day24.clj#2020-12-2412:31benoitA little differently.#2020-12-2412:55genmebloghttps://raw.githubusercontent.com/genmeblog/advent-of-code/master/images/advent_of_code_2020/day24_100.jpg#2020-12-2417:41rjrayOnce again, I learn much from zelark's solution 🙂.#2020-12-2418:37alekszelark@UEF091BP0 Also look at nbardiuk’s solution I borrowed a couple things from it.#2020-12-2421:00rjrayWhen this is over, I plan to link to several of the other Clojure repos (in my README.md), for future reference.#2020-12-2421:03nbardiukWe slowly converge to similar code by learning from each other, nothing original in my solution 😁#2020-12-2503:11Andrew ByalaThank you to everyone for sharing your solutions - I'm learning a ton! https://github.com/abyala/advent-2020-clojure/blob/master/src/advent_2020_clojure/day24.clj.#2020-12-2503:12Andrew Byala@U076FM90B - I love your step function. I wouldn't have thought of for -> :when to construct the next set of black tiles.#2020-12-2319:29mishaprojected time: 22minutes harold#2020-12-2319:39misha"Elapsed time: 912366.338705 msecs", 15 minutes, with array as a continer.#2020-12-2319:51misha"Elapsed time: 28510.814642 msecs", 28 seconds, with transient map lol#2020-12-2319:59misha"Elapsed time: 13782.338101 msecs", 13 seconds with java.util.HashMap#2020-12-2320:00mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day23.cljc#L189-L231#2020-12-2320:19misha"Elapsed time: 6754.597334 msecs", 7 seconds, with typehints for int-array. so that was 14 minutes and 47 seconds of java reflexion, and 13 seconds of actual work, lol#2020-12-2320:22mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2020/day23.cljc#L111-L146#2020-12-2322:18Average-userI'm surprised by the lack of intcode this year. Maybe tomorrow?#2020-12-2323:36rjrayHow odd. I tried re-writing my algorithm to use int-array as @misha does in the 7-second version. It's taking several times longer to run than my vector-based original. I must have something subtle that's wrong in it.#2020-12-2323:52rjrayWell, that's an improvement. I went from 32 seconds to 26 minutes.#2020-12-2400:47euccastroyes, I tried an "optimization" in my 33 minute solution that took it to 45 😛#2020-12-2400:49euccastro@misha there's aset-int too; I got no reflection warnings when using that and no type hints a single type hint on the array itself#2020-12-2411:38mishaYeah, I saw it in your code, TIL opieop #2020-12-2406:06Vincent CantinGood morning. Today, a video about the bestagons. https://www.youtube.com/watch?v=thOifuHs6eY#2020-12-2406:11markwa bit confused on the instructions for part 2#2020-12-2406:11markware we supposed to use the colors determined from part 1 as the starting point?#2020-12-2406:12Vincent Cantin@markw Yes#2020-12-2406:12markwok good to know 🙂#2020-12-2413:53alekszelarkhttps://www.reddit.com/r/adventofcode/comments/kjev7f/2020_day_24_part_2_i_let_it_run_for_10m/#2020-12-2413:54alekszelarkAnyone wants to check it? :)))#2020-12-2414:11Vincent CantinAbove 1 million iterations, it's called Crab-coin.#2020-12-2416:01Vincent CantinBestagons found...#2020-12-2416:01Vincent Cantin
#2020-12-2417:50rjrayI'm just crossing my fingers that we don't get another Zork like last year's day 25...#2020-12-2418:43alekszelarkI was too lazy and relaxed to write an algorithm for that, so just I played in it as it was a game, and got my 2 stars in the end.#2020-12-2420:58rjraySame. I used math.combinatorics to generate the sets of items to hold at once. According to last year’s notes, this got me a ranking of 635 on part 1.#2020-12-2419:36Vincent CantinFor tomorrow’s puzzle, I randomly predict a path finding problem.#2020-12-2421:01rjrayI would welcome that. I have plenty of prior art that I can (try to) adapt for that.#2020-12-2505:33Vincent CantinDay 25 answers thread - Post your answers here#2020-12-2505:35Vincent CantinFor those interested by the topic, today’s puzzle was related to https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange#2020-12-2505:39rjrayKind of feeling let down by the day 25 puzzle. I expected to find that a brute-force approach wouldn’t be feasible. But hey, at least I can tell my wife that it’s over…#2020-12-2505:39rjrayhttps://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day25.clj#2020-12-2505:40Vincent Cantinhttps://github.com/green-coder/advent-of-code-2020/blob/master/src/aoc/day_25.clj#2020-12-2505:40euccastroI couldn't get part 2 because I started AoC at day 16 so I'm missing stars. here is my solution to part 1: https://github.com/euccastro/advent-of-code-2020/blob/master/src/advent/day25.clj#2020-12-2505:43Vincent Cantin#2020-12-2505:46euccastroI guess I lucked out then, since mine runs fast enough without worrying about that#2020-12-2505:48euccastroI even 'cracked' both values unnecessarily#2020-12-2505:51euccastro@U8MJBRSR5 come to think about it, why is that an optimization? shouldn't you perform the same number of steps no matter which key you choose to 'crack' (i.e., find the loop size of)? [P.S.: it seems that at least in my implementation it matters which one you pick, because finding the loop size happens to be more expensive than transforming a number by that number of loops]#2020-12-2505:51Andrew ByalaPretty straightforward Day 25. https://github.com/abyala/advent-2020-clojure/blob/master/src/advent_2020_clojure/day25.clj#2020-12-2505:52Vincent Cantin@U65FN6WL9 The optimization is for the last step, to find the “shared secret”.#2020-12-2505:57euccastrobut to find the smallest loop size you need to find the loop size of both the door and key, which is actually slower than picking either arbitrarily, find the loop size of that one only, and transform the other with that#2020-12-2505:59Vincent Cantinyes, you are right.#2020-12-2506:00euccastro
;; 2437 msecs
(time
 (transform (first input) (crack (second input))))

;; 1751 msecs
(time
 (transform (second input) (crack (first input))))

;; 2980 msecs
(time (do (crack (first input)) (crack (second input))))

;; 3450 msecs
(time
 (do
   (crack (second input))
   (transform (second input) (crack (first input)))))
#2020-12-2506:31alekszelarkhttps://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_25.clj#2020-12-2506:50Vincent CantinThere is an optimization possible for the last step. It looks like: • If the loop-size is even, square the subject-number, then modulo it. Half the loop-size. • If it is even, do one step as usual.#2020-12-2506:52Vincent CantinIt will run in O(log_2(loop-size))#2020-12-2507:00Average-userBut saddly, that is not the bottleneck#2020-12-2507:01Max DeinekoOnly part 1 for me today 🙂 https://github.com/next-mad-hatter/adventofcode/blob/master/src/aoc_2020/day_25.clj#2020-12-2507:18nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2020/src/day25.clj#2020-12-2508:58erwinrooijakkershttps://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day25.clj#2020-12-2510:06Max DeinekoFor the fun of it: added baby-step giant-step logarithm computation and exponentiation as mentioned by @U8MJBRSR5 to bring the runtime for part 1 from 1300 to 1.3 ~13 msecs 🙂 https://github.com/next-mad-hatter/adventofcode/blob/master/src/aoc_2020/day_25.clj#2020-12-2513:52benoitSolution to part1. https://github.com/benfle/advent-of-code-2020/blob/main/day25.clj#2020-12-2515:33alekszelarkFor the last step you can just use .modPow. This (mod-pow pubkey loop-size module) returns an answer instantly!#2020-12-2517:18genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2020/day25.clj#2020-12-2505:51Vincent CantinThe stats are funny … so many people trying to find a way to get a problem for part2#2020-12-2505:53alekszelarkLast year I was one of them#2020-12-2505:53Vincent CantinI was also wondering … because it is my first year, I wanted to know how to do everything and not miss something.#2020-12-2505:56Vincent Cantinoh … wait … it is probably people who did not finish all the previous puzzles.#2020-12-2506:03euccastroyep 🙂#2020-12-2506:04Vincent Cantin“… day 20, you again” :rolling_on_the_floor_laughing:#2020-12-2506:04euccastroheheh, in my case I'm missing all up to 15. I'll do them at a more leisurely pace#2020-12-2506:15Alexandre GrisonYes you need 49 stars so that they give you the 50th for free#2020-12-2506:15Alexandre Grisonbut there are people who don't know they need to click#2020-12-2506:16Alexandre GrisonTook me 7 seconds to click but I was faster than 29 other peoples. Going from rank 206 to 177 :face_with_cowboy_hat:#2020-12-2506:26alekszelark> Yes you need 49 stars so that they give you the 50th for free Yes, last year I didn’t have all of them. So I just couldn’t click it.#2020-12-2603:08euccastroOK, I just finished bingeing on 1-15, to see the true ending. disclaimer: I'd seen Lambda Island's AoC 2020 videos and I had seen the Chinese Remainder Theorem spoiler https://github.com/euccastro/advent-of-code-2020/tree/master/src/advent#2020-12-2508:59erwinrooijakkersThank you! 🙂 Merry Christmas :mother_christmas:#2020-12-2509:00erwinrooijakkerswas a joy to learn from your solutions#2020-12-2509:02erwinrooijakkersand to be part of this community#2020-12-2509:05nbardiukMarry Christmas 🦌 It was fun journey#2020-12-2509:05Alexandre Grisonare the solutions archived somewhere ? I'd like to read some of them in a month or so, since I didn't solved the challenges with Clojure this year#2020-12-2509:07nbardiukwe have a pinned solution thread per day https://app.slack.com/client/T03RZGPFR/C0GLTDB2T/details/pins#2020-12-2509:14Alexandre Grisonthanks!#2020-12-2510:59Vincent Cantinthey won't be there in a month, I am afraid.#2020-12-2511:40alekszelarkhttps://clojurians-log.clojureverse.org/ for rescue#2020-12-2512:58Alexandre Grisonawesome!#2020-12-2510:04petercThanks to everyone for their code solutions and feedback. It was a wonderful learning experience and see you all next year!#2020-12-2511:11JoeI haven't finished yet, but it was fun solving all the problems, and great seeing how other people did things. I learned a lot, thank you!#2020-12-2519:12mishaand as usual "never again" opieop#2020-12-2519:31misha@a.grison https://akovantsev.github.io/corpus/clojure-slack/adventofcode.html#t1608887152 piggybacking on clojureverse's logs: all 5 years of logs in a single offline html page with filtering#2020-12-2605:37Vincent CantinDay 26 answers thread - Post your answers here#2020-12-2605:38Vincent Cantinnahhh … just kidding 🙂#2020-12-2605:51rjray😂#2020-12-2607:41alekszelarkI just got up 😅#2020-12-2614:14pezHahahaha#2020-12-2605:51rjrayMy full GH repo, with notes on things I learned, and links to a few other repos: https://github.com/rjray/advent-2020-clojure#2020-12-2612:30alekszelarkstarted solving 2015, seems not only me 😏#2020-12-2612:58Vincent CantinI would love to join, but I am busy preparing the advent-of-instaparse#2020-12-2612:41mishawhat leaderboard is this?#2020-12-2612:42mishathere is a larger one from the channel's topic: 217019-4a55b8eb#2020-12-2613:26alekszelarkhttps://lambdaisland.com/news/advent-of-code-live#2020-12-2617:38Andrew ByalaSince we're all sharing, this is a link to my Advent 2020 GitHub repo. I've only been doing Clojure for about 4 months, so I made a daily blog post that explains how the code works, as intended for beginners. I did a bunch of cleanups to make the final code pretty and theoretically reusable if I had to see it again, with a few obvious exceptions. Maybe this will help some other Clojure newbies! https://github.com/abyala/advent-2020-clojure#2020-12-2618:39euccastrohere's my AoC repo. I did 16-25 in their respective days, then I did 1-15 in a binge yesterday (having watched Lambda Island's videos), then I slept for 15 hours straight :). I thing code is relatively clean despite the circumstances https://github.com/euccastro/advent-of-code-2020#2020-12-2619:57euccastroimmediately before I'd said "[...] I'm missing all up to 15. I'll do them at a more leisurely pace" 😛... but then I'd read somewhere in the AoC website that I needed to do them all by Dec 25#2020-12-2620:58kingcodeWhy is the AoC home page listing the problems out of order? After 8 17, then I skipped over 17 to do 9, and now 16 18 15 19 10…any idea?#2020-12-2621:00euccastromaybe because numbers roughly correspond to latitudes in the map, and you do some north/south turns as the story progresses? (I haven't checked)#2020-12-2621:00kingcode@euccastro ok, thx!#2020-12-2621:55rjrayThe problems unlocked in the order of the days. The lines are different from previous years because this time it represents your travel path 🙂.#2020-12-2622:38kingcodeHmmm... interesting, but what determines the travel path? Is it just the pretty graphics and if so what is the relationship to challenge nos vs location in the graphs? Sorry for being so thick ;) #2020-12-2622:40kingcodeSo for example what would cause the “travel path” to go from day 9 to day 17? Or are we talking about time travel?#2021-12-2719:05rjrayYou don't. You go from day 9 to day 10 (jumping past 16, 18, 15 and 19), from 10 to 11, etc. Each day represents a point on your trip, some of which are in the middle of an ocean, where you are faced with a challenge. Day 12 goes up to 13 and then to 14, etc.#2020-12-2623:21euccastroboth 9 and 17 happen while you are flying. I guess at the story time of the 9th puzzle you just happened to be a bit south from where you were at the time when the 17th puzzle is set#2020-12-2623:22euccastrobecause of some storm you have to take a very indirect flight path to your vacation island; that's responsible for most of the out-of-order numbers#2021-12-2719:05rjrayYou don't. You go from day 9 to day 10 (jumping past 16, 18, 15 and 19), from 10 to 11, etc. Each day represents a point on your trip, some of which are in the middle of an ocean, where you are faced with a challenge. Day 12 goes up to 13 and then to 14, etc.#2021-12-2703:49Phil ShapiroI wish I had known about this channel while was working on this year’s AoC. This is the first year I’ve completed it, and my first time writing code in Clojure. I’m sure others have much better code but if it’s of any interest, my solutions are here: https://github.com/pshapiro4broad/advent2020#2021-12-2718:14Vincent CantinI just published the source code that I was working on, which I mentioned last week. It uses Instaparse to parse class names and generate Garden data. https://github.com/green-coder/girouette Let me know if you are interested or if you have any question.#2021-12-2719:52Jeff EvansFor day 12 part 1, is it safe to assume all rotations are by multiples of 90? My input suggests so, but that's not stated explicitly anywhere#2021-12-2719:59pezMy input suggested the same. #2021-12-2721:30kingcodethanks @rjay#2021-12-2723:51euccastroyou only need to work with your (real) input. any constraints you discover there are fair game to exploit#2021-12-2723:51euccastroand yeah, they're definitely 90 degree multiples#2021-12-2919:51Jeff Evansit seems for day 11, the most efficient solution is just to keep the input in string form (so you can repeatedly do charAt to check the various cells in constant time). see, ex: https://www.youtube.com/watch?v=1t6Monx_dsk does anyone have an approach where they actually parse the input into a grid structure, then operate efficiently on that grid? I’m trying to figure out if my solution there (which is orders of magnitude slower than all of my previous days’ solutions) can be made faster#2021-12-2921:05holymackerelsmy solution uses a grid (a map of [y x] -> seat-type), I don't remember if it was fast or not, let me try re-running it#2021-12-2921:08holymackerels😬 nope mine is very slow 8s/14s for part1/2#2021-12-2921:17Jeff Evansha, phew, not just me then 😆#2021-12-2921:52mishaHave a look at discussion and shared solutions https://akovantsev.github.io/corpus/clojure-slack/adventofcode.html#t1607671401#2021-12-2921:55Jeff Evansah, cool, so I was basically on the right track. memoized the “find nearest line of sight neighbors” function for part 2, and used transient to update the grid: https://github.com/jeff303/advent-of-code-2020/blob/master/src/advent_of_code/day11.clj#2021-12-2921:56Jeff Evansgranted I shoehorned a transducer into here, probably not really any good reason for that, but I wanted to learn more about them#2021-12-3010:08Max DeinekoYes, day 11 was the one where I had to learn a little about profiling clojure 🙂. Going from maps with coordinates as keys to vectors for storage (both state and precomputed neighbours mappings) did speed up things for me, but it took some tinkering to bring the time down to under 1s¹. Haven't tried the vector-of-vectors grid storage though. I'm surprised to see that manipulating strings as in the linked video is so fast -- but then again, I'm also rather new to java. ¹ https://github.com/next-mad-hatter/adventofcode/blob/master/src/aoc_2020/day_11.clj#2021-12-3010:15Max Deineko@U0183EZCD0D I could speed your solution up slightly with these minor edits: • Memoizing the seat counting function actually makes it slower • Neither of get-neighbours functions actually depends on the grid state, only on seat locations, which are invariant for all grid generations -- so one can memoize partial versions of those using the initial grid • Reducing + after map where latter would create a potentially expensive sequence is slower than reducing over original collection -- adapted count-neighbor-seats* accordingly. hth fwiw :)
diff --git a/src/advent_of_code/day11.clj b/src/advent_of_code/day11.clj
index a893320..bd0f1cc 100644
--- a/src/advent_of_code/day11.clj
+++ b/src/advent_of_code/day11.clj
@@ -67,12 +67,11 @@

 (defn count-neighbor-seats* [grid get-neighbors-fn seat-pred max-row max-col row col]
   (reduce
-    +
-    (map
-      #(count-seats grid seat-pred %)
-      (get-neighbors-fn grid max-row max-col row col))))
+   (fn [s e] (+ s (count-seats grid seat-pred e)))
+    0
+    (get-neighbors-fn max-row max-col row col)))

-(def count-neighbor-seats (memoize count-neighbor-seats*))
+(def count-neighbor-seats count-neighbor-seats*)

 (defn input-line-to-grid-row [line]
   (into
@@ -118,7 +117,7 @@
                                (let [impacted-neighbors
                                      (filter
                                        some?
-                                       (get-neighbors-fn grid max-row max-col row col))]
+                                       (get-neighbors-fn max-row max-col row col))]
                                  #(into % impacted-neighbors)))
            check-next (:check-next acc)
            update-fns (:update-fns acc)
@@ -191,7 +190,7 @@
    (day11-part1 "input_day11"))
   ([input-res]
    (let [grid (get-input-grid input-res)
-         [rounds final-grid] (run-until-stable grid get-adjacent-neighbors 4)
+         [rounds final-grid] (run-until-stable grid (memoize (partial get-adjacent-neighbors grid)) 4)
          final-counts (for [i (range 0 (count final-grid))
                             j (range 0 (count (first final-grid)))]
                         (count-seats final-grid #(= :occupied %) [i j]))
@@ -203,7 +202,7 @@
    (day11-part2 "input_day11"))
   ([input-res]
    (let [grid (get-input-grid input-res)
-         [rounds final-grid] (run-until-stable grid (memoize get-line-of-sight-neighbors) 5)
+         [rounds final-grid] (run-until-stable grid (memoize (partial get-line-of-sight-neighbors grid)) 5)
          final-counts (for [i (range 0 (count final-grid))
                             j (range 0 (count (first final-grid)))]
                         (count-seats final-grid #(= :occupied %) [i j]))
#2021-12-3015:38Jeff Evansthanks, @U9TGHG3LP. extremely helpful!#2021-01-0214:56kingcodeI used a sparse map together with dimensions in a duple e.g. [{[ 4 5] :floor [7 2] :taken …}, dims] storing only the floor and taken seats. Part 1 was fast enough, but Part 2 took 66 seconds: interestingly if I use transducers in pipelines the time goes up to 88+ seconds, because the lists are deltas (<= 8 size colls). So unless you have to iterate on an entire 2D grid, they are probably not worth it. At some point I regretted not sticking to the string format bc it’s much easier to debug with graphic printouts, but writing a rendering fn wasn’t so bad, and the map format made the logic cleaner it seems. I find the fun part of most challenges especially this one, is refactoring the Part 1 code to reuse it with tweaking:
(defn surrounding-occupants [[grid dims] seat]...)
(defn visible-occupants ...)
(defn stabilize [plan occupancy-fn crowd-siz]...)
#2021-01-0302:30holymackerels> I find the fun part of most challenges especially this one, is refactoring the Part 1 code to reuse it with tweaking: I like this part too. I have a love/hate view towards the part 2's that simply scale the problem up so that you need to have an efficient solution (either by 'getting the trick' or writing it a way focused on performance). On one hand its fun to be forced to think about optimization. On the other hand it ends up being (for me at least) "part 2: throw away all that terrible code you wrote for part1 and do it better"#2021-01-0302:33Jeff EvansI get the sense that the "part 1 refactoring" bit is much easier in Clojure as compared to, say, Java. Well, as is doing part 1 in the first place. 😁#2021-12-3017:48kingcodeBONUS for day10: Make a lazy-seq of all arrangements. You just dropped a bunch of your jolts on the airport toilet floor and some will take days to dry, and you can’t tell which ones have their circuits shorted. Since you need something fast and the basic sequence (all jolts in order) and likely many others are not usable, you gotta try a whole bunch of arrangements in a hurry in order to plug your device... ;)#2021-12-3110:38ChristianI am new to clojure and I make my way through the aoc2020 problems. I'm interested in your opinions about my day12 code. In python I would check the values and update some data, but with clojure I wanted to stay with away from mutables for the time being. There is two things I noticed. part1 and part2 are very similar but I dont know how to make it more compact. (would you prefer a github link to this?)
(ns advent-of-code.day-12
  (:require [clojure.edn :as edn]))

(defn update-position
  "returns the coordinate changes from an instruction"
  [instruction northsouth eastwest facing]
  (let [code (first (re-find #"[NSEWLRF]" instruction))
        number (edn/read-string (re-find #"\d+" instruction))]
    (cond
      (= code \N) [(+ northsouth number) eastwest facing]
      (= code \S) [(- northsouth number) eastwest facing]
      (= code \E) [northsouth (+ eastwest number) facing]
      (= code \W) [northsouth (- eastwest number) facing]
      (= code \L) [northsouth eastwest (mod (+ 360 (- facing number)) 360)]
      (= code \R) [northsouth eastwest (mod (+ 360 (+ facing number)) 360)]
      (= code \F) (cond
                    (= facing 270) [(+ northsouth number) eastwest facing]
                    (= facing 90) [(- northsouth number) eastwest facing]
                    (= facing 0) [northsouth (+ eastwest number) facing]
                    (= facing 180) [northsouth (- eastwest number) facing]))))

(defn part-1
  "Day 12 Part 1"
  [input]
  (loop
   [instructions input
    northsouth 0
    eastwest 0
    facing 0]
    (let [instruction (first instructions)
          otherinstructions (rest instructions)
          [newns, newew, newface] (update-position instruction northsouth eastwest facing)]

      (if (empty? otherinstructions)
        (+ (Math/abs newns) (Math/abs newew))
        (recur otherinstructions newns newew newface)))))

(defn update-position2
  "returns the coordinate changes from an instruction"
  [instruction northsouth eastwest shipNS shipEW]
  (let [code (first (re-find #"[NSEWLRF]" instruction))
        number (edn/read-string (re-find #"\d+" instruction))]
    (cond
      (= code \N) [(+ northsouth number) eastwest shipNS shipEW]
      (= code \S) [(- northsouth number) eastwest shipNS shipEW]
      (= code \E) [northsouth (+ eastwest number) shipNS shipEW]
      (= code \W) [northsouth (- eastwest number) shipNS shipEW]
      (= code \F) [northsouth eastwest (+ shipNS (* number northsouth)) (+ shipEW (* number eastwest))]
      (= code \L) (cond
                    (= number 90) [eastwest (- northsouth) shipNS shipEW] ;; n=a e=b => n=b e=-a) 
                    (= number 270) [(- eastwest) northsouth shipNS shipEW]
                    (= number 180) [(- northsouth) (- eastwest) shipNS shipEW])
      (= code \R) (cond
                    (= number 270) [eastwest (- northsouth) shipNS shipEW] ;; n=a e=b => n=b e=-a) 
                    (= number 90) [(- eastwest) northsouth shipNS shipEW]
                    (= number 180) [(- northsouth) (- eastwest) shipNS shipEW]))))

(defn part-2
  "Day 12 Part 2"
  [input]
  (loop
   [instructions input
    northsouth 1
    eastwest 10
    shipNS 0
    shipEW 0]
    (let [instruction (first instructions)
          otherinstructions (rest instructions)
          [newns, newew, newShipNS, newShipEW] (update-position2 instruction northsouth eastwest shipNS shipEW)]
      
      (if (empty? otherinstructions)
        (+ (Math/abs newShipNS) (Math/abs newShipEW))
        (recur otherinstructions newns newew newShipNS newShipEW)))))
#2021-12-3111:40mishaIt looks ok. Replacing cond with case or condp would save you a bunch of typing though. If it would be the code you had to maintain, it would make sense to replace loop with a step function, and a (->> state (iterate step) (drop-until done?) first calc-score) "pipeline", to decouple done condition from step logic, and make step function testable and replaceable, etc. But in the context of aoc - it is perfectly fine as is.#2021-12-3112:40ChristianI had case first, but it would not evaliate my code#2021-12-3113:01mishacan you show me?#2021-12-3114:23ChristianAh, it was another day. I think I was trying to compare my value to something. Like if x is smaller than 4 and bigger than -14. and that would not work.#2021-12-3115:00Max DeinekoApart from case and cond there's also core.match for when you'd prefer something like
(match [code (/ number 90) (<= 4 x 13)]
  [\N _ true] (do-something)
  [\R d _] (rotate-smth-by d))
#2021-01-0220:40kingcodeI use the cycle fn to do rotations. Also I find the most enjoyable part is to ‘clean up’ after part 1 and first modularize part 1 and retest, than add your part 2 tweaks on top of that. A good rule of thumb is to keep each function to 3-10 of no more than 80 columns for easier reading. Cheers!#2021-01-0220:42kingcode...”3-10 lines whenever possible...”, sorry#2021-12-3118:48StuartI'm having trouble understanding the logic for day 17
If a cube is active and exactly 2 or 3 of its neighbors are also active, the cube remains active. Otherwise, the cube becomes inactive.
    If a cube is inactive but exactly 3 of its neighbors are active, the cube becomes active. Otherwise, the cube remains inactive.

z=0
.#.
..#
###

After 1 cycle:

z=-1
#..
..#
.#.
How does top left in z=-1 turn on? It has 1 neighbour that is on (the top middle on z=0)
#2021-12-3118:52holymackerelsthe examples for this one are confusing, it's not keeping like [0 0] on the top left, its always centering the display around the visible active ones#2021-12-3118:53Stuartaaaaah#2021-12-3118:53Stuartthanks!#2021-12-3118:54holymackerelsits mentioned but briefly, I spent way to much time trying to make sense of the examples until someone pointed it out to me: > (and the frame of view follows the active cells in each cycle)#2021-12-3118:54Stuarti saw that and didn't understand what it meant 😞#2021-01-0418:52erwinrooijakkers#2021-01-1422:40Jeff Evanswhy is this not being lazy? (this is for day 15, part 1)
(defn get-spoken-num [accumulator number last-val]
  (lazy-seq
    (let [last-seen (get accumulator last-val)
          last-round-num (dec number)
          seen-before? (and (some? last-seen) (< last-seen last-round-num))
          this-round (if seen-before? (- last-round-num last-seen) 0)]
      (cons 
        this-round 
        (get-spoken-num
          (assoc accumulator this-round number) 
          (inc number) 
          this-round)))))
#2021-01-1422:41Jeff Evanshmm, actually maybe it is ( take 10 (…) works fine). I guess evaluating the full lazy sequence in the REPL actually traverses it#2021-01-1521:25misha@jeffrey.wayne.evans eval
(set! *print-length* 100)
first. evaling infinite seqs in repls realizes them because print (as in REPrintL) is eager
#2021-01-1521:29Jeff Evansah, right, forgot about printing. thank you!#2021-01-1804:26euccastroscreencast of ztellman's solution to day 17: https://www.youtube.com/watch?v=lU3awBr5C7E#2021-01-1804:27euccastroa somewhat cruel reaction to Robert Martin's: https://www.youtube.com/watch?v=umKbM5SwLq4#2021-01-1805:17potetmwtf how did it possibly take 2 hrs & 160 lines of code?#2021-01-1805:17potetmidk, I haven’t done it, but glancing at Zach’s solution, the difference is stark#2021-01-1805:18potetmI’m probably extra harsh on BM because he repeatedly gives terrible advice as if it were handed down from on high.#2021-01-1805:18potetm(And, remarkably, people believe him.)#2021-01-1809:09ChristianTook me a while to get from Robert to Bob as in RM to BM.#2021-01-1812:30StuartUncle Bob makes me think of someone who learny programming 30 years ago, and still programs like its 30 years ago#2021-01-1812:32Stuarti dont understand his popularity#2021-01-1812:39roelofWhat do your experts think of the videos of lamda island?#2021-01-1812:40Stuartim not an expert, but as a clojure beginner, i really liked lambda islands daily aoc videos#2021-01-1812:40Stuarti learnt some neat things from them#2021-01-1812:41roelofI also but I do not know if I learned then good idiomatic clojure code#2021-01-1812:41roelofbut I l like his explanations#2021-01-1812:55ChristianUB has a lot of blog posts like these: https://blog.cleancoder.com/uncle-bob/2019/08/22/WhyClojure.html should they be taken with a grain of salt? I don't want to quote him in my paper, when the "scene" thinks he is not always on the best of paths#2021-01-1813:35MnoStill makes me happy that he likes it, because it bodes well that if someone could convince Uncle Bob that it’s nice.. then it’s possible to convince just about anyone 😅. Also since he does garner attention it did give some attention to Clojure in general which I always appreciate#2021-01-1813:41MnoUncle Bob has a lot of firm opinions based on a mix between experience and the dogmatic belief that programmers are engineers that should be held to similar rigorous standards, which makes him prefer ideas like Test Driven Development. His vocality and personality make him seem a little confrontational/adversarial to those who prefer to keep discussion open, and so that’s what I believe causes the main pushback against him. Personally I’d probably use him if I could use him to demonstrate that a diverse group of people (including him) agree on a topic. Also I’m ending this rant here because it’s a bit off-topic for the channel.#2021-01-1814:47potetmNo.#2021-01-1814:47potetmHe gives terrible advice.#2021-01-1816:06MnoThat sounds like something he would say about anyone else. I’m personally not confident enough to assert any advice is good or bad (or terrible in this case). #2021-01-1816:08MnoI can say I’m not very convinced by his ideas to be honest, and that I don’t believe they’re the great advice for most people and cases. But that depends more on context than what he’s saying outright.#2021-01-1814:47potetmAnd his adherents pretend like it’s The Good Advice.#2021-01-1814:48potetmIt has little to do with “his vocality and personality,” (which, as you say, are grating).#2021-01-1814:48roelofit that the same uncle Bob from c# ?#2021-01-1814:48potetmpretty sure there’s only one 🙂#2021-01-1814:50StuartC# ? I would have thought Uncle Bob was known for Java / C++ more than C#. I must've missed his C# period#2021-01-1814:54potetmNot to mention the fact that he also happens to be a total jerk.#2021-01-1814:54roelofno idea. nver met him#2021-01-1814:54potetmI’ve seen him sic his followers on my friends because he didn’t like a decision that he knew absolutely nothing about.#2021-01-1816:11MnoThat’s unfortunate, I see why you dislike the guy then.#2021-01-1814:55potetmAll because of his personal crusade against “SJWs.”#2021-01-1814:56roelofand what are sjws ??#2021-01-1814:56Stuart"Social Justice Warriors"#2021-01-1814:56StuartI think he got cancelled from a conference after a controversal twitter post.#2021-01-1814:56euccastroto be fair, it's easy to spend an indefinite length of time in an AoC challenge if you miss the key insight. that says little about the soundness (or otherwise) of his methodology#2021-01-1814:57Stuartyeah, some of the challenges this year took me a good few hours!#2021-01-1814:57StuartI just had a blind spot on the insight on a few of them and ended up going down all sort of wrong rabbit holes#2021-01-1814:58potetmYeah, my initial statement had nothing to do w/ the problem. I didn’t do it. I just glanced at Zach’s solution.#2021-01-1814:58euccastropersonally I find it nuts to use TDD for AoC challenges unless you want to get specific practice on that or show it off, but I doubt that accounts for the time overhead#2021-01-1814:58potetmSo it was more, “Dude A took 20min. wtf took 2 hrs?”#2021-01-1814:59potetmDidn’t mean to say everybody should take 20min.#2021-01-1814:59euccastroI haven't seen this screencast by Uncle Bob, but I bet it's failing to realize that an infinite space calls for a sparse representation#2021-01-1814:59euccastrosomething that Zach jumped to immediately#2021-01-1815:00roelofI can image that for some days I will take maybe multiple days because im a beginnner in clojure#2021-01-1815:00euccastroI've seen people in this channel struggle with that, then come out with brilliant solutions in other challenges#2021-01-1815:01Stuart@roelof, 'im the same. BUt its good to solve the problem and then come here / youtube to see other good clojure developers solution. You can learn a lot of useful functions that I find I often end up implementing myself because I didn't know they existed#2021-01-1815:01roelofI hear now things I never heard before like sparse represantation#2021-01-1815:03euccastroin some other challenge everyone seemed to get immediately that a mutable linked list was called for. I took forever to come up with a solution that run in 30+ minutes by just failing to think of that#2021-01-2404:37kingcodeFWIW, I agree that sparse storage is best, but immutable state is a must. I used maps since vectors puke on negative idxs. Also generate move increments for any sized dim. with math.combinatorics/selections is a real time saver. Finally, the key for speed is to only use neighbours to scan for next state, use ‘iterate to produce states et voilà. I spent time to write a rendering module to go through each cycle against the sample diagrams. It took 2 days but was a lot of fun. For me by far the hardest was fay 13 so far, currently on day 18. Cheers! #2021-01-2613:20euccastroyes, I don't know how one would solve 13 without knowing about the Chinese Remainder theorem#2021-01-2821:06kingcodeUncle Bob has an interesting video on day 13 with a simple and fast solution, which positions the cursor on the current bus Id, then skipping (next id number of items) ’til the next one lines up and so on.#2021-02-0100:40euccastroI'll check it out, thanks!#2021-01-1815:05euccastro@roelof in the context of this challenge, sparse representation means that you only represent the cells that are active, not the whole space (which is impossible, since it's infinite) nor a "box" around the active cells#2021-01-1815:06roelofoke thanks#2021-01-1816:19ChristianI'm study CS at uni and we were asked to use Test Driven Development wherever possible because it is safe and secure and the code writes itself when you have the tests. Why is that bad in clojure? I always feel bad becuase I skip making tests#2021-01-1817:09potetmThe problem isn’t that TDD is bad in clojure. The problem is that it doesn’t do those things. It doesn’t make anything safe, secure, and the code doesn’t “write itself.”#2021-01-1817:10potetmThere are upsides to TDD Proper (i.e. test first). There are upsides to having a test suite.#2021-01-1817:12potetmBut things like, “safety” or “security” are the result of a lot of decisions, and the test suite is way down the list of important things.#2021-01-1816:27MnoIt’s not necessarily bad, it’s a strategy that has it’s tradeoffs. In the case of advent of code.. maintainability is not something that is strongly valued and which is what TDD is supposed to give you in return for writing more code (for testing).#2021-01-1816:30Max DeinekoQuestion's probably good fit for #testing 🙂 (Can one cross-post in slack? I don't see it)#2021-01-1816:30MnoIn clojure in general tests and specs are used quite a bit, but REPL driven development or Data Driven Development are more common, for various possible reasons.#2021-01-1816:31MnoGood shout Max!#2021-01-1817:09potetmThe problem isn’t that TDD is bad in clojure. The problem is that it doesn’t do those things. It doesn’t make anything safe, secure, and the code doesn’t “write itself.”#2021-01-1817:25pez@roelof, without having read all messages since you asked about lamdaisland (aka @plexus) , for all I can tell, that is showing super-duper idiomatic Clojure coding, and coding habits you can take inspiration from with great benefits. The only thing I disagree with is that he is not using Calva. 😃#2021-01-1817:26roelofthanks, I saw also a teacher whch making and explained this but he does it totally a other way then plexus#2021-01-1817:26roelof@pez#2021-01-1817:34pezThere is no One True Way, so might be perfectly valid both of them. But when I see Arne code I just want to be that good, all the time. I’m virtually drooling.#2021-01-1817:41roelofI can image, I tried to follow him and I cannot all the time#2021-01-1817:42roelofI saw one videoo where he uses bit-map things#2021-01-1819:01Joe> I'm study CS at uni and we were asked to use Test Driven Development wherever possible because it is safe and secure and the code writes itself when you have the tests. Why is that bad in clojure? I always feel bad becuase I skip making tests The test-first TDD approach does a lot of stuff, and one of them is creating short feedback loops between writing small pieces of code and running it to see if it works the way you think it does, which you don't otherwise have in a lot of languages. Clojure already has a built in, ubiquitous mechanism for that same thing: the REPL. So that benefit falls off a bit in Clojure. Not doing TDD doesn't imply you shouldn't have tests at all though, there are lots of other benefits of having a test suite. More generally where I see TDD fall down in practice is when it's used to try to 'discover' an algorithm. Bob's AoC videos I think have lots of good examples of this. Another is the infamous Ron Jeffries attempt to write a Sudoku solver. In cases like that it's much more effective just to think about the problem for a while, maybe with a pen and paper. TDD is too rigid/mechanistic.#2021-01-1915:21slipsetA bit late to the party, but I found https://www.potetm.com/video/aoc-2018-d01.html video of a guy spending an hour solving the first AOC puzzle from 2018 super interesting.#2021-01-1916:30potetmXD#2021-01-1916:31potetmA whole hour on day 1? Fire that guy.#2021-01-1916:35slipset But seriously, I’ve only see two of your screen casts, but they were very good both of them. You really got across what you intended, and it was super interesting to see how hard the imperative version was, even for you. #2021-01-1916:36MnoI really enjoyed the fact that you did the 2nd part in many different ways. Especially the transducer version was particularly interesting.#2021-01-1917:22potetmThanks ya’ll. It’s good to hear that they’re helpful!#2021-01-1919:05ChristianI used aoc to get into FP and clj. You bet it took my hours for many of those 😄#2021-01-2403:11ACI don’t have an answer for why your code ran slow, but I used the clojure reader to handle parsing day 18 --
(defn parse-expr
  [s]
  (read-string (str "(" s ")")))

> (parse-expr "((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2")
(((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2)
#2021-02-1315:44kingcodeI am curious to know... which challenges were hard for tou?#2021-02-1320:03ACI found 2020 to be mostly straightforward. for me, the trickiest for that year were: day20 - I had a few bugs that didn’t show up in test cases for part1 and that caused problems in part2 day23 - I had to learn more about type annotations to get my solution to run in seconds instead of days. 🙂#2021-02-1320:19kingcodekool @AC I am still on 20, and just saw the light at the end of the tunnel - fun stuff…#2021-02-1323:34StuartI need to get back to this year, I only got up to day 16 before I had too much stuff to do with family that I couldn't find time to work on it. But up to day 16 it was all fairly straight forward. Apart from day 14, I couldn't get a working solution to part 2.#2021-02-1416:17kingcodePart 2 is always a challenge, but once done, very satisfying. For me 10, 13, 19 were significant challenges so far.#2021-02-1416:22kingcode@AC interesting - I am currently working on day 20 part 2. I would think that once the corners are figured out shouldn’t it be linear? Just grab any corner as the top row/col [0 0], then use whichever transform will match an already indexed tile etc…I’m sure there is more 🙂 Ooops sorry, I just realize you were talking about 23#2021-02-1416:44Phil ShapiroI solved day 20 part 2 that way, by picking a corner and placing tiles. It ended up being a fair amount of code. Afterwards I thought that it might’ve been better to place any tile and match tiles to open edges. Once you know which side a tile goes on, you can use a matrix transform to move its pixels into place. Assuming you represent a tile as set of pixels. #2021-02-1416:48kingcodeIndeed, that’s my strategy as well - probably will try parallelizing on all four corners. The transforms are straightforward with rotation matrices which also take care of flipping. But of course as you say there are all kinds of nifty details…early on, one for me was to re-center/re-scale the tile’s coordinates around the origin in order to do rotations smoothly, then restore to ‘printable’ coords - fun stuff.#2021-02-1711:52JoeI struggled with some of the problems where the natural (and efficient) solution was ‘bash on this array <tel:1000000|1000000> times’. It introduced me to int-array, aget, aset etc, but it always felt quite clunky compared to doing similar things in a traditional loopy imperative language. Is this just something that Clojure is not idiomatic for, or is it more a case of getting used to the pattern?#2021-02-1714:32Phil ShapiroMy take is that the need for this kind of optimization doesn’t come up often. When it does, there are ways to get around it without having to write something in Java (or C). If there was more need for this, then most likely Clojure would evolve to have better support for it. For advent2020, I only needed to do this once, for day 23.#2021-02-1722:59ACsame here - int-array + type-hinting made my day 23 solution run in seconds vs days.#2021-02-1800:01Jeff EvansIs that significantly faster than using a transient vector with assoc! ?#2021-02-1800:08Phil ShapiroNo idea about using assoc! I did try a few things on the way to aset/aget but they were too slow. If you want to try it out, my code is here: https://github.com/pshapiro4broad/advent2020/blob/main/src/day23.clj#2021-02-1815:22Max DeinekoMy solution for day 23 runs in abount 9s with int-arrays, 13s with transient vectors, 18s with vanilla vectors here. fwiw & hth: https://github.com/next-mad-hatter/adventofcode/blob/master/src/aoc_2020/day_23.clj (transients) & https://github.com/next-mad-hatter/adventofcode/blob/master/src/aoc_2020/day_23_inplace.clj (int-arrays)#2021-02-1816:37Jeff Evansfascinating. thanks for sharing!#2021-02-1817:11pavlosmelissinosI really struggled with day 7. I tried to solve it without recursion. Modeling the data into a structure that made sense to me was kinda hard but was nothing compared to coming up with the ugly, imperative code that did the actual computation 😛(inspired by the topological sorting algorithm; I used 2, or maybe 3, atoms). It's not public yet but I'll probably put it on gihub as soon as I get a little bit further. 1. Any of you come up with a pretty non-recursive solution? 2. The recursive solution feels much more natural to me, so I've also been wondering: why is recursion so frowned upon and more or less considered "inferior" to an iterative approach? I understand that in some cases it's hard to understand but in this case I really don't see any reason to avoid it.#2021-02-1820:11Max DeinekoOne should take advice from people who consider recursion inferior with massive grain of salt afaiac 😉 Fwiw, or mayby luckily, this (it being frowned upon) had never been my experience. Which isn't to say recursion is equally useful in every programming language -- not every language supports tco, and even less support unlimited recursion in general. But if one wants to avoid mutable state there's no way around it.#2021-02-1817:27Jeff EvansAFAIK, the only non-recursive approach to topo sorting is to use a stack and do DFS, right? I have no clue how that would work in idiomatic Clojure. This is one of the top hits on Google, and it’s using recursion: http://hueypetersen.com/posts/2013/06/25/graph-traversal-with-clojure/ The examples here are also using recursion: https://github.com/life0fun/clojure-idiom/blob/master/graph.clj#2021-02-1818:39pavlosmelissinosIndeed, stack + dfs is how I did it and it's probably the most unidiomatic thing ever written 😂 thanks for the response and the links 🙂#2021-02-1819:54Max DeinekoIf you have some priority queue implementation then topological sort can be written as rather simple "loop" (whether it is expressed recursively or not is another matter somewhat)#2021-02-1820:00Jeff Evanstrue, the pseudeocode on the Wikipedia article does just that#2021-02-1820:36Max DeinekoFrom what I've heard, this year's aoc was a bit easier than some previous entries. I think I spent most time on (and had most fun with) day 11, seeing how far I could speed it up. Second would probably be day 23, trying out and comparing different vector types. The part I enjoyed the least was probably the last part of day 20, was a bit too long for me. And day 15 I cheesed, didn't feel like doing it at all 🙂#2021-02-1821:19Phil ShapiroWas that day 15 or 13? Because day 13 was a really hard one for me. And I agree day 20 part 2 was a lot of work. Most of the other days weren’t that bad. Overall it seemed easier to me than 2019, which I got about 1/2 way through, or 2018, which I also didn’t finish. #2021-02-1821:25Max DeinekoI skipped implementing day 15. For day 13 I had to dust off and look up some long forgotten math, but coding it wasn't that bad.#2021-02-1821:30Max Deineko2020 is the first aoc year I took time to solve all problems (but not in december :)), only did a couple from 2018 before that, so cannot myself comment on difficulty compared to previous ones, only hearsay#2021-02-1821:43Max Deinekoof course, the difficulty is somewhat subject to variation depending on which building blocks of the solutions one is willing to take from libraries -- 2020's days 18 and 19 would have definitely been more work without instaparse 🙂#2021-02-1821:57Phil ShapiroI don’t really know clojure, doing advent2020 was my first use of it so I didn’t know about instaparse, although I did look at it for day 18. I ended up doing something cheesy with regular expressions. I’m sure using a proper parser would’ve been cleaner. #2021-02-1822:32Max DeinekoAh, similar story here :) Took aoc as opportunity to practice clojure, whenever people mentioned libraries here, put them on my to-check-out list..#2021-02-1822:52Max DeinekoI guess some would only consider implementing a complete parser to be proper solution.. But that's the nice thing about aoc, only you get to set your goals and constraints :)#2021-04-2208:14kjI've started working through Advent of Code 2020 while trying to learn Clojure, and I've just noticed that the challenges aren't being displayed in numerical order. The story doesn't make any sense if I follow them top-to-bottom (planes landing before they've taken off etc.), but can anyone who's already completed them tell whether they've been re-ordered in terms of difficulty? Or has something just gone a bit haywire?#2021-04-2208:29nbardiukI believe it is to support the story, a problem is aligned with position on the map. The hero is traveling all over the world and challenges are not aligned. In general problems are not ordered by complexity, you can try to figure out complexity by looking at leaderboard for each day to see how long it took to solve them for competitive people https://adventofcode.com/2020/leaderboard/day/9 . But this will not tell how hard it would be for you, if you are not into competitive programming#2021-04-2208:32kjAh, I see, I hadn't even realised that was a map! That makes sense now, thank you!#2021-04-2210:53MnoIn general it does tend to be harder in the later days, but that also may vary wildly depending on where your hobbies/skills lie. Some are efficiency problems others are math oriented, others are just complicated logic, its a really mixed bag, which is what makes it awesome#2021-04-2210:54MnoSo day 10 might be 3 times harder for you than day 11, but it could be the easiest for someone else because they reading about binary trees recently#2021-04-2210:55MnoGood luck!#2021-04-2212:03pezIt started to get too hard for me at day 14 iirc. At day 17 I had to drop out and become a spectator, b/c it took too much of my time. I had wonderfully fun all the 25 days, much thanks to this channel.#2021-04-2215:49StuartIm glad to hear othrr people found day 14 hard. I couldn't get both stars tjst day and also stopped around 17/18 ish. I always assume that im jist a shitty dev for not finishing. So im happy others find it hard!#2021-04-2215:58pezHaha, I feel both impressed and a bit depressed when I see vides like this: https://www.youtube.com/watch?v=lU3awBr5C7E#2021-04-2214:53John Flinchbaugh2020 was a little easier to skip a day or a part2, so i made it pretty far with some skips. it did get hard at times.#2021-05-0312:00ryan echternachtDefinitely this. 2019's opcode thing was cool, but made skipping near impossible#2021-04-2214:54John Flinchbaughthere were times it felt like it was built to be solved functionally with list structures.#2021-05-2020:25JoeI'm trying to do https://adventofcode.com/2015/day/6 part 2 which involves a conceptually simple problem. Described one way, you have a 1kx1k array and given several 'boxes' of indices within that array you have to change the values at each of those indices in the array (+1, -1, +2 depending on the instruction). Part 1 was a simple binary on/off. I solved it using sets of coordinates and unions/intersections, but it was very slow (~30seconds). For part 2 I could go down the route of a double reduce with a map of coord->value, but I'm guessing that will also be very slow. The solutions I've seen in languages like Rust seems to handle just looping through the instructions and banging on an array no problem. Should I look at just using a 1kx1k array here, and would that be more performant (like in the sub-5 second range)? Or is there another way to think about this problem? https://github.com/RedPenguin101/aoc2015/blob/main/src/aoc2015/day6.clj#2021-05-2020:38JoeYeah, the map solution worked but took ~40 second#2021-05-2020:57spfeifferI remember using mutable primitive arrays there for performance reasons.#2021-05-2108:34chrisblommaking current transient might help#2021-05-2108:35chrisblombut you would need to adapt union/difference/exclusive-union to work with a transient set#2021-05-2108:38chrisblomthe mutable array approach will be faster i think, hard to beat that approach#2021-05-2109:26JoeGotcha, thanks!#2021-06-2815:42Noel LlevaresI had a tech test for a job application where the problem was for a given n pairs of brackets, calculate the number of possible valid (open/close) combinations. e.g. • 2 pairs => ()(), (()) answer = 2 • 3 pairs => ()()(), ()(()), (())(), ((())), (()()) answer = 5 I started with a brute-force solution: 1. Generate all possible permutations of the brackets. 2. Remove duplicate permutations. 3. For each permutation, check if it is valid. Obviously, the above solution is poor. I’d like to be better and learn. So, how would you approach this problem?#2021-06-2816:47tschadyLook at your examples, moving from 2->3. There’s a pattern there. You can extrapolate this. I’m also confident there’s an O(1) formula that spits out the answer. If you want more hints lmk.#2021-06-2816:50tschadylots of interview questions work this way. Figure out an approach that goes from level N to level N+1 and you’re mostly there.#2021-06-2817:22yubrshenFor induction from n to n+1, consider the cases of 1. () and. n-1 case [a pair of closed brackets, followed by the rest of n-1 brackets closed in whatever fashion.] 2. n-1 case and () [reverse of 1. above] 3. (n-1 case) [a pair brackets enclosing the rest of n-1 brackets closed in whatever fashion.] The above 1. and 2 are symmetry, and need to minus the duplicates.#2021-06-2817:25yubrshenSo f(n) = 3*f(n-1)-1#2021-06-2817:29nbardiukfor brute-force solution I would go with trees - balanced brackets represent some sort of a tree. Case n+1 takes all previous trees and for each node in those trees tries to add new node to the left, to the right and a child#2021-06-2817:30nbardiuk
(require '[clojure.zip :as zip])

(defn locations [z]
  (when-not (zip/end? z)
    (lazy-seq (cons z (locations (zip/next z))))))

(defn add-node [tree]
  (let [ls (->> tree zip/vector-zip locations)]
    (->> (concat
          (map #(zip/insert-child % []) ls)
          (map #(zip/insert-left % []) (rest ls))
          (map #(zip/insert-right % []) (rest ls)))
         (map zip/root)
         set)))

(defn trees [n]
  (case n
    0 []
    1 (add-node [])
    (->> (trees (dec n))
         (mapcat add-node)
         set)))

(defn parens [n]
  (count (trees n)))

(->> (range 10)
     (map parens))
; => (0 1 2 5 14 42 132 429 1430 4862)
#2021-06-2817:35nbardiukLooks like closed formula is a https://en.wikipedia.org/wiki/Catalan_number#2021-06-2817:40nbardiukI would not be able to come up with the formula during interview#2021-06-2817:42tschadyno, but I think you’d get credit saying you know there’s likely an O(1) formula and you’d use OEIS to get it.#2021-06-2817:44nbardiukGood point, the intuition that sequence should have a formula would be enough for me if I was giving such task.#2021-06-2819:10yubrshenThe way of thinking in recursion, or mathematically, in deduction can give us a long way forward sometimes.#2021-06-2906:42Noel LlevaresThank you @tws, @yubrshen, @nbardiuk. I spent a considerable time thinking of an O(1) answer and when I failed to come up with one, I just settled for a brute-force. I still have a long way to go. I can build full-stack apps, microservices, CI/CD pipelines and data pipelines but algorithms is a hard one. I have no computer science/engineering background so I’m working hard to catch up on these. To be honest, 90% of what you guys said above sound alien to me but I will do my best to be better.#2021-06-2908:29spfeifferI do not know if this helps you in your case, but i feel algorithm related interview questions are absolutely useless for assessing engineering performance on real life problems. Besides some edge cases, you will not need to implement low level algorithms. What these exercises perhaps show is how you work towards any solution, may it as bad as it can be, not about to show you can deliver a „good“ solution to an artificial problem under pressure.#2021-06-2906:45pezThanks for posting this question, @noelmartin! I learn a lot reading the answers. Of course thank you all answering as well. 😃#2021-06-2907:31nbardiukTo be honest in real life interview under stress I would go with brute force solution as you did. The solution with trees is too complex for me to do without rereading docs. And the O(1) solution I've found only after implementing brute force and searching internet for this sequence of numbers. Thanks for puzzle, it was fun 🙂#2021-06-2907:35slipsetOn or off topic, but still https://www.darkcoding.net/software/a-day-in-the-life-of-a-professional-software-engineer/#2021-06-2907:36slipsetNot that many devs actually have to solve the kind of problems you get in interviews. But some regard those problems as a good proxy for how you’ll perform in a job. Others do not. #2021-06-2910:53tschadyFWIW, this is very similar to problem 8.14 from Cracking the Coding Interview. Even mentions Catalan numbers as something nobody would be expected to know. Goes through a few different approaches.#2021-06-2910:55tschadyits all just part of the Interview-Industrial Complex. :face_vomiting:#2021-08-2419:24JoeDoes anyone have a good answer to https://adventofcode.com/2019/day/18 (Part 1)? It's the one with the maze, keys and doors. I can't seem to get it down to a reasonable time.#2021-08-2608:48pavlosmelissinosHaven't tried it, so I'm not 100% sure, but you might be able to reduce this to a shortest path problem which is O(nlogn). I don't know if that will get you to subsecond performance though (depends on the size of the input)#2021-08-2601:57AChow do you define “reasonable time”? 🙂 I didn’t spend any time optimizing, so mine runs in 27s. I’m pretty sure there’s some insight I missed.#2021-08-2608:23JoeHaha, like sub-second I guess#2021-08-3008:19erwinrooijakkersMine runs in 27s too 😉#2021-08-3008:20erwinrooijakkerswith bfs no optimization#2021-08-3008:21erwinrooijakkershere are examples of algorithms with reasonable sub-second times: https://old.reddit.com/r/adventofcode/comments/ec8090/2019_day_18_solutions/#2021-08-3011:05Joethanks!#2021-11-1419:25tschadywrote my first https://github.com/tschady/advent-of-code/blob/main/script/update_badges.clj for some advent-of-code README eye-candy:#2021-11-2912:15genmeblog@U1Z392WMQ where to find a .session file?#2021-11-2912:16tschadythat’s your logged-in cookie from advent of code. you can see it in chrome dev tools.#2021-11-2912:16genmeblogah, ok, thanks#2022-01-0703:14kingcode@U1Z392WMQ very cool! How did you learn to do this? How do you make it work within github site?#2022-01-0713:49tschadylearned it by puttering around for a decade. The script creates the image, which I then put into the README markup like any other. I have to run this manually every time I solve a new one. Sometime this year I’ll make it a GitHub Action.#2021-11-1623:27tschady2nd bb script to download problem input, because you know, that’ll save me 4 seconds#2021-11-2817:50tschadyfinally finished 2020#2021-11-2818:01roelofpff, I did not come further then day 5 of 2020 😢#2021-11-2911:20StuartI tapped out at 34 stars on 2020#2021-11-2912:09pezIt started to consume way to much of my time at day 15 or something for me. I think I will not engage as much this year around. It would be good for my skills, but I don’t think I can afford spending as much time as I did last year.#2021-11-2912:18tschadyi restrict myself to ~1h every morning over coffee, 2h on the weekends. Do the rest over the year if I want to learn something specific.#2021-11-2912:42MnoI'll probably do the early ones by restricting myself to only using transducers as much as possible just to get used to them 😅, and then we'll see.#2021-11-2914:48NoahTheDukei used last year to learn rust and i think that was a mistake, lol. started off pretty fun and quickly became a massive chore and strain. i got 31 stars and never got around to finishing it off#2021-11-2914:49NoahTheDukethink i’ll stick with clojure and see if it feels better this time around#2021-11-2915:04potetmI tried rust for a total of 5min last year.#2021-11-2915:04potetmHuge mistake.#2021-11-2915:24pez5 minutes - huge 😃#2021-11-2915:35NoahTheDukerust is great but trying to learn it under time pressure was not fun#2021-11-2915:36potetmMeh, I wasn’t going for best time.#2021-11-2915:37potetmIt was just super tedious for an exercise I was doing for fun.#2021-11-2915:49roeloffor me I think it s too soon to do that sort of things. My feelings says I need to have more xp in thinkimng the clojure way of thinking#2021-11-2915:56pezIf you do something like what @hobosarefriends is planning to do, @roelof, you can use it for unlocking some of that Clojure way thinking.#2021-11-2915:57roelofwho knows. but Im not sure I understand what transducers are and how to use them#2021-11-2915:58pez@danielamber2 did some early vids comparing JS solutions to Clojure ones (not AoC related, just generally). That was very interesting and insightful to me. Maybe he’ll pick up one or two of the AoC challenges this year and do some cool vids about it. 😃
#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:34Chase
defn 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:13delaguardo
user=> (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:12alekszelarkMorning!#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:58alekszelark🧵 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:52alekszelarkHere 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 , condor 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-0214:56potetm1000 lines???#2021-12-0214:56Stuartyes, thats not a typo, it was over 1000 lines of code#2021-12-0214:56potetmidk, I’ll give a benefit of doubt#2021-12-0214:57potetmthings that actually run forever are often more complicated than one might assume#2021-12-0214:57potetmerror checking/recovery can occupy a lot of space#2021-12-0215:00roelofthat is right#2021-12-0214:42potetmOh @tws’s Day 2 is real nice.#2021-12-0214:42potetmI think you win. 😄#2021-12-0214:49potetm@tws How does this work? https://github.com/tschady/advent-of-code/blob/8bc31afea74cfd522ac3c0bcf79321f059ca9352/src/aoc/2021/d01.clj#L9-L10#2021-12-0214:49potetmYou’re supposed to sum the partition. You’ve clearly seen some math trick that I don’t see.#2021-12-0214:51Stuartif you have A B C D E F and you partition it by 3 and a step of 1 you get (A B C) (B C D) (C D E) etc#2021-12-0214:51Stuartso only 1 is actually different#2021-12-0214:51Stuartso you can jsut take diff of 1st item and 3rd item#2021-12-0214:51Stuarti'm guessing thats what his offset of dropping 3 is doing ?#2021-12-0214:51tschadyThe picture in the problem showed me. The B and C lined up, don't need to add them. #2021-12-0214:51Stuartclever#2021-12-0214:52potetmclever#2021-12-0214:52potetmI like your style.#2021-12-0215:00borkdudevery clever :)#2021-12-0215:17tschadythanks2#2021-12-0215:59Ben Slessyeah, math!#2021-12-0218:07alekszelark@U07S8JGF7 thanks for sharing @tws’s solution, it’s really neat and smart.#2021-12-0218:08tschadythis is how I build my empire#2021-12-0411:33Benjaminsick#2021-12-0217:32nooga@borkdude never fails#2021-12-0217:50Chaseparse-long is getting so much usage already. You can tell who saw the 1.11.0-alpha3 update post and who didn't. Haha#2021-12-0218:06nbardiukI am waiting for usage of clojure.java.math. I've just grepped my last year solution and there are only 3 cases of Math#2021-12-0218:11roelofI did not see that post. Is there a important change then ?#2021-12-0218:13nbardiukHere is list of changes https://clojure.org/releases/devchangelog#2021-12-0218:14nbardiukAnd here is a highlights of changes https://clojure.org/news/2021/11/24/deref#2021-12-0218:16roelofaha, that is why that post. parse-long is new 🙂#2021-12-0217:52tschadyi take my AOC way too seriously to use anything alpha.#2021-12-0220:11borkdudeI added the new parse-long, parse-boolean, etc functions from clojure 1.11 in #babashka 0.6.8 in case anyone wants to play with that for AoC :)#2021-12-0221:24ordnungswidrigI just used -I and let bb to the parsing 😉#2021-12-0221:51borkdudehaha awesome!#2021-12-0221:51borkdudehttps://gist.github.com/ordnungswidrig/21224314590b871456cd4ccb2633ca8e#2021-12-0306:51Vincent CantinDo you think we could ask a parse-binary in the next Clojure release?#2021-12-0306:51Vincent Cantin.. kidding#2021-12-0310:39ordnungswidrighehe#2021-12-0310:41borkdudeFor today's solution it would have been nice if parse-long supported the radix argument#2021-12-0310:41borkdude(cc @U064X3EF3)#2021-12-0221:12R.A. PorterInteresting observation that doesn't mean anything (though there's probably some small degree of correlation with something). A quick scan down the list of current members of the Clojurians private leaderboard (code in this channel's description if you've not joined) shows that there are a fair number of supporters of AoC, all in the top third.#2021-12-0222:31tschadythanks for the reminder!#2021-12-0222:32R.A. PorterCertainly not my intent, but 👍#2021-12-0223:38euccastrothis year I'll do these about 12 hours after the puzzles get unveiled, since I'm doing them with a friend in the EST timezone and there's less of a chance that the problems will bug me into work hours 🙂#2021-12-0304:30Cora (she/her)I'm super boring about my solutions. here's days 1 and 2 https://gist.github.com/corasaurus-hex/ee69c4bdee71b55a1ebbcf588d82c527#2021-12-0317:22Benjaminsick. I learned about the args to partition from this#2021-12-0305:49mchampineDone with day3 but it’s too ugly to post before some cleanup. :)#2021-12-0306:02alekszelarkthe same#2021-12-0306:03alekszelarkand the part two has a pitfall ^_^#2021-12-0306:48peterchah did everyone copy and paste their code for part2?#2021-12-0307:28mchampine@U067R559Q what pitfall did you notice?#2021-12-0307:33alekszelark@U06B54Y95 actually it wasn’t a pitfall, I just didn’t read the description carefully.#2021-12-0307:40mchampine@U067R559Q Yeah, when the problem text is that long and involved, it’s so easy to get some little detail wrong. So to me it had several potential pitfalls there! Not to mention the usual risks of off-by-ones and edge cases. I couldn’t use max-key vs min-key in part 2 because they’re not complements like > and <= are. @U1NLKFVC4 I copy/pasted on my first pass, but couldn’t stand to look at it. 🙂#2021-12-0306:04alekszelark🧵 Day 3 answers thread: post your answers here#2021-12-0306:54Vincent CantinUgly code ...
(ns aoc2021.day3
  (:require [ :as io]
            [clojure.string :as str]
            [clojure.edn :as edn]))

(defn parse-binary [s]
  (edn/read-string (str "2r" (str/triml s))))

(def input
  (->> (io/resource "day3.txt")
       io/reader
       line-seq))

;; Part 1
(let [s (for [index (-> input first count range)
              :let [{zeroes \0
                     ones   \1} (->> input
                                     (map (fn [bin] (nth bin index)))
                                     frequencies)]]
          (if (< zeroes ones)
            [\1 \0]
            [\0 \1]))
      gamma (->> s
                 (map first)
                 str/join
                 parse-binary)
      epsilon (->> s
                   (map second)
                   str/join
                   parse-binary)]
  (* gamma epsilon))

;; Part 2
(defn most-common-bit [coll index]
  (let [{zeroes \0
         ones   \1} (->> coll
                         (map (fn [x] (nth x index)))
                         frequencies)]
    (if (<= zeroes ones) \1 \0)))

(defn least-common-bit [coll index]
  (let [{zeroes \0
         ones   \1} (->> coll
                         (map (fn [x] (nth x index)))
                         frequencies)]
    (if (<= zeroes ones) \0 \1)))

(let [[[oxygen] _] (->> [input 0]
                        (iterate (fn [[s index]]
                                   (let [bit (most-common-bit s index)]
                                     [(filter (fn [n]
                                                (= (nth n index) bit))
                                              s)
                                      (inc index)])))
                        (drop-while (comp not #{1} count first))
                        first)
      [[co2] _] (->> [input 0]
                     (iterate (fn [[s index]]
                                (let [bit (least-common-bit s index)]
                                  [(filter (fn [n]
                                             (= (nth n index) bit))
                                           s)
                                   (inc index)])))
                     (drop-while (comp not #{1} count first))
                     first)]
  (* (parse-binary oxygen)
     (parse-binary co2)))
#2021-12-0306:55peterc
(defn read-data []
  (->> (slurp "data/day3.txt")
       clojure.string/split-lines
       (map (fn [s]
              (->> (seq s)
                   (map #(- (int %) (int \0))))))))

(defn to-decimal [ns]
  (read-string (apply str "2r" ns)))

(defn part1 []
  (let [data   (read-data)
        n      (count data)
        counts (apply map + data)
        v1     (map #(if (< % ( * n 0.5)) 1 0) counts )
        v2     (map #(if (< % ( * n 0.5)) 0 1) counts )]
    (* (to-decimal v1)) (to-decimal v2)))


(defn bit-to-keep-o2 [ones zeroes]
 (cond
   (= ones zeroes) 1
   (> ones zeroes) 1
   :else           0))

(defn bit-to-keep-co2 [ones zeroes]
 (cond
   (= ones zeroes) 0
   (< ones zeroes) 1
   :else           0))

(defn part2-rating [f ratings]
  (loop [rs ratings
         n  0]
    (if (= 1 (count rs))
      (to-decimal (first rs))
      (let [counts   (->> rs
                        (map #(nth % n))
                        (reduce +))
            keep-bit (f counts (- (count rs) counts))]
        (recur (filter #(= (nth  % n) keep-bit ) rs)
               (inc n))))))

(defn part2 []
  (let [data (read-data)]
    (* (part2-rating bit-to-keep-o2 data)
       (part2-rating bit-to-keep-co2 data))))
Any improvements welcome.
#2021-12-0307:11mchampine#2021-12-0307:39alekszelarkMaybe I’ll refact it later ^_^ https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_03.clj#2021-12-0307:45mchampineBtw, I found out that to get nice code coloring, start by clicking the lightning bolt in the lower left of the composition box, then select “create a text snippet”. It supposedly has language auto-detect but I haven’t tried it. It also doesn’t color it right away - takes a minute or so after you post!#2021-12-0309:08Antonio Bibianothis is my solution
; part 1
(defn rate [key-compare input]
    (->> input
         (apply map vector)
         (map frequencies)
         (map #(key (apply key-compare val %)))
         string/join)
  )

(def gamma (rate max-key large))
(def epsilon (rate min-key large))

(* (Integer/parseInt gamma 2) (Integer/parseInt epsilon 2))

; part 2

(defn rate [comparison input]
  (loop [pos 0 
         input input]
    (if (= 1 (count input))
      (first input)
      (let [{zeros \0 ones \1} (group-by #(nth % pos) input)]
        (if (comparison (count zeros) (count ones))
          (recur (inc pos) ones)
          (recur (inc pos) zeros))))))

(def oxygen (rate <= large))

(def co2 (rate > large))

(* (Integer/parseInt oxygen 2) (Integer/parseInt co2 2))
#2021-12-0310:13genmebloghttps://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day03.clj#2021-12-0310:43jacoelhohttps://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day03.clj#2021-12-0310:50delaguardohttps://github.com/DeLaGuardo/adventofcode2021/blob/main/src/aoc/day_3.cljc#2021-12-0312:10Callum Oakleysurprised I don’t see anybody above using bit-test bit-set etc! https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/03.clj#2021-12-0312:11genmeblogI used bit-not and bit-and in part 1#2021-12-0312:34Joehttps://github.com/RedPenguin101/aoc2021/blob/main/day03.md https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day03.clj Haven't read any other solutions yet, but whenever there's one of these binary problems I always feel like I've missed a trick by not actually using any bitwise operators. Like that plane seating problem, I forget which year.#2021-12-0314:20R.A. PorterEven if I remove all the comment blocks, I'm still pretty long today. So a link instead - https://github.com/coyotesqrl/advent-of-code/blob/main/src/coyotesqrl/2021/day3.clj Like @U1EP3BZ3Q, I also used bit-and and bit-not in part 1. Both parts today, in fact, have that inverse, mirror symmetry. I used filter/`remove` to get to the O2/CO2 values.#2021-12-0315:08borkdudeI have the feeling this could be a one-or-two liner so it's probably more verbose than necessary: https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_03-clj But it runs in insignificant time with bb (60ms including startup).#2021-12-0316:03tylerwHere’s mine. I used core.matrix and didn’t end up using it much. I have the feeling there’s a function I’m missing that would’ve made things easier.#2021-12-0316:05tylerwLooking forward to reading others’ solutions later to compare, but gotta do some real work first 🙂#2021-12-0316:17VI'll paste my solution here. I feel like I made it too complicated. I'm still too reliant on loops - Feedback is very welcome#2021-12-0316:44V#2021-12-0316:55tschadyhttps://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d03.clj after a vain search for bitwise brilliance (deeper than bit-test and bit-and-not I just went with strings. I like my part1 (no temporary variables), but p2 still needs work.#2021-12-0317:35nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day03.clj#2021-12-0319:04FredrikMy unreadable solution of part 2, making each bitstring a function that pushes a counter up or down and adds itself to a set, the sign of counter then picks next set of bitstrings to inspect.
(defn pick [l test]
  (let [make-fn (fn [idx f]
                  (fn [[n m]] [(f n) (update m f (fnil conj #{}) idx)]))
        to-weird-format (fn [a]
                          (map-indexed #(mapv (partial make-fn %1) (mapv {\1 inc \0 dec} %2)) a))
        pos-or-neg (fn [xs idx]
                     (reduce #(%2 %1) [0 {}] (map #(nth % idx) xs)))
        l2 (to-weird-format l)]
    (loop [candidates l2,  bit-index 0]
      (let [[n m] (pos-or-neg candidates bit-index)
            next-indices (if (test n) (m inc) (m dec))]
        (if (< 1 (count next-indices))
          (recur (reduce #(conj %1 (nth l2 %2)) [] next-indices)
                 (inc bit-index))
          (nth l (first next-indices)))))))

(defn sol [input-string]
  (apply * (map #(Integer/parseInt % 2)
                (map #(pick (str/split-lines input-string) %) [(partial <= 0) (partial > 0)]))))
#2021-12-0319:46ianjonesa little late to the party but I finally found time to do it today! https://github.com/theianjones/aoc_2021/blob/master/src/theianjones/aoc-2021/d03/answer.clj#2021-12-0322:04gaboThis one felt like a chore for some reason https://gist.github.com/galuque/2fec8a886e1cb24f17662fda438d7e83#2021-12-0322:14karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day3.clj - here is mine. somehow managed to reuse most of the extract logic from part 1. But accessing things positionally in Clojure always feels kind of dirty to me 😄#2021-12-0322:45Andrew ByalaI loved the day 3 puzzle. Here’s a link to my blog about my solution and its many refactorings, with a link to the source at the top. I really enjoyed making composable functions, like most-common-bit, least-common-bit, one-pass-bit-check, and multi-pass-bit-check that all built up my gamma, epsilon, O2, and CO2 calculations. Very fun day! https://github.com/abyala/advent-2021-clojure/blob/main/docs/day03.md#2021-12-0401:00ChaseOh man, part 2 ate me alive. I don't know why I struggled so much but that's kind of sad this early in the game. Haven't had a chance to process and clean it up. I just can't figure out how to think in terms of reduce. https://github.com/Chase-Lambert/aoc-clojure/blob/main/src/aoc/2021/day_03.clj#2021-12-0401:01ChaseI'm looking forward to reading these answers and figuring out how to approach this in a more simple manner. Things got ugly quick! lol#2021-12-0401:29euccastromy solution: https://github.com/euccastro/advent-of-code-2021/blob/main/day3.clj I have the feeling that I left some mathematical insight on the table, but this is much cleaner than the first thing that I got to work#2021-12-0401:35euccastrooh yeah, frequencies would have helped in part one#2021-12-0401:46euccastroTIL (or was reminded of) %& in function literals#2021-12-0401:51euccastro@U067R559Q great one! part 1 esp. blew my mind. this is maybe evil, but (sort-by (juxt second first)) could be (sort-by reverse) in this case?#2021-12-0401:52StuartDay 3, part 1 (I'll post part 2 when I'm not utterly ashamed of it 😆)
(defn get-key-with-highest-val [m]
  (if (>= (m \1 0) (m \0 0))
    \1
    \0))

(defn flip-bits [s]
  (map (fn [i] ({\1 \0 \0 \1} i)) s))

(defn binary-str->int [s]
  (Integer/parseInt s 2))

(defn char-seq->str [cs]
  (->> (map str cs)
       (str/join "")))

;; part 1
(let [input (->> (f/read-all-lines-and-parse "puzzle-inputs/2021/day3" parser)
                 (apply map vector)
                 (map frequencies))
      γ-bin (->> input
                 (map get-key-with-highest-val))
      ε     (->> γ-bin
                 (flip-bits)
                 (char-seq->str)
                 (binary-str->int))
      γ     (->> γ-bin
                 (char-seq->str)
                 (binary-str->int))]
  (* ε γ))
#2021-12-0401:58StuartOK, I'm still ashamed of it but :man-gesturing-no: it's 2am here...
(defn has-v-at-idx [idx v xs]
  (= v (nth xs idx)))

(defn parser [l]
  (map identity l))


(defn reduce-binary-over-f [input f]
  (loop [input input, idx 0]
    (if (= 1 (count input))
      (-> (first input)
          char-seq->str
          binary-str->int)
      (let [bits-at-idx (nth (apply map vector input) idx)
            most-common (->> (frequencies bits-at-idx)
                             (get-key-with-highest-val)
                             (f))]
        (recur (filter (partial has-v-at-idx idx most-common) input)
               (inc idx))))))

(let [input (f/read-all-lines-and-parse "puzzle-inputs/2021/day3" parser)
      oxygen-generator (reduce-binary-over-f input identity)
      oxygen-scrubber (reduce-binary-over-f input #({\1 \0 \0 \1} %))]
  (* oxygen-generator oxygen-scrubber))
#2021-12-0402:05euccastroyou don't need to wrap the map in a function literal; it's already a function as is#2021-12-0402:05StuartWhat do you mean ?#2021-12-0402:06euccastro#({\1 \0 \0 \1} %) could be just {\1 \0 \0 \1}#2021-12-0402:06euccastrothat part 2 solution looks fine to me, nothing to be ashamed of#2021-12-0402:06Stuartah okay! I see, thank you!#2021-12-0402:07euccastrokudos on the greek chars for part 1! 😄#2021-12-0403:40potetmhttps://github.com/potetm/advent-of-code/blob/master/src/advent_2021/day_3.clj#2021-12-0403:41potetmBasically the same as 3-4 others I saw.#2021-12-0403:41potetmI’m kinda convinced there’s no pretty way to do Part 2.#2021-12-0404:07Sam Adamsa late, long-winded submission: https://samadams.dev/2021/12/03/advent-of-code-day-3.html#2021-12-0404:09Sam AdamsMaybe tomorrow I’ll benchmark a frequencies -based solution too#2021-12-0404:42Sam Adams@U067R559Q I might be misreading but I think your gamma and epsilon ratings are flip-flopped 🙂#2021-12-0404:53alekszelark@U016C0EGHUN you’re right, I was polishing the code and mixed them up. But yesterday evening I refactored the code and there is no even names, just one single thread :star-struck: https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_03.clj#2021-12-0404:56alekszelark@U65FN6WL9 revers won’t help here
; Execution error (IllegalArgumentException) at zelark.aoc-2021.day-03/eval9970 (REPL:47).
; Don't know how to create ISeq from: clojure.core$reverse
#2021-12-0411:00euccastro@U067R559Q it seems you have the arguments swapped in your experiment? anyway, you're right it doesn't work, but for a reason that is surprising to me: clojure doesn't know how to compare lists (while it can compare vectors):
(sort '[(3 4) (1 2)])

clojure.lang.PersistentList cannot be cast to java.lang.Comparable

(sort-by (comp vec reverse) {:a 3 :b 1})
;; => ([:b 1] [:a 3])
#2021-12-0411:01euccastroof course once you have to (comp vec reverse) it stops being that much prettier#2021-12-0412:32alekszelarkYes, the actual exception is “clojure.lang.PersistentList cannot be cast to java.lang.Comparable”#2021-12-0412:59Joe> I loved the day 3 puzzle.  Here’s a link to my blog about my solution > and its many refactorings, with a link to the source at the top.  I > really enjoyed making composable functions, like most-common-bit, least-common-bit, one-pass-bit-check, and multi-pass-bit-check that all built up my gamma, epsilon, O2, and CO2 calculations.  Very fun day! @U01HHBJ56J1 this was a great read and a nice solution, thanks!#2021-12-0413:24Felipea bit late to the party, but here's mine! https://github.com/FelipeCortez/advent-of-code/blob/master/2021/03.clj#2021-12-0413:26Felipeoh, I can do str/join instead of apply str. nice!#2021-12-0415:41euccastrolooking into the details of clojure list/vector comparison I realized that I could shorten the following thread-last sequence in my solution:
(group-by #(nth % idx))
                (sort-by key)
                (map second)
                (sort-by count)
(where I felt clever for relying on the stability of sort-by so the order in the first sort would be a tie-breaker in the second one) to just
(group-by #(nth % idx))
                vals
                sort
because vectors will first be compared by length and then lexicographically on ties, which is exactly what I want
#2021-12-0512:12Benjaminproud of part 2 https://github.com/benjamin-asdf/advent-of-code-2021/blob/master/src/day3.clj - now I can read your solutions and go aha 7 times 😛#2021-12-0603:39Cora (she/her)https://gist.github.com/corasaurus-hex/ee69c4bdee71b55a1ebbcf588d82c527#file-3-1-clj#2021-12-0603:45Cora (she/her)again a very boring solution by me#2021-12-0820:59timoWhy do you @U04V15CAJ do this in your Day 3 solution?
(if more-ones? 
  (conj bits 1) (conj bits 0))
I don't understand why you are shifting the bits to the left with another 0 or 1 on it...
#2021-12-0821:01borkdudeeh, lemme check#2021-12-0821:03borkdudehonest answer: I don't remember, day 3 is already too long ago ;)#2021-12-0821:04timoalright, never mind. thanks anyway#2021-12-0822:17Fredrikthis is not bit shifting per se, it is gradually building up the answer. for every position, determine if that column has more ones or zeros, and append accordingly either 1 or 0 to the answer#2021-12-0822:21borkdudeindeed#2021-12-0311:38StuartI'm in that horrible situation where my code runs on the test data for day 3, and produces correct answer, and runs on the full data without crashing, but the answer is wrong... gah#2021-12-0311:51alekszelarkMaybe you’ve missed this “If `0` and `1` are equally common, keep values with a `1` in the position being considered.” and this “If `0` and `1` are equally common, keep values with a `0` in the position being considered.”#2021-12-0311:59Stuarthmmm. That will be it, I assumed since the page doesnt explain what to do in the event of a tie that its set to never occur, thanks!#2021-12-0312:02genmeblogIt explains (for part 2): "If `0` and `1` are equally common, keep values with a `1` in the position being considered."#2021-12-0312:03Stuartah, im on part 1!#2021-12-0312:07genmeblogah! do you have a tie in your dataset? (I don't have, it may happen in part 2)#2021-12-0312:07StuartI don't, as even putting that condition I'm getting back same answer#2021-12-0312:11Stuartepsilon is always just gamma with the bits flipped right?#2021-12-0312:13Stuartomg, i was debugging and had a rogue (take 3) in! argh! That I forgot to take out once I was using the real data. IT works and I have part 1 completed.#2021-12-0313:14noogawall of text today 😄#2021-12-0313:45Ben SlessI didn't do part 2 only due to too long didn't read#2021-12-0314:18NoahTheDukememe from reddit:#2021-12-0314:18NoahTheDuke#2021-12-0314:21StuartAt least you wouldn't have the leaderboard filled in 2 minutes!#2021-12-0316:36tschadyTIL about: https://github.com/clojure/data.int-map seems very useful for AOC#2021-12-0316:42Ben Slessif your ints are sequential, you can just use a vector#2021-12-0316:48Jeff Evansdoes anyone else find themselves more interested in refactoring part1 so that it can be solved using part2 code, rather than going for sheer speed?#2021-12-0317:00Mario C.Yes, I am actually focusing on this, this year. I try to write part 1 in such a way that it can be re-used or easily refactored for part2. The less effort required for part 2 means I did a decent job with part 1. Major refactor means I may have made it to specific.#2021-12-0317:40thomYeah. I find no joy in just doing the quickest thing, it's far more fun to have unit tests and nice abstractions. Also fun to properly benchmark multiple approaches etc.#2021-12-0317:41ACThis is my first year tracking my progress on a private leaderboard, so I hacked up a pretty gross solution to part 1. After I read part 2, it didn't feel right to do the same. I did refactor part 1 and then came back and finished part 2 this morning. I'm pretty sure I'll end up refactoring it a couple more times.#2021-12-0317:51BenjaminRich always solves part 2 while hammoking on part 1#2021-12-0317:55Jeff Evansawesome. sounds like I am in good company, then 😁#2021-12-0318:02thomI mean, I can't be the only person with GitHub Actions running my tests and generating Marginalia docs, right? Right?#2021-12-0318:42fingertoeAll in all, I think speed is rather useless.. Instead, I want to do it badly first, so I can build buckets to put the “how to do it right” knowledge into..#2021-12-0319:10Antonio BibianoI like to get to a solution as fast as i can and then spend the rest of the day thinking about better ways, that allows me to learn a lot from other people solution throughout the day with no guilt :D#2021-12-0322:12karol+1 to get solution as quickly as you can and then if you find it interesting enough optimise it 😄#2021-12-0318:00nbardiukStats show a dip today on part2, almost half of people decided to skip it https://adventofcode.com/2021/stats#2021-12-0318:06kpavI can only assume it was the big wall of text. I know I couldnt process that while I was half asleep last night.#2021-12-0318:11nbardiukYeah, I waisted time debugging code while the problem was in my reading skils#2021-12-0318:27StuartI managed to get part 1 done during a meeting today at work, just haven't had time yet today to even look at part 2#2021-12-0318:27StuartAnd I'm going out tonight, so will have to do part 2 tomorrow before I do day 4#2021-12-0318:30nbardiukThat a good point, tomorrow is a weekend, people will have plenty of time to catch up#2021-12-0320:39sebastianfor me at least, part 2 was a considerable step up in difficulty from part 1#2021-12-0401:47Stuartjust finished day3, it's 1:46 am here and I'm pretty drunk. Very not proud of my code#2021-12-0404:57alekszelark🧵 Day 4 answers thread: post your answers here#2021-12-0406:40alekszelarkcould be optimized of course https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_04.clj#2021-12-0407:46nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day04.clj#2021-12-0407:51alekszelark@U076FM90B yeah, lazy-seq is a good candidate for today’s puzzle#2021-12-0407:58nbardiukI've solved the problem with reduce, the lazy-seq was an optimization after refactoring. I like the idea of lazy-seq but not familiar enough to just use it on the spot#2021-12-0408:32R.A. PorterSolved...but I can't bring myself to post in the current state. Maybe I'll clean up tomorrow.#2021-12-0410:10jacoelhoSolved representing each card as a map, looking at other solutions here, seems overcomplicated https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day04.clj#2021-12-0411:25tschadyfirst pass, eager version. lazy coming next.#2021-12-0411:52Callum OakleyDoesn’t “mark” the boards in any way, just compares against the set of called numbers. Plays every board to completion, min-key for part-1 and max-key for part-2. ~50ms https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/04.clj#2021-12-0411:56Mikko Koskihttps://github.com/rap1ds/advent-of-code-2021/blob/main/src/day4.clj#2021-12-0412:05tschadyhttps://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d04.clj i couldn’t unsee @U076FM90B’s. group-by bingo? is 🔥 here’s my lazy eval version. i like the helpers, but any advice on fixing that last cons line?#2021-12-0412:10karolhttps://github.com/kfirmanty/advent-of-code-2021/blob/main/src/day4.clj - so here is my first very naive pass using loop but still it executes in less than 100ms so can't complain. will try loopless approach later#2021-12-0412:40borkdudeMy day 4: https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_04-clj#2021-12-0412:46JoeLoved this one! Pretty happy I was able to get my https://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day04.clj to less than 50 lines. I went down a bit of a wrong path after part 1 due to https://github.com/RedPenguin101/aoc2021/blob/main/day04.md, and I had to write some reduce functions, but happily part 2 forced to me reevaluate what the issue was and get back to a cleaner declarative solution.#2021-12-0412:50borkdudeSurprisingly my solution is faster in babashka than clojure:
$ bb aoc21_04.clj
32844
"Elapsed time: 122.147231 msecs"
4920
"Elapsed time: 451.069084 msecs"
$ clojure -M aoc21_04.clj
32844
"Elapsed time: 180.087077 msecs"
4920
"Elapsed time: 521.740564 msecs"
#2021-12-0414:54Felipeis it cheating if you use throw to escape out of a nested loop? part 1: https://github.com/FelipeCortez/advent-of-code/blob/master/2021/04.clj#2021-12-0414:58borkdude@UA2U3KW0L I would say everything is allowed in AOC, even the most insane hacks. Impressive!#2021-12-0415:18drowsyWell, it's not exactly concise nor fast, but I learned a lot about datascript while using it to solve day4: https://github.com/IamDrowsy/aoc-2021/blob/main/src/aoc2021/d04.clj#2021-12-0415:30R.A. PorterI'm still not content, but it's not as terrible as it could be? I have three functions that should be collapsible to one, but I was too tired to see it. Not sure why this one was such a bear for me. Trying a link to a statically-generated Clerk page https://coyotesqrl.github.io/advent-of-code/2021/#/src%2Fcoyotesqrl%2F2021%2Fday4.clj#2021-12-0415:55potetmAight: https://github.com/potetm/advent-of-code/blob/master/src/advent_2021/day_4.clj#2021-12-0416:01potetmIMO the easiest way to get laziness out of this one is to iterate#2021-12-0416:11potetmI think I have an aversion to repeatedly mapping over the same data, no matter the cost 😄 Like in this one, I tracked board state by index instead of mapping over boards with a set of called numbers.#2021-12-0416:13potetmtbh I don’t even know if its actually faster.#2021-12-0417:12genmeblogMy idea is to pack rows/cols into sets, disjoin every input and looking for empty set in each board. Haven't checked other solution yet. https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2021/day04.clj#2021-12-0417:37Antonio Bibianomy solution is similar to yours I think#2021-12-0417:37Antonio Bibiano#2021-12-0417:39Antonio BibianoI called the "boards" "cards" because in my native language we call them like that 😄#2021-12-0417:40genmeblogIt is indeed! I avoided filtering twice by using group-by and used disj instead of difference.#2021-12-0417:47Antonio Bibianoah nice, i love group-by#2021-12-0417:49Antonio Bibianojust figured since my predicate didn't return true/false the output would be a bit awkward touse#2021-12-0417:49Antonio Bibianobut yeah it irked me a bit to "filter" twice 😄#2021-12-0418:00StuartPart 1 https://gist.github.com/stuartstein777/e16e3b8b4150f0ad9e9646183438c189 I store each board as a flat collection, e.g. https://gist.github.com/stuartstein777/e0af631b8b151fa2e401fa24189e4264 Is their a nicer way to do my mark-number-called without the nested maps?#2021-12-0418:28Antonio BibianoI also had a bunch of nested mapping, the only thing I could come up with is to create an helper function that did the inner map :(#2021-12-0418:29euccastrotoday I was in the "many little helpers" mood: https://github.com/euccastro/advent-of-code-2021/blob/main/day4.clj#2021-12-0418:49euccastro@U013YN3T4DA see @U1Z392WMQ's solutions for a nice use of specter to avoid the nested maps#2021-12-0419:00StuartFor part 2, are people finding a situation where a number is eliminating multiple boards?#2021-12-0419:12Antonio Bibianoyes for me it happens, i have multuple winners in a single draw#2021-12-0419:55StuartPart 2 https://gist.github.com/stuartstein777/74765018745c8a500dbf4b2ad9405451 I removed the boards as they become winners. I had an issue where on each number I was only looking for A winning board, so that lost a lot of time. It was fine once I realised what was happening. I found it by printing the boards at each number and by the end all of my boards were totally filled in:laughing:#2021-12-0419:59Antonio Bibianoactually I did something similar, because I thought that in bingo when you win you can keep the board and do bingo again :man-facepalming:#2021-12-0419:59StuartI think you can, I think you can call bingo up to 3 times. Atleast from my memory of bingo, you can get 1 horizontal line, 2 horizontal lines or 3 horizontal lines.#2021-12-0420:00StuartProbably changes per country though#2021-12-0420:06potetmOkay, it looks much better when you don’t track each board’s state individually and just track the called numbers: https://github.com/potetm/advent-of-code/blob/master/src/advent_2021/day_4.clj#2021-12-0420:06Antonio Bibianoi guess that's how it's played in the north pole#2021-12-0422:36sebastianthis one I'm really happy with (being a beginner in Clojure)#2021-12-0422:48Vincent CantinMy solution, similar to @U4LN72X44 's https://github.com/green-coder/advent-of-code/blob/master/src/aoc_2021/day_4.clj#2021-12-0500:01Sam AdamsMy spec-sploration solution: https://samadams.dev/2021/12/04/advent-of-code-day-4.html#2021-12-0500:02Sam AdamsI need to code faster so I have time to read all these enlightening solutions 🙂#2021-12-0506:36mchampineNot happy with this one, lots of missed optimizations..#2021-12-0510:39babardoCathing up 😅 https://github.com/v-garcia/aoc_2021/blob/main/day_four.clj#2021-12-0514:15Vincent CantinI think that there was a way to solve this Bingo problem in linear time, O(n+m) where n is the count of numbers and m is the number of grids.#2021-12-0514:16Vincent CantinDid anyone find it?#2021-12-0514:29Vincent CantinThe implementation is also very small.#2021-12-0514:31Vincent Cantin
;; Fast solution
(def number->index
  (into {} (map-indexed (fn [i n] [n i])) numbers))

;; grid is a vector of sets representing the numbers in the rows and the cols.
(defn winning-index [grid]
  (->> grid
       (mapv (fn [line]
               (transduce (map number->index) max line)))
       (apply min)))
#2021-12-0514:32StuartI dont understand, is that the entire solution for part 1 ?#2021-12-0514:32Vincent CantinThat's the main part which describe the algorithm, not the whole solution.#2021-12-0514:33Stuartoh, is that working out if a grid is won or not?#2021-12-0514:33Vincent CantinOnce you calculate the winning index of each grid (which is fast), you can take the first one which wins or the last one, for part 1 and part 2.#2021-12-0514:34Stuartohhh, i see! Oh that's clever!#2021-12-0515:13Vincent CantinI wrote the full implementation at https://github.com/green-coder/advent-of-code/blob/master/src/aoc_2021/day_4_fast.clj#2021-12-0516:36Antonio Bibianois this similar in principle to @U01HL2S0X71 solution?#2021-12-0517:23Vincent CantinIt's different, his solution has to test a grid multiple times. In my version, each grid is visited only once. My algorithm should be faster.#2021-12-0517:39Antonio BibianoAh now I get it! #2021-12-0518:23Callum Oakleyoooh very nice#2021-12-0519:38tschadyperhaps a bit of a bug, in that if the set of called numbers don’t complete a card ever, yours will still call it completed.#2021-12-0605:09Cora (she/her)https://gist.github.com/corasaurus-hex/ee69c4bdee71b55a1ebbcf588d82c527#file-4-1-clj#2021-12-0913:36Sidestep@U02N27RK69K probably clearest implementation. I bet it performs well too because it's well designed.#2021-12-0913:39Sidestephttps://gitlab.com/sidestep/advent-of-code-2021/-/blob/master/day4/src/scratch.clj#2021-12-0405:58alekszelarkHello Saturday!#2021-12-0410:29borkdudeMy day 2 works on the sample input, but not on the real data :(#2021-12-0410:46borkdudeNow it does#2021-12-0411:01roelof@borkdude congrats#2021-12-0418:45Benjaminday 3 tip request#2021-12-0418:47Benjaminwhat is a data structure let's me easily express vertical and horizontal series? I'm guessing just a vector of vectors? Do you have a tip for flipping it on it's side#2021-12-0418:48genmeblog(apply map vector rows)#2021-12-0418:48genmeblogI keep data column-wise#2021-12-0418:49Benjamin👀#2021-12-0418:50genmeblog(for the first part)#2021-12-0418:51Benjaminman I need to start using multi arity map (refering to apply map vector#2021-12-0418:52genmeblogYeah, it's really helpful.#2021-12-0419:25Antonio BibianoYeah I think that trick is gonna be used in every challenge #2021-12-0419:28Antonio BibianoI was wondering about it’s performance though, let’s say you have a lot of rows, there was a discussion about apply having bad performance on large lists of argumens. Is there an alternative?#2021-12-0419:43borkdudeif you know the size of the matrix, you could optimize it using that knowledge and not use apply#2021-12-0419:43borkdudebut it yields more verbose code#2021-12-0419:43borkdudeand I don't think it really matters for this AOC puzzle#2021-12-0419:44potetm@U01HY37QQUA I’ve never seen it be a particular problem.#2021-12-0419:45potetmspeedwise#2021-12-0419:45borkdudein SCI apply was a problem, getting rid of that vastly improved the speed of function calls (those were always done with apply in the beginning) but this is a very non-typical use case#2021-12-0419:45Antonio Bibianonice, because I was going through the posted solution and discovered core.matrix but I guess just for transposing or getting the columns it might be overkill#2021-12-0419:51potetm@U01HY37QQUA I almost always end up using core.matrix during AoC#2021-12-0419:51potetmat some point#2021-12-0419:51potetmI did today just to do matrix/index-seq#2021-12-0419:51potetmSo might be worth checking it out.#2021-12-0419:53Antonio Bibianoyeah i'll definitely keep it in mind!#2021-12-0421:30borkdudeapparently day 4 is a good day for #babashka performance ;) https://twitter.com/mknoszlig/status/1467240830301843458#2021-12-0421:55nbardiukMade a quick animation of the bingo game in quil#2021-12-0421:58borkdudenice!#2021-12-0422:03Vincent CantinI just realized that we were all playing the "Squid's Game" today.#2021-12-0422:06Vincent CantinIt makes sense, as Bingo was a game we were mostly playing a long time ago, during childhood.#2021-12-0504:59alekszelark🧵Day 5 answers thread: post your answers here#2021-12-0505:52normanhttps://gitlab.com/maximoburrito/advent2021/-/blob/main/src/day5/main.clj#2021-12-0506:01alekszelarkhttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_05.clj#2021-12-0506:47fingertoehttps://github.com/jreighley/aoc2021/blob/master/src/day5.clj#2021-12-0507:18R.A. PorterI'm sure if I remembered my linear algebra at all, I'd have a cleverer way of getting the points on a line (the degenerate cases were easy with for comprehension). But this'll do. https://coyotesqrl.github.io/advent-of-code/2021/#/src%2Fcoyotesqrl%2F2021%2Fday5.clj#2021-12-0507:21nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2021/src/day05.clj#2021-12-0507:26nbardiukI am also curious if there is a geometrical property that can help to avoid generating points#2021-12-0507:34AC@U01GXCWSRMW I wrote an almost identical version of your move-fn (picking dec, inc, or identity as a 'step' function)
(defn step-fn [a b]
  (cond (> a b) dec
        (< a b) inc
        :else identity))
#2021-12-0507:34Andrew ByalaOnce again, it's not concise, but I had fun with letfn and some-fn, so this was a terrific learning experience. Looking forward to reading your solutions... tomorrow... https://github.com/abyala/advent-2021-clojure/blob/main/docs/day05.md#2021-12-0507:38R.A. Porter@U0124C56J5R I had initially been using range for the degenerate cases, but gave up on it when I went to diagonal. I just constantly forget I can call map over multiple collections.#2021-12-0508:00petercInspired by @U076FM90B solution.#2021-12-0508:03alekszelark@U1NLKFVC4 in my solution it is the same ^_^#2021-12-0508:04petercYeah I just realized that looking at your solution!#2021-12-0508:22nbardiukI was very surprised how close I was to the alekszelark's#2021-12-0509:34Vincent CantinMy solution (no clean up, I prefer to show it raw) https://github.com/green-coder/advent-of-code/blob/master/src/aoc_2021/day_5.clj#2021-12-0509:37Vincent CantinMy goal was to introduce Clojure to the viewers, so I didn't try to do anything complicated (i.e. simplify the program, in fact 😄 )#2021-12-0509:42Vincent CantinNice use of frequencies again#2021-12-0510:12Joehttps://github.com/RedPenguin101/aoc2021/blob/main/clojure/src/aoc2021/day05.clj and (rather boring) https://github.com/RedPenguin101/aoc2021/blob/main/day05.md Is there a function that does a sort of take-until ? i.e. take-while but on matching the predicate it will terminate the sequence? Easy enough to write with a reduce but feels like something that might be in the standard library, or there's a way to use the standard library to do that.#2021-12-0510:35JoeOooh, that step in range would've saved me some hassle, totally forgot about that.#2021-12-0511:16Callum Oakleymost interesting part for me was figuring out how to draw the line segment in a way which works for horizontal, vertical, and diagonal, and only hits the integer points without having to do any filtering. the metric you want is the https://en.wikipedia.org/wiki/Chebyshev_distance! https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2021/05.clj#2021-12-0511:19Callum Oakleyah I see @U8MJBRSR5 did the same thing :)#2021-12-0512:06Mikko KoskiEnded up implementing specialized version of range which can be used to expand horizontal, vertical and diagonal lines:
(defn range* [start end]
  (cond
    (< start end)
    (range start (inc end))

    (= start end)
    (repeat start)

    :else
    (reverse (range end (inc start)))))

(defn expand [[[x1 y1] [x2 y2]]]
  (map (fn [x y] [x y]) (range* x1 x2) (range* y1 y2)))
https://github.com/rap1ds/advent-of-code-2021/blob/main/src/day5.clj
#2021-12-0512:16borkdudeMy day 5: https://gist.github.com/borkdude/b5cf0e9d2d8ab7c678d88e27a3357b33#file-aoc21_05-clj#2021-12-0513:43johnnyDay 5: https://github.com/jhny/adventofcode2021/blob/main/src/day5.clj#2021-12-0513:50Phil Shapiroday 5: https://github.com/philshap/advent2021/blob/main/src/day5.clj#2021-12-0513:51tschadyexpecting more line stuff, so I’m considering abstracting this into Line protocol. went with slopes/intercepts. https://github.com/tschady/advent-of-code/blob/main/src/aoc/2021/d05.clj#2021-12-0513:58Antonio Bibianothis is my solution for today#2021-12-0513:59Antonio Bibiano#2021-12-0514:04Antonio BibianoI was unsure about the cond in my range* .. but then the i would have had to do some kind of conditional for straight lines so might as well put it there#2021-12-0514:04Antonio Bibianoif the input was a single point I would be screwed 😄#2021-12-0514:05sebastianNot the prettiest. But it works.#2021-12-0514:06babardoNot so dirty today ^^ https://github.com/v-garcia/aoc_2021/blob/main/day_five.clj#2021-12-0514:08tschadyfor those doing range* type stuff, might simplify to:
(defn range* [x1 x2]
  (let [dx (compare x2 x1)]
    (range x1 (+ dx x2) dx)))
#2021-12-0514:10Antonio Bibianoaaaah nice, was looking for that!#2021-12-0514:10nbardiukI've considered it for a moment but didn't try, was waried about edge case when dx is 0#2021-12-0514:11Antonio Bibiano#2021-12-0514:26Stuarthttps://gist.github.com/stuartstein777/73f42275324d7c06b6d3510fd70e4229 ALso couldn't think of a nice general way to get points on a diagonal line given (x1,y1), (x2, y2)#2021-12-0514:48Stuartstrange that the stats show less completions today than day 4, thought today was a LOT easier than yesterday#2021-12-0514:55tschadyhangover effect#2021-12-0514:58Antonio Bibiano@U0105JJK1L3 take until could be implemented like take-while (complement pred) coll?#2021-12-0515:03tschadyhttps://weavejester.github.io/medley/medley.core.html#var-take-upto is close#2021-12-0515:50potetmhttps://github.com/potetm/advent-of-code/blob/master/src/advent_2021/day_5.clj#2021-12-0515:51potetmI agree with @U1Z392WMQ that I will probably end up pulling line-pnts to a common namespace.#2021-12-0515:51potetmtoo useful for AoC#2021-12-0515:52potetmThe alternative to (compare x1 x2) is to (sort pnts). If your points are vectors, they will sort exactly like you would want.#2021-12-0515:52potetmBut yeah, no way around checking for undefined slopes.#2021-12-0516:04jacoelhoGenerating the points and using a map to track count https://github.com/jacoelho/advent-of-code-clj/blob/main/src/aoc/2021/day05.clj#2021-12-0516:10mchampineMuch easier than day 4 IMO#2021-12-0516:19max minoShttps://github.com/maxminoS/advent-of-code/blob/main/2021/src/aoc2021/puzzle09.clj took 9 whole minutes to solve this#2021-12-0516:19StuartNumber 1 on the leaderboard today solved both parts in 3:02!😮
#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:24alekszelark@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:25alekszelarkAlso, 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:19alekszelark@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:30alekszelark🧵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:33alekszelarkAlmost 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:43alekszelark@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:58alekszelarkJust 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:54alekszelark🧵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:59alekszelarkJust 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.cljhttps://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:32alekszelark@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:50borkdude
user=> (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:47alekszelarkhttps://twitter.com/algrison/status/1468129198128648193#2021-12-0709:54alekszelarkHaha, 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:56alekszelark🧵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:14alekszelarka 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:31alekszelark@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:13alekszelarkRewrote 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.mdhttps://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.cljhttps://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:19alekszelarkhttps://twitter.com/algrison/status/1468541254455771139#2021-12-0904:44alekszelark🧵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:07alekszelarkhttps://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:09alekszelark> 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:27Stuart
acedgfb 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:29Stuart
8                       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:42alekszelark@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:06alekszelark@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:19alekszelarkOnce, 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:59alekszelark🧵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:05alekszelarkhttps://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:58alekszelark🧵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:59alekszelarkhttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_11.clj#2021-12-1107:01alekszelarkNeed to think if I can apply frequencies here 😆#2021-12-1108:43alekszelarkHere 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.cljhttps://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.mdhttps://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:16alekszelarkhttps://twitter.com/algrison/status/1469555494461313026#2021-12-1119:23Andrew ByalaVery cool, @U067R559Q! What did you use for visualization?#2021-12-1204:56alekszelark@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:57alekszelark🧵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:51alekszelarkI 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:49alekszelark🧵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:26alekszelarkhttps://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:55alekszelark@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.cljhttps://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:49alekszelarkfold along day=13:christmas_tree:#2021-12-1316:37alekszelark#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:55alekszelark🧵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:59alekszelarkhttps://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.cljhttps://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:19alekszelark@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:52alekszelark🧵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:43alekszelark> 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:47alekszelarkOh, thank you, I see#2021-12-1508:05alekszelarkhttps://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_15.clj#2021-12-1509:36alekszelarkThe same result could be gotten with #(inc (mod % 9))#2021-12-1509:37alekszelarkI 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 Vindavs
user=> (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.cljhttps://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.cljhttps://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:59alekszelark🧵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:44alekszelark@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:54alekszelarkDidn’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:55alekszelarksecond 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.cljhttps://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:56alekszelark🧵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:37alekszelarkIt 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.cljhttps://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:55alekszelark🧵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:37alekszelarktook 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.cljhttps://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 requires 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.cljhttps://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:55alekszelarkIt’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:48alekszelark🧵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:21alekszelarkfinally 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:52alekszelarkA 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:53alekszelark@U89SBUQ4T I ended up with 24 orientations#2021-12-1920:55alekszelarkan 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:56alekszelarkI 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&amp;utm_medium=web2x&amp;context=3https://www.reddit.com/r/adventofcode/comments/rjpf7f/comment/hp551kv/?utm_source=share&amp;utm_medium=web2x&amp;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.cljhttps://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&amp;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:46alekszelark🧵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:15alekszelarkWorks for both demo and real inputs https://github.com/zelark/AoC-2021/blob/main/src/zelark/aoc_2021/day_20.clj#2021-12-2007:20alekszelark@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:32alekszelarkYeah, 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:31alekszelark@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.cljhttps://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:55alekszelark🧵 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:34alekszelark@U076FM90B Like your approach for switching between two players. I always forget about it#2021-12-2112:49alekszelarkrefactored 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:33alekszelarkLol#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:48alekszelark@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:50alekszelarkand 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:51alekszelarkyeah, 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:01alekszelark@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.cljhttps://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:48alekszelark🧵 Day 22 Solutions Thread: post your solution here#2021-12-2207:44alekszelarkhttps://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:02alekszelarkRefactored 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:00alekszelarkit’s pretty fast#2021-12-2216:01alekszelark~156msecs#2021-12-2216:06alekszelark@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:28alekszelarkhttps://twitter.com/algrison/status/1473344262762905612?s=20 made by @a.grison, not me#2021-12-2304:55alekszelark🧵 Day 23 Solutions Thread: post your solution here#2021-12-2309:05alekszelarkSolved 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:00alekszelark@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:23alekszelarkHope 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:16alekszelarkAn 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.mdhttps://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:53alekszelark@U01HY37QQUA It might be you have too many possible movements.#2021-12-2411:57alekszelarkstill 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:33alekszelarkI 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:45alekszelark🧵 Day 24 Solutions Thread: post your solution here#2021-12-2410:47alekszelarkhttps://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:06alekszelark@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:54alekszelark🧵 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:54alekszelarkhttps://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.mdhttps://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:30alekszelarkIt’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:16alekszelark@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:06alekszelarkafter 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:53alekszelarkAlso highly recommend this series from Lambda Island https://www.youtube.com/watch?v=9ITiZ88sljA&amp;list=PLhYmIiHOMWoGIMCmCRwMSrWkHJg12vevR&amp;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:57alekszelark
"\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:17borkdude
user=> (: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:08alekszelark
(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:01alekszelarkhttps://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:23Caseyhttps://gist.github.com/mcpower/87427528b9ba5cac6f0c679370789661https://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:08borkdude
ldd /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&amp;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:24alekszelarkhttps://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&amp;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&amp;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.mdhttps://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:02alekszelarkeduction 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.mdhttps://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:30alekszelarkhere we go https://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_09.clj#2022-12-0916:56alekszelark@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&amp;cid=C0GLTDB2T oh that could clean up my next-pos nicely, thanks Apple#2022-12-1007:13alekszelark@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:53alekszelarkhttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_10.clj#2022-12-1007:05alekszelark
6) 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:32alekszelark@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:00alekszelark(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:24alekszelarklovely 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:41alekszelarkI 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.mdhttps://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:55alekszelarkhttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_11.clj#2022-12-1110:56alekszelark@U01HHBJ56J1 my code is pretty the same as yours this time 🙂#2022-12-1110:57alekszelarkhate 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:04alekszelarkpracticed 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:02alekszelarktotally 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:28alekszelark@UTFAPNRPT like your comments (thoughts) in the code#2022-12-1208:32alekszelarkold 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:21alekszelarkOk, 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:23alekszelark@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:25alekszelarkOhh, I missed that 🙃#2022-12-1212:59alekszelarkFound 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:57alekszelark@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.mdhttps://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:17bhauman
Also 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:43alekszelarkbreadth-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:51alekszelarka 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.mdhttps://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:34alekszelarkImpressed by @UTFAPNRPT’s code of comparator. It’s really concise.#2022-12-1316:35alekszelarkMine 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:23alekszelarknil is endless void ^_^#2022-12-1307:27alekszelarkDay 13 part 1: I get the right answer for the sample, but it’s wrong for my input. Any tips?#2022-12-1307:31alekszelarkdouble checked everything, but can’t see a mistake#2022-12-1307:35alekszelarkcompared 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:41alekszelarkI 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:43alekszelarkshould be fine, I found a problem with a logic for comparison#2022-12-1309:43alekszelarkI’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:53alekszelark(cmp [[[] 6 2]] [[[]] [10]]) a good example to check against, should return false#2022-12-1312:59alekszelarkMy 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:02alekszelark@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:07alekszelark@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:44Apple
culi 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:56alekszelarkA 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:11alekszelark@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:16alekszelarkInteresting, 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:27alekszelarkI 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:31alekszelarkYes, it is#2022-12-1717:32alekszelarkFor 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:54alekszelarktoday’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:08alekszelarkProbably 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:12alekszelarknice catch
(->> (parse large-example)
     (mapcat surfaces)
     (frequencies)
     (filter #(== (second %) 1))
     (count))
#2022-12-1813:28alekszelark“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 Vindavs
0 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:51alekszelarkThe 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:57alekszelarkI 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:01alekszelarkI 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:53bhauman
That'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:01alekszelarkUsed 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:24alekszelark@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:27alekszelark@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:57alekszelarkBtw, 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:57alekszelarkhttps://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:33alekszelark@U01HL2S0X71 brilliant, just came to the same#2022-12-2112:57alekszelarkUpdated 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.
#2022-12-2202:34Felipe@U1Z392WMQ I thought I was being original with the promises and futures 😞#2022-12-2202:34Felipemanaged to solve part 2 through... visual inspection!#2022-12-2202:36Felipe#2022-12-2203:10bhaumanShowing my symbolic manipulation output:
(- (/ (+ 4 (* 2 (- humn 3))) 4) 150)
(normalize)
[+ -150 [* 1/4 (+ 4 (* 2 [+ -3 humn]))]]
(simplifier)
[+ -301/2 [* 1/2 humn]]
This is where ‘= is replaced with ‘- effectively setting the equation equal to 0. The normalizing and simplifying code is pretty tidy thanks to core.match
(defn norm [[op exp1 exp2 :as all]]
  (condp = op
    '- (if (number? exp2)
         ['+ (* -1 exp2) exp1]
         ['+ exp1 ['* -1 exp2]])
    '/ (if (number? exp2)
         ['* (/ 1 exp2) exp1]
         all)
    (if (number? exp2) [op exp2 exp1] all)))

(defn simplify-exp [[op x exp2 :as arg]]
  (match [op (if (sequential? exp2) (vec exp2) [])]
         ['+ ['+ y other]] ['+ (+ x y) other]
         ['* ['* y other]] ['* (* x y) other]
         ['* ['+ y other]] ['+ (* x y) ['* x other]]
         :else arg))

(def normalize (partial postwalk #(cond-> % (sequential? %) norm)))
(def simplifier (partial postwalk #(cond-> % (sequential? %) simplify-exp)))
#2022-12-2206:00AppleMy solution for part2: 1. adds to the data set y=x*z and z=y/x when x=y/z is seen. 2. replaces root=x ops y with x=y+0 and y=x+0 #2022-12-2212:51Benjaminlearned the first thing about core.logic https://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day21_logic.clj it was expecially satisfying that part 2 executed instantly#2022-12-2312:44bhauman@U02CV2P4J6S that is absolutely awesome!#2022-12-2121:20AppleDay 21 - Can your solution solve this
root: pppw + sjmn
pppw: 3 + humn
sjmn: 5 - humn
#2022-12-2121:24bhaumanIs that your input? Or just a case that you accounted for?#2022-12-2121:24AppleI am just wondering. The puzzle doesn't exclude this kind of input, right?#2022-12-2121:26Applewith * and / in the mix this could be a problem of solving an equation.#2022-12-2121:26Applei think i can still manage if there's only + and -#2022-12-2121:27bhaumanThe puzzle does exclude this#2022-12-2121:27bhaumanI can tell you more if you want#2022-12-2121:27bhaumanI just finished#2022-12-2121:28AppleOh that's good. So two lines join at the root pretty much#2022-12-2121:33Miķelis Vindavs@U064J0EFR I re-read the problem statement but didn’t find anything that said that each value is used only once#2022-12-2121:33Miķelis Vindavsdid I miss it?#2022-12-2121:34Miķelis VindavsI did my initial p2 solution using z3, because i was worried the equality could be really complex and nonlinear, but ended up making a really simple “reverse application” solution instead#2022-12-2121:34Miķelis Vindavsbut it assumes that humn is only referenced in one branch, and only once#2022-12-2121:34bhaumanin my problem the humn value has a direct line to the root#2022-12-2121:35Miķelis Vindavsright, sure, but i mean the problem statement says nothing about this#2022-12-2121:35bhaumanthat’s true#2022-12-2121:41Callum Oakleyproperties of the input that aren't stated in the puzzle text have to be considered "part of the puzzle" imo or some previous days are borderline impossible#2022-12-2121:42bhaumanyeah there is definitely a stage of doing data analysis on the input for a few of these#2022-12-2121:43Callum Oakleye.g. 2019 day 16 for a particularly infamous example 😅#2022-12-2122:41normanThis is one of the things that has always frustrated me about aoc - the input isn't input to your problem, it IS the problem to solve. The text along side is not a problem spec, it's just some text to help you understand the puzzle/problem you are given. I've come to peace with it over the years of aoc and don't treat it like I would other kinds of programming challenges. I also, always, look at my input and the question asked before I even read the text.#2022-12-2123:58tschadyPart1 my future/promise solution doesn’t care about special input structure, except that it’s solvable. Part2 I definitely looked at the behavior (linear) to simplify.#2022-12-2203:00bhauman@xnooga missing you in here, are you down in the compiler bowels?#2022-12-2210:30noogaI just have too much stuff going on at my day job lately - will prolly try to catch up before new year 😎#2022-12-2214:00mishaDay 22 - Solutions#2022-12-2214:01mishathis was tiresome https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2022/day22.clj#L145-L202#2022-12-2214:02noogadid you mean day22?#2022-12-2214:10Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/22.clj well it's the first time I've made a physical model this year 😂 I hard coded the joins between the faces for the cube, but I was quite pleased with the compactness of the representation (only 7 joins, which get expanded out to the full joins between all the tiles)#2022-12-2214:36Callum Oakleysome people solved the problem in general by doing the folding in 3d... which I really didn't want to do (hence the hard coding), but I like this alternative! very nice: https://www.reddit.com/r/adventofcode/comments/zsct8w/comment/j184mn7/?utm_source=share&amp;utm_medium=web2x&amp;context=3#2022-12-2217:54normanaoc finally took it's toll on me last night. I had to stop mid-part2 and sleep. Now I'm trying to squeeze in some prep while at work ...#2022-12-2220:50normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day22/main.clj finally done, after getting bit by bit done during the day. By cube transitions are hardcoded for my input, so it doesn't work for the sample. I assume different people's inputs have different layouts too, so mine may be just for me... Who knows...#2022-12-2221:10alekszelarkI cut it out ^_^#2022-12-2221:11normanYou had the same layout as me... Did everyone get this layout?#2022-12-2221:19alekszelarkA friend of mine said he had a different unfolding#2022-12-2318:08Felipestuck in part 1. did a little viz to check if the wrapping is wrong, but it seems fine#2022-12-2318:10alekszelarkOh, man, good luck! Especially with part 2.#2022-12-2318:53Felipeoff by one error facepalm was considering my map had one less column than it actually did#2022-12-2221:28AppleDay 22 - What if the map is like this
...     ...#  ...     ...#
...     .#..  ...     .#..
..#     #...  ..#     #...
...     ....  ...     ....
...#.......#  ...#.......#
........#...  ........#...
..#....#....  ..#....#....
..........#.  ..........#.
        ...#....
        .....#..
        .#......
        ......#.
#2022-12-2309:34Miķelis VindavsIs that a hypercube? 😁 #2022-12-2306:12normanDay 23 - Solutions#2022-12-2306:24normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day23/main.clj part 2 from part1 took under 2 minutes, including the 15s it took to run. Clojure definitely made that part easy#2022-12-2308:46mishahttps://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2022/day23.clj#L8-L88#2022-12-2309:32Miķelis VindavsIt took me half an hour to finally understand that the moves need to be rotated after each round :man-facepalming::skin-tone-2: #2022-12-2309:57Eugene Huangverbose, novice clojurian solution. https://github.com/elh/advent-2022/blob/main/src/advent_2022/day_23.clj#2022-12-2310:20alekszelarkhttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_23.clj#2022-12-2311:14alekszelark@U051HUZLD like your idea to group elves by propose while making them, then you don’t need freqs#2022-12-2311:18Callum Oakleyhttps://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/23.clj I was wondering when we would get the annual game of life puzzle 🙂#2022-12-2311:19alekszelark@U01HL2S0X71 I believe tomorrow 🙂#2022-12-2311:19Callum Oakleyah I thought this might have been it. it's arguably "in the spirit of it" even if there's no multiplication 😅#2022-12-2314:12Miķelis Vindavshere’s my solution for today https://github.com/axelarge/advent-of-code/blob/master/src/advent_of_code/y2022/day23.clj#2022-12-2314:14Miķelis Vindavsi did the main part of resolving move conflicts using group-by + mapcat#2022-12-2406:53normanDay 24 - Solution#2022-12-2407:09normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day24/main.clj I did my state management a bit differently than I normally do and ended up messing up the co-ordinates several times because of it. Probably at least a solid 30 minutes of extra debugging because of it.#2022-12-2407:46Miķelis VindavsMissed my alarm clock and overlept for 90mins 😭 Today’s solution is the slowest one in terms of runtime for me, it takes 5 minutes to run. I wonder if I’m missing something real obvious about pruning the search space. @U0954HGDQ how fast does your solution run? it seems like you’re storing a collection of winds for each round, whereas I’m just storing the original position and checking whether a position is occupied by adding time modulo (lcm width, height) , but it’s a linear search over the winds. I wonder if your way could actually be faster#2022-12-2407:47Miķelis Vindavshmm i could memoize the occupied function#2022-12-2407:53Miķelis Vindavswell that cut the runtime down to 2mins 😅#2022-12-2407:58norman
day24.main> (time (part2 full-input))
"Elapsed time: 6188.766655 msecs"
859
#2022-12-2408:01Miķelis Vindavsnice! i think i don’t make enough assumptions about previously visited positions#2022-12-2409:13alekszelarkThe key point is we don’t care how we came in same position at a certain minute, so we can reduce the space by applying set.#2022-12-2409:14Miķelis Vindavsbut we do care, because the winds might be different?#2022-12-2409:15Miķelis Vindavsthey do repeat every lcm(width,height) steps, but besides that#2022-12-2409:17Miķelis Vindavsi fixed my occupied function, now it all runs in 2s 😄#2022-12-2409:17Miķelis Vindavsi was caching whether a position is occupied it at a particular time. instead it makes a lot more sense to cache the position of all blizzards at a particular time, because it can be reused for all positions at that time#2022-12-2409:18alekszelarkFor a certain minute wind is always the same, so if we came at position [2 2] by 10 ways, we can go with only one [2 2].#2022-12-2409:19Miķelis Vindavsyep, but the cache key has to be [(mod time cycle-length) position] not just position#2022-12-2409:19Miķelis Vindavsof course in norman’s solution all times are considered in the same iteration, so I think we’re actually talking about the same thing#2022-12-2409:24alekszelarkYeah, I’m polishing my solution, but basically it’s similar to @U0954HGDQ ’s#2022-12-2409:31Miķelis Vindavsand actually a priority queue isn’t need either, so switching to a regular queue made it even faster 🎉#2022-12-2409:33alekszelarkExactly, first I thought I need something like astar#2022-12-2410:46alekszelarkhttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_24.clj Part 2 runs ~ 2,5 sec#2022-12-2410:58Miķelis Vindavsmod1 seems like a useful function#2022-12-2413:10alekszelark#2022-12-2413:39mishap2 "Elapsed time: 3514.53702 msecs" https://github.com/akovantsev/adventofcode/blob/master/src/adventofcode/y2022/day24.clj#L60-L129#2022-12-2413:44mishamore memoization gives "Elapsed time: 2843.663069 msecs" since wind-map loops every 600 steps#2022-12-2414:03alekszelarkMy answer for part 3 is 4666929 minutes. It’s just 77782 hours, or approximately 8 years of dodging blizzards. Without sleep of course.#2022-12-2505:41normanDay 25 - Solutions#2022-12-2505:50normanhttps://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day25/main.clj#2022-12-2506:05ACthat was a nice finish to this year’s AoC. it took me longer than it should have to remember how to convert bases.#2022-12-2506:06Miķelis Vindavsthe carrying part when converting back to snafu took me a bit to get right#2022-12-2506:08Miķelis Vindavsbut it’s nice that the last one was a bit of a reprieve compared to some of the days in the last week like 19 or 22#2022-12-2506:49Apple
;; 202225
(let [m0 {\2 2, \1 1, \0 0, \- -1, \= -2}
      m1 {2 \2, 1 \1, 0 \0, -1 \-, -2 \=}
      s5->n10 (fn [s] (->> (map m0 s) (reduce (fn [r n] (+ (* 5 r) n)) 0)))
      n10->s5 (fn [n]
                (loop [n n, carry 0, r ()]
                  (if (= n 0)
                    (apply str r)
                    (let [n (+ n carry), x (mod n 5)]
                      (if (<= 0 x 2)
                        (recur (quot n 5) 0 (conj r (m1 x)))
                        (recur (quot n 5) 1 (conj r (m1 (- x 5)))))))))]
  (->> (slurp "resources/202225") (re-seq #"[^\n]+")
       (transduce (map s5->n10) + 0) n10->s5))
;; "2=000=22-0-102=-1001"
#2022-12-2507:38rjrayhttps://github.com/rjray/advent-2022-clojure/blob/master/src/advent_of_code/day25.clj#2022-12-2507:40nbardiukhttps://github.com/nbardiuk/adventofcode/blob/master/2022/src/day25.clj#2022-12-2509:27alekszelarkhttps://github.com/zelark/AoC-2022/blob/master/src/zelark/aoc_2022/day_25.clj#2022-12-2511:33Callum Oakleymerry christmas all! 🎄 https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/25.clj#2022-12-2512:54Miķelis VindavsThanks all for sticking it to the end, seeing other folks' solutions and different approaches made it much more interesting. And happy holidays to everyone!#2022-12-2511:43Callum Oakleywhat are people's total runtimes / linecounts for the year?#2022-12-2511:44Callum Oakleyruntime 28s:
aoc.2022.01/part-1   0.001s   72240                                        *
aoc.2022.01/part-2   0.001s   210957                                       *
aoc.2022.02/part-1   0.006s   11063                                        *
aoc.2022.02/part-2   0.007s   10349                                        *
aoc.2022.03/part-1   0.003s   7793                                         *
aoc.2022.03/part-2   0.003s   2499                                         *
aoc.2022.04/part-1   0.002s   456                                          *
aoc.2022.04/part-2   0.002s   808                                          *
aoc.2022.05/part-1   0.002s   FZCMJCRHZ                                    *
aoc.2022.05/part-2   0.002s   JSDHQMZGF                                    *
aoc.2022.06/part-1   0.001s   1702                                         *
aoc.2022.06/part-2   0.003s   3559                                         *
aoc.2022.07/part-1   0.000s   1611443                                      *
aoc.2022.07/part-2   0.001s   2086088                                      *
aoc.2022.08/part-1   0.059s   1814                                         *
aoc.2022.08/part-2   0.060s   330786                                       *
aoc.2022.09/part-1   0.023s   5695                                         *
aoc.2022.09/part-2   0.099s   2434                                         *
aoc.2022.10/part-1   0.000s   13680                                        *
aoc.2022.10/part-2   0.000s   PZGPKPEB                                     *
aoc.2022.11/part-1   0.001s   117640                                       *
aoc.2022.11/part-2   0.446s   30616425600                                  *
aoc.2022.12/part-1   0.013s   468                                          *
aoc.2022.12/part-2   0.013s   459                                          *
aoc.2022.13/part-1   0.001s   5208                                         *
aoc.2022.13/part-2   0.001s   25792                                        *
aoc.2022.14/part-1   0.005s   979                                          *
aoc.2022.14/part-2   0.190s   29044                                        *
aoc.2022.15/part-1   0.000s   5838453                                      *
aoc.2022.15/part-2   0.003s   12413999391794                               *
aoc.2022.16/part-1   0.020s   1792                                         *
aoc.2022.16/part-2   1.840s   2587                                         *
aoc.2022.17/part-1   0.057s   3175                                         *
aoc.2022.17/part-2   0.112s   1555113636385                                *
aoc.2022.18/part-1   0.008s   3550                                         *
aoc.2022.18/part-2   0.047s   2028                                         *
aoc.2022.19/part-1   4.451s   1262                                         *
aoc.2022.19/part-2   1.604s   37191                                        *
aoc.2022.20/part-1   0.501s   14888                                        *
aoc.2022.20/part-2   5.291s   3760092545849                                *
aoc.2022.21/part-1   0.168s   291425799367130                              *
aoc.2022.21/part-2   0.572s   3219579395609                                *
aoc.2022.22/part-1   0.070s   117054                                       *
aoc.2022.22/part-2   0.056s   162096                                       *
aoc.2022.23/part-1   0.175s   3684                                         *
aoc.2022.23/part-2  10.419s   862                                          *
aoc.2022.24/part-1   0.473s   308                                          *
aoc.2022.24/part-2   1.355s   908                                          *
aoc.2022.25/part-1   0.001s   20===-20-020=0001-02                         *
aoc.2022 (total)    28.305s
linecount: 1214
12    43   297 src/aoc/2022/01.clj
   43   165  1100 src/aoc/2022/02.clj
   31   100   876 src/aoc/2022/03.clj
   25    90   617 src/aoc/2022/04.clj
   39   171  1232 src/aoc/2022/05.clj
   27   104   913 src/aoc/2022/06.clj
   41   184  1295 src/aoc/2022/07.clj
   33   123  1095 src/aoc/2022/08.clj
   41   200  1252 src/aoc/2022/09.clj
   58   241  2595 src/aoc/2022/10.clj
   83   350  2821 src/aoc/2022/11.clj
   38   176  1241 src/aoc/2022/12.clj
   36   141  1064 src/aoc/2022/13.clj
   68   268  2278 src/aoc/2022/14.clj
   67   424  2816 src/aoc/2022/15.clj
   91   488  3626 src/aoc/2022/16.clj
   61   317  2184 src/aoc/2022/17.clj
   32   124  1143 src/aoc/2022/18.clj
   74   345  2930 src/aoc/2022/19.clj
   41   205  1522 src/aoc/2022/20.clj
   33   169  1121 src/aoc/2022/21.clj
   90   443  3710 src/aoc/2022/22.clj
   50   189  1632 src/aoc/2022/23.clj
   67   322  2338 src/aoc/2022/24.clj
   33   171  1145 src/aoc/2022/25.clj
 1214  5553 42843 total
#2022-12-2713:43noogauh, I have 14 days to solve now 😅#2023-01-0302:16Alex AlemiI rounded out my calendars:#2023-01-0302:16Alex Alemirepo here: https://github.com/alexalemi/advent its 60% Clojure#2023-01-2000:35ACAnyone working on the Protohacker problems? They’re a nice complement to AoC. https://protohackers.com/#2023-01-2000:38ACI have never used Java and had only barely touched Java interop. These have been a fun way to “level up” and also learn how to read Java docs and translate that to clojure code.#2023-01-2011:19noogaI'd say these are way more hardcore than AoC#2023-01-2011:19noogafirst thing I see is I have to reverse engineer some unknown protocol 😂#2023-01-2018:13ACThat one (#10) looks like it’ll be fun, but I’m just starting #8 now. While they don’t necessarily get progressively harder, you’ll want to start with the earlier ones.#2023-01-2915:12noob.cljNot going to lie, protohacker questions make me feel like I am fresh out of college and don’t know anything. And I’ve been developing for years 😞. It would be fun to read some stuff and try it. Where do you guys usually deploy your code?#2023-01-3000:40ACI had written network code in other languages but not in clojure, so I felt similar. I learned a lot about java interop and core.async. I started out building uberjars and launching in externally-hosted docker containers, but it was easier to just add a port redirect to my laptop and test against that. especially with #10 where you learn the specs through testing.#2023-02-0115:28normanhttps://gitlab.com/maximoburrito/protohackers just started - looks fun#2023-02-1216:19noogahttps://play.battlesnake.com/ another fun online challenge that could use stronger Clojure representation 😉 I've deployed a bot written in let-go, same lang as my AoC solutions from last year#2023-03-0604:19ACanother fun set of challenges (after you finish AoC and Protohackers) -- https://fly.io/dist-sys/ https://fly.io/blog/gossip-glomers/#2023-03-1920:31Eugene Huanghighly recommend! had a lot of fun doing them. was also a good opportunity to learn some patterns for futures and concurrency from aphyr’s demo code https://github.com/elh/gossip-glomers#2023-11-0514:32pesterhazyLess than a month to go until AOC2023. Which raises the obvious questions: What language to use? What to focus on? (Static types? Unit testing? Optimize for fast feedback? Learn new editor?)#2023-11-0514:33pesterhazyI'm thinking Elisp this year - not sure if this is wise...#2023-11-0514:55borkdudeI hope some people will try #C03U8L2NXNC #2023-11-0515:42pezhttps://youtu.be/0rJvOtbJDyI?si=G5h1v6VIQmVYMWbO#2023-11-0518:29peterhI am considering Janet, since I had a great experience learning it this year and I especially want to see how far I can go with PEGs (parsing expression grammars, built into Janet) and how I can work with a mix of imperative and functional code, maybe learning some C along the way.#2023-11-0520:44MaxI had a good time doing some of last year’s puzzles in APL. There’s a relatively nice setup you can get working with an APL kernel for Jupyter. Some of the puzzles are more trouble than they’re worth though#2023-11-0609:41elkenClojure & #clerk is the dream combo 🙂 https://www.juxt.pro/blog/using-clerk-for-aoc/#2023-11-0612:46karlisAnother year, another naïve plan to use Idris 2 as the "language to learn".#2023-11-0615:06Charles Comstock@U06F82LES In the past, I've tried to do a new language each day, so solved a couple using elisp. It was interesting, though a struggle to move back into the mutable mindset. Restartable error conditions were nice though.#2023-11-0615:57pesterhazyI'd like to be more comfortable with writing my own emacs modes. So I figured elisp might help with that#2023-11-0700:13Andrew MeinersI'm still a Clojure beginner so just plain and simple Clojure for as far as I can reach! Probably dropping into Java since I have work experience with that once I hit the wall#2023-11-0701:06Phil ShapiroThe first year I did AoC I used elisp. Not sure I learned much from it that would help writing a custom emacs mode… I did learn a lot about Common Lisp style loop. https://github.com/pshapiro4broad/advent2019 #2023-11-0714:22Georgi Stoyanov@U047L83TC77 same here. The idea to try different languages is a nice one, I could actually try Haskell or rust this year for some of the tasks 🙈 #2023-11-0719:14mauricio.szaboI am thinking about Smalltalk 😄#2023-11-0719:45tschadymy goal is to kill my completionism and quit when it ceases to be fun#2023-11-0719:47pezGood luck with that, @U1Z392WMQ 😃#2023-11-0719:49tschadyi’ve got hope, i’ve managed to not lose any sleep for last 2 yrs, that’s a start.#2023-11-0816:25James LandreinThis year I'll try to finish it in clojure 😄 (and probably rust too as well as keeping performance acceptable as an exercise for performant clojure, that should be fun)#2023-11-0816:32pesterhazyPerformance or profiling could be an interesting focus. Flame graphs are so hard to read#2023-11-0816:33James LandreinA friend a mine did it a couple years ago with the goal of having of the exercises running under 1s of runtime#2023-11-0816:33James LandreinWas a nice exercise 😄#2023-11-1405:03Ben SlessThinking of trying J