adventofcode

Happy Advent 2020! Please put answers in the pinned threads or create one if it does not exist yet. | https://github.com/adventofcode-clojurians/adventofcode-clojurians | Join the private leaderboard with code 217019-4a55b8eb
kenj 2020-12-02T00:05:13.046500Z

Did 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))

Mario C. 2020-12-02T16:51:16.078600Z

Hey are you going to be doing a video series this year for AoC? @potetm

2020-12-02T18:19:24.088600Z

ugh I made the mistake of trying it in rust this year

2020-12-02T18:19:37.088800Z

no one wants to see that ๐Ÿ˜„

Mario C. 2020-12-02T19:55:55.094700Z

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

kenj 2020-12-02T00:05:35.047Z

it also returns the whole set if a pair isnโ€™t found which is a terrible result in the negative find case

kenj 2020-12-02T00:09:21.047400Z

ah looks like skykanin did something similar above in a cleaner fashion

2020-12-02T00:18:28.048Z

Today 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

7๐Ÿ‘
erwinrooijakkers 2020-12-02T09:38:38.055800Z

Nice ๐Ÿ™‚

2020-12-02T02:00:53.048200Z

reduced is totally fine and normal. You use it in exactly this sort of situation: You want to short-circuit evaluation because youโ€™re done.

2๐Ÿ‘
mchampine 2020-12-02T06:13:23.051600Z

Day 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))]))))

pez 2020-12-02T09:47:05.059700Z

That is beautiful!

pez 2020-12-02T09:53:27.060600Z

Mine:

(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 ๐Ÿ˜ƒ )

1๐Ÿ‘
pez 2020-12-02T09:54:18.060800Z

Neither did you, I now realize. Haha.

nbardiuk 2020-12-02T07:38:51.054200Z

I am curious what did you you use to parse data for Day 2. Have you used regexp or some nice parser combinator library?

mchampine 2020-12-02T15:42:09.076700Z

A small regex. I simply split each line with #(str/split % #โ€œ[- :]โ€œ) and then converted the strings to numbers and chars as appropriate.

1๐Ÿ‘
pez 2020-12-03T06:01:07.110700Z

I also used a regex, but with groups. I should have splitted instead, had I thought about it. ๐Ÿ˜€

plexus 2020-12-02T08:00:09.054800Z

My solution for day 2 https://youtu.be/rghUu4z5MdM

3๐Ÿ‘
nbardiuk 2020-12-02T08:28:21.055Z

always forget about slurp and barf, I like how some edits are more fluent with them

1โž•
erwinrooijakkers 2020-12-02T09:38:38.055800Z

Nice ๐Ÿ™‚

pez 2020-12-02T09:45:53.059300Z

Has 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.

erwinrooijakkers 2020-12-02T09:46:55.059600Z

There is some Python program somewhere

pez 2020-12-02T09:47:05.059700Z

That is beautiful!

erwinrooijakkers 2020-12-02T09:47:13.060Z

https://github.com/wimglenn/advent-of-code-data

1โค๏ธ
erwinrooijakkers 2020-12-02T09:47:45.060500Z

aocd > input.txt  # saves today's data
aocd 13 2018 > day13.txt  # save some other day's data

pez 2020-12-02T09:53:27.060600Z

Mine:

(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 ๐Ÿ˜ƒ )

1๐Ÿ‘
pez 2020-12-02T09:54:18.060800Z

Neither did you, I now realize. Haha.

pez 2020-12-02T09:55:50.062100Z

If I end up rolling this, Iโ€™ll have use for that to see what is involved.

zackteo 2020-12-02T09:57:02.063200Z

Was attempting to do so yesterday, then I realised authentication is required

plexus 2020-12-02T10:00:16.064700Z

lazy 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

erwinrooijakkers 2020-12-02T10:00:50.065200Z

In the Python aocd tool you can add the value of the session cookie in the AOC_SESSION env var or ~/.config/aocd/token file

uneman 2020-12-02T10:08:37.068800Z

Wow 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.

1๐Ÿ‘
erwinrooijakkers 2020-12-07T15:26:34.364900Z

@namenu lol your ReasonML is gone? In favour of https://github.com/namenu/advent-of-code/tree/master/src? ๐Ÿ˜„

erwinrooijakkers 2020-12-07T15:27:26.365300Z

aah I see itโ€™s still Reason ๐Ÿ™‚

erwinrooijakkers 2020-12-07T15:27:32.365500Z

nice

erwinrooijakkers 2020-12-07T15:27:49.365700Z

looks pretty clean

uneman 2020-12-08T01:00:25.377400Z

oh yes I merged the ReasonML repo with Clojure's to contrast them

uneman 2020-12-08T01:00:37.377600Z

I 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!

uneman 2020-12-08T01:01:20.377800Z

I use ReasonML and Clojure both for living, and they are both great in very different ways

erwinrooijakkers 2020-12-02T10:09:00.069100Z

Maybe a program can login via the GitHub SSH key so that you donโ€™t need the session

1โค๏ธ
erwinrooijakkers 2020-12-02T10:09:08.069300Z

If you use GitHub to login

erwinrooijakkers 2020-12-02T10:09:53.069500Z

Not sure if thatโ€™s possible

