Fork me on GitHub
#adventofcode
<
2023-12-01
>
nbardiuk07:12:10

Day 1 - Solutions 🧵

Sam Ferrell07:12:55

https://github.com/samcf/advent-of-code/blob/main/2023-01-trebuchet.clj Got frustrated with regex and resorted to index-of and last-index-of

👍 3
😍 2
vollcheck09:12:08

re-seq + (juxt first last) to the rescue 😉 https://github.com/vollcheck/aoc/blob/master/src/y23/day01.clj

👍 2
❤️ 1
borkdude10:12:46

My solution in #C03U8L2NXNC : https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa7da6236e9670681a93761b81fd66ad26c119164%2Faoc_ui.cljs&amp;repl=true&amp;src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgooZGVmIGlucHV0ICgtPj4gKGpzLWF3YWl0IChmZXRjaC1pbnB1dCAyMDIzIDEpKQogICAgICAgICAgICAgc3RyL3RyaW0KICAgICAgICAgICAgIHN0ci9zcGxpdC1saW5lcykpCgooZGVmbiBkaWdpdHMgW3NdCiAgKHZlYyAoa2VlcCBwYXJzZS1sb25nIHMpKSkKCihkZWZuIGZpcnN0LWFuZC1sYXN0LWRpZ2l0cyBbZGlnaXRzXQogIChzdHIgKGZpcnN0IGRpZ2l0cykgKGxhc3QgZGlnaXRzKSkpCgooY29tbWVudAogICgtPiAoZGlnaXRzICJhMWIyIikKICAgIChmaXJzdC1hbmQtbGFzdC1kaWdpdHMpCiAgICBwYXJzZS1sb25nKQogICkKCihkZWZuIHBhcnQtMQogIFtpbnB1dF0KICAoLT4%2BIGlucHV0CiAgICAobWFwIGRpZ2l0cykKICAgIChtYXAgKGNvbXAgcGFyc2UtbG9uZyBmaXJzdC1hbmQtbGFzdC1kaWdpdHMpKQogICAgKGFwcGx5ICspKSkKCihjb21tZW50CiAgKHBhcnQtMSBpbnB1dCkpCgooZGVmIHdvcmQtPmRpZ2l0IHsib25lIiAxCiAgICAgICAgICAgICAgICAgICJ0d28iIDIKICAgICAgICAgICAgICAgICAgInRocmVlIiAzCiAgICAgICAgICAgICAgICAgICJmb3VyIiA0CiAgICAgICAgICAgICAgICAgICJmaXZlIiA1CiAgICAgICAgICAgICAgICAgICJzaXgiIDYKICAgICAgICAgICAgICAgICAgInNldmVuIiA3CiAgICAgICAgICAgICAgICAgICJlaWdodCIgOAogICAgICAgICAgICAgICAgICAibmluZSIgOX0pCgooZGVmIHJlCiAgOzsgZm9yIGxhY2sgb2YgcmUtcGF0dGVybgogIChuZXcganMvUmVnRXhwCiAgICAoc3RyIChzdHIvam9pbiAifCIgKGtleXMgd29yZC0%2BZGlnaXQpKSAifFxcZCIpKSkKCihkZWZuIG1hdGNoLW92ZXJsYXBwaW5nCiAgInJlLXNlcSB3aXRoIG92ZXJsYXAiIAogIFtyZSBzXQogIChsb29wIFttYXRjaGVzIFtdCiAgICAgICAgIHMgc10KICAgIChpZi1sZXQgW21hdGNoIChyZS1maW5kIHJlIHMpXQogICAgICAocmVjdXIKICAgICAgICAgIChjb25qIG1hdGNoZXMgbWF0Y2gpCiAgICAgICAgKHN1YnMgcyAoaW5jICguaW5kZXhPZiBzIG1hdGNoKSAyKSkpCiAgICAgICh2ZWMgbWF0Y2hlcykpKSkKCihjb21tZW50CiAgKHZlYyAobWF0Y2gtb3ZlcmxhcHBpbmcgcmUgIm9uZTF0d294dGhyZWU0ZWlnaHR3byIpKSkKCihkZWZuIGRpZ2l0cysgW3NdCiAgKG1hcHYgIyhvciAoZ2V0IHdvcmQtPmRpZ2l0ICUpIChwYXJzZS1sb25nICUpKQogICAgKG1hdGNoLW92ZXJsYXBwaW5nIHJlIHMpKSkKCihjb21tZW50CiAgKC0%2BIChkaWdpdHMrICJ0d28xbmluZSIpCiAgICBmaXJzdC1hbmQtbGFzdC1kaWdpdHMKICAgIHBhcnNlLWxvbmcpCiAgKQoKKGRlZm4gcGFydC0yCiAgW2lucHV0XQogICgtPj4gaW5wdXQKICAgIChtYXB2IGRpZ2l0cyspCiAgICAobWFwdiBmaXJzdC1hbmQtbGFzdC1kaWdpdHMpCiAgICAobWFwdiBwYXJzZS1sb25nKQogICAgKGFwcGx5ICspKSkKCihjb21tZW50CiAgKGRlZiBpbnB1dCogKHN0ci9zcGxpdC1saW5lcyAidHdvMW5pbmUKZWlnaHR3b3RocmVlCmFiY29uZTJ0aHJlZXh5egp4dHdvbmUzZm91cgo0bmluZWVpZ2h0c2V2ZW4yCnpvbmVpZ2h0MjM0CjdwcXJzdHNpeHRlZW4iKSkKICAocGFydC0yIGlucHV0KQogICk%3D

👍 3
genmeblog10:12:07

first day first problems with understanding of the task... anyway, the solution: https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2023/day01.clj

👍 1
vollcheck10:12:32

first day first problems with understanding of the task...I had the same feeling 🙂

borkdude10:12:28

The overlapping regex thing sure was tricky ;)

☝️ 1
1
vollcheck10:12:58

I definitely need to read not only descriptions but test data more carefully...

oyakushev11:12:50

Here's what happens when you are dumb and don't know about overlapping regexes https://gist.github.com/alexander-yakushev/06485fe945e30691a1f4d0c87be1f4d9

❤️ 2
👍 1
potetm13:12:14

It never occurred to me until now to put an entire regex into a zero-width lookahead/lookbehind.

potetm13:12:32

When I saw it, I actually thought it might be invalid syntax lol

vollcheck13:12:46

I guess there's lot more things that Eric want to teach us about this year 😛

potetm13:12:38

I suppose it's that with the outer capture group that makes it work

borkdude13:12:06

I like the pragmatic idiot-solution driven approach instead of trying to be elegant today ;)

tschady13:12:10

maybe the strategy is reduce server costs by losing your audience day 1

😆 2
tschady13:12:43

in total anger, my first pass was munging the number-words to duplicate the last character so I could destructively replace. “eight” -> “eightt”

1
tschady13:12:38

second pass looks almost identical to others here. https://github.com/tschady/advent-of-code/blob/main/src/aoc/2023/d01.clj

👍 4
1
oyakushev14:12:21

@U1Z392WMQ Same sentiment, really. I got irrationally angry over AoC today. I rallied up a bunch of friends for it this year and promised that it's gonna start easy, and the very first day is such a newbie-destroyer.

borkdude14:12:50

That was my feeling too. Day 1 should be a give-away

vollcheck14:12:03

do you think it's the Eric way of defending against the continuously rising AI tooling?

borkdude14:12:44

Well, to be honest, this is what you can expect from the rest of AoC, there's always an angry throw-keyboard-out-of-window thing in there ;)

oyakushev14:12:53

Yeah, it's usually like that, and it's all fine and dandy. Just pulling that out day 1 will shoot a lot of unfamiliar folks down.

👍 3
nbardiuk14:12:01

Today task is easy for an approach when one iterates over indexes and check if there is a word at that position. I've noticed that Jonathan Paulson was lucky and didn't even notice edge cases https://www.youtube.com/watch?v=rnidYOt9m2o

vollcheck14:12:25

yup, I guess we (me for sure) got kinda tricked by the Clojure that encourages to treat everything as a collection to apply functions over in compare to Python when you have more imperative way of thinking

potetm14:12:42

> pragmatic idiot-solution driven I think I should put this on my linked in

😂 3
tschady14:12:38

looks like 37% of people gave up on part2 (or went to bed).

1  46999  27759 

borkdude15:12:02

Oh I didn't even think about this edge case:

blah7foo is 77
but I guess it just worked because I did first and last on a vector (with a single element)

😏 1
Sam H15:12:23

ended up getting frustrated with the tricky eightwo case and ended up replacing all the words with the digit wrapped in words 😅 eight8eight

😆 2
😂 2
muthui shere15:12:34

https://github.com/muthuishere/advent-of-code-clojure-2023. Did a livestream as well https://www.youtube.com/watch?v=15DdYethJHg. Part2 is definitely not a day 1 problem !!! https://www.youtube.com/watch?v=q60gepcBaZs My code No regex , a plain stuff