erwinrooijakkers 2020-12-02T10:14:50.069800Z

I remember a talk from Clojure Vienna 2016 on ReasonMLโ€™s Unikernels and also transforming Clojure to ReasonML: https://youtu.be/tB705w4w6H0

1
uneman 2020-12-02T10:16:13.070300Z

Wow thats... cursed

erwinrooijakkers 2020-12-02T10:16:26.070600Z

haha

erwinrooijakkers 2020-12-02T10:18:01.071200Z

Was pretty interesting stuff. Booting up a unikernel faster than the time it takes to do a TCP handshake

erwinrooijakkers 2020-12-02T10:18:16.071400Z

Not sure what the status is of it now

plexus 2020-12-02T11:49:12.072Z

@pez https://github.com/lambdaisland/aoc_2020/blob/main/bin/fetch_input

2โค๏ธ
plexus 2020-12-02T11:49:49.072700Z

just need to find the session id with devtools and put a export AOC_SESSION=... in your shell profile

2020-12-02T11:58:44.074Z

And 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

erwinrooijakkers 2020-12-02T12:40:26.074400Z

@mroerni 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)? @juniusfree 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-02T14:04:50.075800Z

My 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-02T14:06:31.076100Z

I like your solution for part2!

erwinrooijakkers 2020-12-02T14:38:56.076300Z

๐Ÿ™‚ i did same as yours initially but then realized clojure had no xor

rmprescott 2020-12-02T15:33:10.076500Z

Curious: why use set membership rather than `(= 2020 ...)

mchampine 2020-12-02T15:42:09.076700Z

A small regex. I simply split each line with #(str/split % #โ€œ[- :]โ€œ) and then converted the strings to numbers and chars as appropriate.

1๐Ÿ‘
Mario C. 2020-12-02T16:51:16.078600Z

Hey are you going to be doing a video series this year for AoC? @potetm

pez 2020-12-02T17:13:39.085700Z

Decided 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 "<https://adventofcode.com/2020/day/>" 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))
  (-&gt;&gt; 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. ๐Ÿ˜ƒ

pez 2020-12-02T17:20:35.085900Z

Neat! Found this a bit late, but I did exactly that. ๐Ÿ˜ƒ

2020-12-02T17:34:28.086200Z

Last year the session never changed.

Ben List 2020-12-02T17:40:42.087100Z

nothing fancy but my day 02 solution https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/02.clj

nbardiuk 2020-12-02T17:41:39.087300Z

I've just checked that cookie expiration is set for 10 years ๐Ÿ˜

pez 2020-12-02T17:49:42.087500Z

Even I should be able to solve the puzzles in that time!

spfeiffer 2020-12-02T17:56:38.087700Z

I am stuck in 2016 somewhere, not sure 10 years will cut it for me ๐Ÿ˜‰

kenj 2020-12-02T18:19:17.088500Z

my also not fancy day 2โ€ฆ I like how declarative it came out looking https://gist.github.com/KennyMonster/eb6ea22eaba1a1a1201820ef1bddc1cf

2๐Ÿ‘
2020-12-02T18:19:24.088600Z

ugh I made the mistake of trying it in rust this year

2020-12-02T18:19:37.088800Z

no one wants to see that ๐Ÿ˜„

pez 2020-12-02T18:28:30.089800Z

I put my input-slurper into a gist: https://gist.github.com/PEZ/bcd23b9bc099b8b21a41c8c9de78a0f4

1โค๏ธ
2020-12-02T19:47:27.093100Z

hi 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

Mario C. 2020-12-02T19:55:55.094700Z

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-02T20:08:12.095300Z

this 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 &lt;nil&gt; as a Reader. however, doing the exact same thing in lein repl works fine

juniusfree 2020-12-02T20:13:14.095500Z

@erwinrooijakkers Correct. There are a lot of built-in functions in Clojure that I still have to explore!

nbardiuk 2020-12-02T20:31:58.095700Z

I 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

nbardiuk 2020-12-02T20:32:37.095900Z

https://github.com/kumarshantanu/lein-exec

-p  indicates the script should be evaluated in project (with classpath)

2020-12-02T20:44:41.096700Z

thank you! that was it

kpav 2020-12-02T20:46:14.096900Z

ha, funny seeing you here @jeffrey.wayne.evans

1๐Ÿ˜€
2020-12-02T20:46:40.097200Z

trying to get my day1 and day2 solutions finished and pushed

kpav 2020-12-02T20:46:44.097400Z

I am learning clojure too, trying to do AOC with it

2020-12-02T20:46:58.097600Z

sweet! letโ€™s keep each other accountable

1๐Ÿ™Œ
kpav 2020-12-02T20:49:46.097900Z

Ive got my solutions here, finished day 1 and 2! https://github.com/kwpav/advent-of-code-2020

2020-12-02T22:09:14.098200Z

nice! Iโ€™m a bit behind, only got day 1 done so far: https://github.com/jeff303/advent-of-code-2020

2020-12-02T22:09:21.098500Z

gonna try to finish day 2 before I look at yours

kpav 2020-12-02T22:34:36.098700Z

day 2 was fun

2020-12-02T22:56:04.098900Z

yeah, almost seems easier, especially with Clojure. though Iโ€™m sure part 2 will throw some kind of wrench into it