(def text-digits ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"])
(defn is-string-a-number [inp]
  (not= nil (parse-long inp)))

(defn text-to-number [input]
  (str (inc (.indexOf text-digits input))))

(defn get-position-info-at-index [index input text-digit]
  (if (str/index-of input text-digit index)
    {:text-digit text-digit :index (str/index-of input text-digit index) :digit-to-be-replaced (text-to-number text-digit) }
    nil))

(defn get-position-info [input text-digit]
  (let [first-index (str/index-of input text-digit)
        last-index   (str/last-index-of input text-digit)]
    (if (not= first-index last-index)
      [(get-position-info-at-index 0 input text-digit) (get-position-info-at-index (dec last-index)  input text-digit)]
      [(get-position-info-at-index 0 input text-digit)])))

(defn get-all-position-data [currentline]
  (->> text-digits
       (map #(get-position-info currentline %1))
       (flatten)
       (filter not-empty)
       (sort-by :index  #(compare %2 %1))))

(defn replace-input-with[input position-info]
  (let [index (get position-info :index)
        digit-to-be-replaced (get position-info :digit-to-be-replaced)]
    (str (.substring input 0 index) digit-to-be-replaced  (.substring input (inc index) ))))

(defn convert-text-digit-to-normal-digit [input]
  (reduce #(replace-input-with %1 %2)
             input (get-all-position-data input)))

(defn first-and-last [inp]
  (let [first-one (first inp)
        last-one (last inp)]
    [first-one last-one]))

(defn calibrate [input]
  (->> input
       (convert-text-digit-to-normal-digit)
       (map str)
       (filter is-string-a-number)
       (first-and-last)
       (reduce  str)
       (parse-long)))

(defn read-as-array-from-classpath [filename]
  (->> filename
       (io/resource)
       (slurp)
       (str/split-lines)))

(defn find-total-calibration-value-in [filename]
  (->> filename
       (read-as-array-from-classpath)
       (map calibrate)
       (filter #(some? %1))
       (reduce +)))

(comment

  (find-total-calibration-value-in "original.txt")
  (find-total-calibration-value-in "sample.txt"))

🎉 2
ric15:12:33

I'm more annoyed by having to hunt edge cases in a thousand-line file. Including it in the examples in a less subtle way would've been nice 🙂

👍 1
j4m3s15:12:53

kinda curious, did any of you figure out the overlapping regexes from the explanation or from trying it out ?

Sam H15:12:14

for me it was running the code on the second sample and then double checking why the answer was out

tschady15:12:59

whenever I hit these problems I scrutinize the examples, caught eightwothree eventually.

👍 1
tschady15:12:17

tho at first I put in 10-19 after I saw

7pqrstsixteen

Sam H15:12:09

yeah, I was thrown off by the sixteen but then searched my input for teen but didn't see anything. Then re-read the instructions finally 😄

fingertoe15:12:56

I need to brush up on my regex. Got lazy and did some silly string reverse regex to get the answer to #2, so I could go to bed.

borkdude15:12:44

that's actually not too bad a solution, maybe performance-wise even faster

Ben Lieberman16:12:20

I'm relieved to see other people finding the lookaround regex solution a pain 😅

fingertoe16:12:45

@j4m3s I got a pretty good hint because I originally had a used map to string replace the strings with digits. Because the map was in random order, I got lucky and saw the eigh2. If the map had had eight first, it wouldn’t have been so intuitive that the same problem was happening at the end on my full dataset. I had it passing the example data, but not my full data.

👍 2
jurjanpaul16:12:57

This time I imagined the overlap edge case as soon as I read part 2, before encountering any evidence of its occurrence. Experience, I guess. I was lucky to quickly find an example of expressing the regex for overlapping matches, which I definitely did not know by heart. TIL (?=...). Only later did I think of the sensible reverse regex approach.

maleghast16:12:20

I just used clojure.string/replace with a list of potential overlaps coming first in the | list in the regex, because I don't get overlapping regexes. I only did that once I realised that the overlapping edge-case was being enforced. I thought it was a pretty crappy thing to not explain explicitly

1
maleghast16:12:08

Like this:

(defn numbers-as-text-to-digits
  "Convert text expressions of numbers 1-9 into string digits"
  [input-string]
  (str/replace
   input-string
   #"oneight|threeight|fiveight|nineight|twone|eightwo|eighthree|sevenine|one|two|three|four|five|six|seven|eight|nine"
   {"oneight" "18"
    "threeeight" "38"
    "fiveight" "58"
    "nineight" "98"
    "twone" "21"
    "eightwo" "82"
    "eighthree" "83"
    "sevenine" "79"
    "one" "1"
    "two" "2"
    "three" "3"
    "four" "4"
    "five" "5"
    "six" "6"
    "seven" "7"
    "eight" "8"
    "nine" "9"}))

think_beret 1
maleghast16:12:15

I accept that it only "works" because there are a very limited number of overlaps that are possible because of how the words for numbers are spelled,

jurjanpaul16:12:36

I like how pragmatic that is!

🙇 1
maleghast16:12:25

Also, I've just spotted a typo that means that threeight is not one of the overlaps in the input data as I got the correct answer despite matching on threeeight (incorrectly)

wevrem17:12:24

what about triplets like eightwone? Or even fiveightwone? Maybe they don’t show in the input data?

maleghast17:12:48

The first and last words will be matched by the primitive words in the | list

borkdude17:12:50

that doesn't matter probably since you only need to discover the first and last?

borkdude17:12:02

(I'm pretty confused about this the minute I said it haha)

maleghast17:12:41

FWIW @U04V15CAJ, I ❤️ your part1 digit sieve, using keep and parse-long Mine was similar but far less beautiful

❤️ 1
Ryan Martin17:12:56

what?!! didn't know overlapping regex was possible... all I could think of was regex with a reversed string (re-seq #"\d|eno|owt|eerht|ruof|evif|xis|neves|thgie|enin") :rolling_on_the_floor_laughing:

j4m3s17:12:01

oh yeah, just figured that we don't need regexes per se, just prefix/suffix match 😮

potetm17:12:32

yeah reversing crossed my mind too

potetm17:12:35

but I'm too lazy

maleghast17:12:55

@U0355S1RV60 - Please go into detail, I wish to learn and what you said there ^^ makes no sense to me 🙂

j4m3s17:12:38

like eightwothree you only need first and last, so you could match first string from the beginning with exact string, and same from the end of the string ?

maleghast17:12:00

Oh I see what you mean, yes. That I understaood

j4m3s17:12:02

Just an idea on top of my head tho, haven't tested ~

genmeblog17:12:07

One of the most interesting approaches I've seen today was replacing one with o1e, two with t2o and so on. Then just extract digits.

🤯 6
maleghast17:12:11

The problem with overlaps between just two words for numbers is that there are a handful that share a letter and because the match on the first wipes out the match on the second you have to match twone and eighthree and so on as separate options in the regex

j4m3s17:12:55

yeah but technically you don't really need regexes since it's an exact string match 🙂

j4m3s17:12:19

(it is much easier to write though, so that's what I did )

potetm17:12:19

the numbers aren't exactly at the end or beginning, so you have to compensate for that somehow

maleghast17:12:23

@U1EP3BZ3Q I saw that on a Python-based solutions thread after I'd finished (was looking around to see how people had done it out of curiosity) and I couldn't figure out how that would handle two word overlaps.

👍 1
borkdude17:12:54

the first puzzle drives you to regex and then the second puzzle punishes you for choosing that direction, very AOC

☝️ 3
1
maleghast17:12:01

@U0355S1RV60 - i see what you mean, but an OR regex in the right order with a list of replacements inside clojure.string/replace is so convenient 🙂

Jakob Durstberger17:12:28

I am also trying to record a video for each day. I have to say, I really struggled with the overlapping numbers 😬 https://youtu.be/7zD4OYcqaWI

👀 1
maleghast17:12:37

@U04V15CAJ - I agree, but having Clojure to hand i didn't go near regex for part1

Jakob Durstberger17:12:36

@U08ABGP70, spotted your string/replace solution and had my mind blown 😄

🙇 2
maleghast17:12:27

Glad you liked it @UM8P1G72Q

👍 2
genmeblog17:12:57

@U08ABGP70 when you replace, both ends are still in the string and the next substitution works. oneightwo becomes o1ei8ght2o

🤯 1
maleghast17:12:43

That is so cool 😎

genmeblog17:12:58

Me too! Clever.

maleghast17:12:12

Thanks I was blocking on why it would work - I appreciate the mental nudge 🙂

j4m3s17:12:44

also, means you can do it in place and not allocate memory 😮 (although, not very clojurey)

Jakob Durstberger17:12:07

I like that that approach works, but I think @U08ABGP70 way of replacing is easier to understand when reading the code. But again something I would not have thought of

vollcheck17:12:01

I'm thinking also about recording a videos of that, but from the post-solution analysis perspective - do you think that might be interesting?

borkdude17:12:44

Maybe a video of combining all of the coolest clojure hacks would be cool ;)

☝️ 3
maleghast17:12:12

@U03N5HN4K1N - I would say try it and find out..? I think that there is enough interest overall in AoC and it's a good way to get Clojure coolness out there

maleghast17:12:41

I would definitely watch (once I had done the day's challenges)

Jakob Durstberger17:12:50

Agreed! Go for it! I'd like to see a video that collected different approaches. I have learned about two different approaches by just reading this thread.

fingertoe17:12:40

It would be interesting to see which approach is most performant, but also which one is easiest to look at, parse, and understand, and what that trade-off costs.

vollcheck17:12:40

thank you people for the motivation and ideas! I will try to compile some stuff on the evening

maleghast17:12:47

Here is my full solution in case you would like to share it: https://gist.github.com/maleghast/9bc7cd4851d0563de9686394b1debe37

👀 1
maleghast17:12:45

Oh, that's how you do lookahead regexes 🙂

Jakob Durstberger17:12:44

I honestly still don't understand them fully. I got it to work in that situation, but I am not certain I could correctly use it in other cases. Scratch that. It actually just clicked. To be fair, it does feel quite hacky now that I understand how it works 😕

borkdude17:12:56

I made this (brute-force) overlapping re-seq because googling for this look-ahead syntax took too long ;)

(defn match-overlapping
  "re-seq with overlap" 
  [re s]
  (loop [matches []
         s s]
    (if-let [match (re-find re s)]
      (recur
          (conj matches match)
        (subs s (inc (.indexOf s match) 2)))
      (vec matches))))

👏 2
j4m3s17:12:43

I initially went the way to implement this through aggressive re-find use

borkdude17:12:31

@U05PEDP7J85 Beautiful, I guess one could unduplicate that regex pattern with str/reverse and use re-pattern as well

😲 1
Jakob Durstberger17:12:25

@U05PEDP7J85 that is brilliant! I wonder if you could extract the regex-pattern string before making it a regex and reverse it too so you don't need the eno|owt|... borkdude beat me to it

Ryan Martin17:12:05

Yeah, didn't think about that earlier. Was just focused on getting a correct answer

borkdude17:12:15

I think you can use clojure.pprint/cl-format to get the human names for numbers too, and then compose the regex from that ;)

🤯 3
😱 1
💛 1
maleghast17:12:48

That would be fully awesome

borkdude17:12:24

user=> (pp/cl-format nil "~r" 1)
"one"
just sayin'

👍 1
Ben Lieberman17:12:30

cl-format is such a great addition to the language, I'm doing this year's AOC in CL and I'm learning the ropes of format there and wow, what a tool

chaos18:12:23

(solution in basilisp - a clojure compatible dialect for python) https://github.com/ikappaki/aoc23-basilisp/blob/master/day1.clj

🆒 2
Felipe18:12:00

took me much much much longer than expected to get twone right

borkdude18:12:21

@U012BL6D9GE nice, never heard of basilisp!

Felipe18:12:29

wait what, clojure.string/reverse is a thing?

wevrem18:12:56

After reading this thread, I did a version 2 with reversed string and reversed regex which I like better than my original version with “fancy” regex. https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2023/day_01_trebuchet_v2.clj

👀 1
chaos18:12:36

(@U04V15CAJ I've recently ported the https://github.com/basilisp-lang/basilisp/pull/723 to it, I was waiting for the basilisp author to review it before contacting you with regards to copyright and credits. It's amazing how much effort he has put to it. I've been using it for a while and thought to put it on the test with AoC)

Chase18:12:09

https://github.com/chase-lambert/aoc-clojure/blob/main/src/aoc/2023/day_01.clj holy schnikeys, was not expecting Part 2 to hit that hard on Day 1. I finally looked up how to do overlapping regexes when I figured out why the example data was passing but not the real stuff. My solution is ugly and probably horrifically inefficient as of now. I may have talked a couple of new programmers into trying AOC with promises the first few days are easy. lol oops

mrnhrd18:12:07

Part 2 of this was so hard for me being a clj beginner who doesn't like regex, I just cheated by looking at solutions here. What a day 1. I feel the overlap thing ought to be possible to do with seq and stuffs.

Felipe18:12:51

@U05N15QDUHX it was hard for me too as a non-beginner who likes regex

3
fingertoe18:12:44

Interestingly, the imperative folks don’t seem to be having as much trouble. Their first instinct is to index everything, while our first instinct to first/last leads us astray, I suspect?

Casey18:12:39

Yea there's lots of talk (her and HN) about it being hard but I feel like it wasn't that difficult if you didn't try to use regex for part 2.

Casey19:12:51

I just parsed the strings into a map of pos-->digit, keys, sort, first/last

Casey19:12:01

Of course saying it's easy or not easy (overall ) is a hard judgement to make, as one is clouded by their experience

Sam Ferrell19:12:12

some implementations accidentally picked the right arbitrary overlap rule, some did not

tschady19:12:59

@U1EP3BZ3Q’s two -> t2o is my kind of solution, your yearly reminder to punch AOC input until it quacks.

❤️ 1
🦆 2
genmeblog19:12:54

regex solution was obvious for me, but this kind of hacking is the best one :)

Felipe19:12:10

@U70QFSCG2 I think the hard part is realizing that overlaps can happen. even when I did notice it I missed that you can't just replace the first occurrence, reverse the string and do the same to find the last one, because if you have simply twone it becomes 2ne

Felipe19:12:40

in a funny way I was bitten by "mutability" in a mostly immutable language

Sam19:12:41

Dodging regex until I die. eightwothree becomes eight8eighttwo2twothree3three.

(def literal->digit 
              [["one" "1"]
              ["two" "2"]
              ["three" "3"]
              ["four" "4"]
              ["five" "5"]
              ["six" "6"]
              ["seven" "7"]
              ["eight" "8"]
              ["nine" "9"]])

(def star2 "54591"
  (problem1 (reduce (fn [s [literal digit]]
                (string/join
                 (str literal digit literal)
                 (string/split s (re-pattern literal))))
              input
              literal->digit)))

Cora (she/her)19:12:38

some of it is probably suboptimal

borkdude19:12:18

you can read the puzzle input using fetch-input

borkdude19:12:38

Cmd-Enter evaluates expressions (or the Windows key on other kbds)

borkdude19:12:13

and then you can hit "Share" + copy the url to share

1
Luke Zeitlin19:12:44

(def name->num {"one"   1
                "two"   2
                "three" 3
                "four"  4
                "five"  5
                "six"   6
                "seven" 7
                "eight" 8
                "nine"  9
                "1"     1  
                "2"     2
                "3"     3
                "4"     4
                "5"     5
                "6"     6
                "7"     7
                "8"     8
                "9"     9})

(defn starts-with-num [s]
  (loop [ss s]
    (or (some (fn [[k v]]
                (when (clojure.string/starts-with? ss k)
                  v))
              name->num)
        (recur (subs ss 1)))))

(defn ends-with-num [s]
  (loop [ss s]
    (or (some (fn [[k v]]
                (when (clojure.string/ends-with? ss k)
                  v))
              name->num)
        (recur (subs ss 0 (dec (count ss)))))))

(defn cal-val [input]
  (->> input
       ((juxt starts-with-num ends-with-num))
       (apply str)
       read-string))

(-> "aoc/day1input.txt"
    slurp
    (clojure.string/split #"\n")
    (->> (map cal-val)
         (reduce +)))

Janet A. Carr19:12:59

my solution after figuring out the annoying 'regex' issue:

(ns advent-of-code.day-one
  (:require [clojure.string :as s]))

(defn part-one
  []
  (apply + (map (fn [line]
                  (let [numbers (re-seq #"\d" line)
                        num (str (first numbers)
                                 (last numbers))]
                    (try
                      (Integer/parseInt num)
                      (catch Exception e
                        (println "that's what you get for impurity")
                        0))))
                (line-seq ( "./input/day1.txt")))))

(defn part-two
  []
  (apply + (map (fn [line]
                  (let [lookup {"one" "1" "two" "2" "three" "3" "four" "4"
                                "five" "5" "six" "6" "seven" "7" "eight" "8" "nine" "9"}
                        numbers (->> line
                                     (re-seq #"(?=(\d|one|two|three|four|five|six|seven|eight|nine))")
                                     (map second)
                                     (map #(get lookup % %)))
                        num (str (first numbers)
                                 (last numbers))]
                    (try
                      (Integer/parseInt num)
                      (catch Exception e
                        (println "that's what you get for impurity")))))
                (line-seq ( "./input/day1.txt")))))

🎉 1
oyakushev20:12:11

BTW, Clojure 1.11 added parse-long that can be used instead of Integer/parseInt.

👆 2
borkdude20:12:52

keep parse-long is a very nice idiom for this

Janet A. Carr20:12:57

@U06PNK4HG I couldn't remember what it was called. lol

Janet A. Carr20:12:29

parse-int? nope throws an error. Just going to do the dirty parseInt.

🗿 1
borkdude20:12:35

it basically does what you have written :)

borkdude20:12:42

except that it returns nil

borkdude20:12:49

hehe alright

Janet A. Carr20:12:53

It also won't insult me. haha

😆 1
mrnhrd20:12:05

(def digit-strings 
    ["one" "two" "three" "four"
     "five" "six" "seven" "eight" "nine" 
     "1" "2" "3" "4" "5" 
     "6" "7" "8" "9"])

  (->> digit-strings 
       (map #(vector (str/index-of "xtwone3four" %) %))
       (filter first)
       (into (sorted-map))); => {1 "two", 3 "one", 6 "3", 7 "four"}
pseudo-edit: now if only index-of returned the indexes of all occurences :face_with_rolling_eyes:

wevrem20:12:46

or add in using str/last-index-of

👀 1
Cora (she/her)20:12:56

converted my solution over to the squint playground https://squint-cljs.github.io/squint/?boilerplate=https%3A%2F%2Fgist.githubusercontent.com%2Fborkdude%2Fcf94b492d948f7f418aa81ba54f428ff%2Fraw%2Fa7da6236e9670681a93761b81fd66ad26c119164%2Faoc_ui.cljs&repl=true&src=OzsgSGVscGVyIGZ1bmN0aW9uczoKOzsgKGZldGNoLWlucHV0IHllYXIgZGF5KSAtIGdldCBBT0MgaW5wdXQKOzsgKGFwcGVuZCBzdHIpIC0gYXBwZW5kIHN0ciB0byBET00KOzsgKHNweSB4KSAtIGxvZyB4IHRvIGNvbnNvbGUgYW5kIHJldHVybiB4CgooZGVmbiBzbHVycAogIFtwcm9ibGVtXQogIChmZXRjaC1pbnB1dCAyMDIzIHByb2JsZW0pKQoKKGRlZm4gcGFyc2UtbGluZXMKICBbc10KICAoLT4gcyBzdHIvdHJpbSBzdHIvc3BsaXQtbGluZXMpKQoKKGRlZiB0ZXh0LT5kaWdpdAogIHsib25lIiAxCiAgICJ0d28iIDIKICAgInRocmVlIiAzCiAgICJmb3VyIiA0CiAgICJmaXZlIiA1CiAgICJzaXgiIDYKICAgInNldmVuIiA3CiAgICJlaWdodCIgOAogICAibmluZSIgOQogICAiMSIgMQogICAiMiIgMgogICAiMyIgMwogICAiNCIgNAogICAiNSIgNQogICAiNiIgNgogICAiNyIgNwogICAiOCIgOAogICAiOSIgOX0pCgooZGVmbiBtYXRjaC1udW1iZXJzLTEKICBbc10KICAoZG9hbGwgKHJlLXNlcSAjIlxkIiBzKSkpCgooZGVmIG51bWJlci1yZWdleHAKICAiUG9zaXRpdmUgbG9va2FoZWFkIHNvIHRoYXQgd2UgY2FuIGdldCBvdmVybGFwcGluZyBtYXRjaGVzLiIKICAoanMvUmVnRXhwLiAiKD89KG9uZXx0d298dGhyZWV8Zm91cnxmaXZlfHNpeHxzZXZlbnxlaWdodHxuaW5lfFxcZCkpIiAiZyIpKQoKKGRlZm4gbWF0Y2gtbnVtYmVycy0yCiAgW3NdCiAgKC0%2BPiAoLm1hdGNoQWxsIHMgbnVtYmVyLXJlZ2V4cCkKICAgICAgIChtYXB2ICMoZ2V0ICUgMSkpKSkKCihkZWZuIG1hdGNoZXMtPm51bWJlci0xCiAgW3hzXQogIChqcy9wYXJzZUludCAoc3RyIChmaXJzdCB4cykgKGxhc3QgeHMpKSkpCgooZGVmbiBtYXRjaGVzLT5udW1iZXItMgogIFt4c10KICAobGV0IFtudW1iZXJzIChtYXB2IHRleHQtPmRpZ2l0IHhzKV0KICAgIChqcy9wYXJzZUludCAoc3RyIChmaXJzdCBudW1iZXJzKSAobGFzdCBudW1iZXJzKSkpKSkKCigtPj4gKGpzL2F3YWl0IChzbHVycCAxKSkKICAgICBwYXJzZS1saW5lcwogICAgIChtYXAgbWF0Y2gtbnVtYmVycy0xKQogICAgIChtYXAgbWF0Y2hlcy0%2BbnVtYmVyLTEpCiAgICAgKHJlZHVjZSArKQogICAgIGFwcGVuZCkKCigtPj4gKGpzL2F3YWl0IChzbHVycCAxKSkKICAgICBwYXJzZS1saW5lcwogICAgIChtYXAgbWF0Y2gtbnVtYmVycy0yKQogICAgIChtYXAgbWF0Y2hlcy0%2BbnVtYmVyLTIpCiAgICAgKHJlZHVjZSArKQogICAgIGFwcGVuZCk%3D

borkdude20:12:56

@U02N27RK69K awesome, got the same answers using my unique puzzle input 🎉 🎉

🎉 2
mrnhrd20:12:55

Newb solution to part2 (part1 fell victim to my edit history): https://gist.github.com/mrnhrd/a544b725b865015ec88c9f1c10cad718 (thanks @UTFAPNRPT)

👀 1
pez22:12:08

That was a bit harder for me than day 1 usually is.

(defn part-1 [input]
  (->> input
       (map (fn [line]
              [(re-find #"(?<=^\D*)\d" line)
               (re-find #"\d(?=\D*$)" line)]))
       (map #(apply str %))
       (map edn/read-string)
       (apply +)))

(def spelled ["one" "two" "three" "four" "five" "six" "seven" "eight" "nine"])
(def spelled->digit (into {}
                          (concat (map (fn [i s]
                                         [s (str i)])
                                       (range 1 10)
                                       spelled)
                                  (map (fn [d] [(str d) (str d)])
                                       (range 1 10)))))
(def pattern (re-pattern (str "(?=(" (string/join "|" (sort (keys spelled->digit))) "))")))

(defn part-2 [input]
  (->> input
       (map (fn [line]
              [(spelled->digit (second (first (re-seq pattern line))))
               (spelled->digit (second (last (re-seq pattern line))))]))
       (map #(apply str %))
       (map edn/read-string)
       (apply +)))

👀 1
dpsutton04:12:46

(defn parse-line
  [f g line]
  (let [digits (f line)]
    (assert (seq digits) (format "no digits found in `%s`" line))
    (parse-long (str (g (first digits)) (g (peek digits))))))

(defn solve-b
  ([]
   (solve-b (slurp "src/day01.txt")))
  ([input]
   (let [g       (merge (zipmap (map str (range 10)) ;; string keys
                                (map str (range 10)))
                        (zipmap ["one" "two" "three" "four"
                                 "five" "six" "seven" "eight" "nine"]
                                (map str (next (range 10)))))
         pat     (re-pattern (str "(?=(" (str/join "|" (keys g)) "))"))
         f       (fn [line] (into [] (map second) (re-seq pat line)))
         extract (partial parse-line f g)]
     (apply + (map extract (str/split-lines input))))))

dpsutton04:12:36

the overlap was a nasty day one addition 🙂

3
Ben Sless06:12:52

Coming late to the party, but I decided to abuse strings and regexes

(defn reverse-charseq
  ^CharSequence [^CharSequence cs]
  (let [len (.length cs)
        n (unchecked-dec-int len)]
    (reify CharSequence
      (length [_] (.length cs))
      (subSequence [_ from to]
        (reverse-charseq
         (.subSequence cs (unchecked-subtract-int len to) (unchecked-subtract-int len from))))
      (charAt [_ i] (.charAt cs (unchecked-subtract-int n i)))
      (toString [this]
        (.toString (StringBuilder. ^CharSequence this))))))
This solves the problem of the overlapping regexes by allowing me to search for the reversed pattern on the string without allocating a new string, terrible idea 😄

norman14:12:03

Oh no - off by one error! I thought AOC started tonight, not last night...

plus_one 1
borkdude14:12:35

It's never too late to start :)

borkdude14:12:59

(unless you have leaderboard ambitions)

norman14:12:16

Well, not for day 1 at least 🙂

elken14:12:33

I was up at 5am by accident and by the time I solved it I still only got 7777 😄 Leaderboard is too timezone favoured for me to care about it

borkdude14:12:56

I'm only in it for the fun and to improve #C03U8L2NXNC this year ;)

elken14:12:23

Yeah I'm only for the fun now 😄 And a good excuse to show off some cool #C035GRLJEP8 viewers

👍 1
borkdude14:12:40

I guess you could also try it out the live in-browser editor feature in clerk ;) https://snapshots.nextjournal.com/clerk/build/ad8e5a2c19aa55921ea357fa9005d563f80c53be/editor/

elken14:12:11

I could, but then I'd have to leave Emacs 😉 I get the same workflow in Emacs with xwidgets

borkdude14:12:37

fair enough :)

nbardiuk15:12:04

My off by one error was in time zone conversion - when I opened AoC the task was available for an hour already

Ingy döt Net15:12:51

This is not AoC but it is very Advent, Code and Clojure... I'm publishing a Programming Advent blog about my new programming language, YAMLScript. I've announced it in other channels as: > YAMLScript is live today! https://yamlscript.org/posts/advent-2023/dec-01/ > I've been working on YAMLScript nonstop since my https://www.youtube.com/watch?v=9OcFh-HaCyI about it when @pez noticed and invited me here. > YAMLScript is billed as a new programming language that can be use for general purpose programming or embedding in YAML data files for dynamic transformation of the content. > In reality YAMLScript compiles/transpiles to Clojure code and is evaluated with SCI. > The ys runtime binary CLI is GraalVM compiled and libyamlscript.so can be bound to almost any programming language. > YAMLScript plans to ship as a dynamic YAML config loading module/binding to dozens of programming languages. > The language is written in Clojure of course. > Please join #C05HQFMTURF if you to discuss it further.

🎉 3
Chase22:12:41

I won't make a habit of sharing all the subreddit stuff but Rockstar is one wild language! https://old.reddit.com/r/adventofcode/comments/1883ibu/2023_day_1_solutions/kbifxzl/

Aziz Aldawood19:12:05

these elves are very incompetent!