adventofcode 2024-12-01

(def all (slurp "input.txt"))
(def small (slurp "small.txt"))

(let [data (-> all
               (split-lines)
               (->>
                (map #(split % #"   "))))
       col-a (sort (mapv #(Integer/parseInt %) (map first data)))
       col-b (sort (mapv #(Integer/parseInt % ) (mapv second data)))
       diff (map #(abs (- %1 %2)) col-a col-b )
       total (reduce + diff)      
      ]
   total)

I like all and small @thomas ha, nice

๐Ÿ™ 1

Could have compressed even more, but no need. Awesome that we have a frequencies method. Part 1

(defn row-prep [rowstr]
  (let [x (s/split rowstr #"[ ]+")
        y (map #(Integer/parseInt %) x)]

    ;; Just return Y.
    y))

(def c (map row-prep (s/split-lines in)))
(def left (sort (map first c)))
(def right (sort (map last c)))
(reduce + (map #(abs (- %1 %2)) left right))
Part 2
(def right-freqs (frequencies right))
(reduce + (map #(* % (get right-freqs % 0)) left))

always seems like the parsing is the tough bit!

(defn parse-input [source]
  (let [lines (str/split-lines source)]
    (reduce (fn [[left right] line]
              (let [[x y] (map parse-long
                               (str/split line #"\s+"))]
                [(conj left x) (conj right y)]))
            [[] []]
            lines)))

(def day-1-input
  (-> "resources/aoc2024/day1.txt"
      slurp
      parse-input))

(defn total-distance [[list1 list2]]
  (reduce + 0 (map difference (sort list1) (sort list2))))

(defn task1 []
  (total-distance day-1-input))

(defn similarity-score [[list1 list2]]
  (let [l2-frequencies (frequencies list2)]
    (transduce (map #(* % (get l2-frequencies % 0))) + 0 list1)))

(defn task2 []
  (similarity-score day-1-input))

Refactored the overall AOC/YS repo layout. ReadMe has section to show code as Clojure. https://github.com/ingydotnet/advent-of-code/blob/main/ReadMe.md

I'm committing to not obsessively staying up every night this year to finish them when they drop, but at least for the easy days I will... ๐Ÿ™‚ https://gitlab.com/maximoburrito/advent2024/-/blob/main/src/day01/main.clj?ref_type=heads

2

Good to see a thread! Btw, Is it okay to post code to a public repo?

;; ## Day 1
(def pairs
  (-> ( 1)
   (
    #"\n"
    #"\s+"
    parse-long)))

;; ### Part 1
(let [left-list  (sort (map first pairs))
      right-list (sort (map second pairs))
      distance   (fn [a b] (abs (- a b)))]
  (reduce + (map distance left-list right-list)))

;; ### Part 2
(let [left             (map first pairs)
      right            (map second pairs)
      similarity       (frequencies right)
      similarity-score (fn [x] (* x (similarity x 0)))]
  (reduce + (map similarity-score left)))

@abyala Iโ€™ve been trying to wrap by head around juxt and this line really helps: > Whenever we take one thing and return a vector of things from different functions, we call on juxt Thanks for sharing ๐Ÿ˜

๐Ÿ‘ 1

As usual, day 1 is a breeze : https://github.com/Maravedis/advent_code/blob/master/src/advent_of_code/2024/01.clj . I wish those dropped at a friendlier time in Europe ๐Ÿ˜ž

@kjw0323 Public repo is ok for your own solution, but they ask you do not commit any input or puzzle text. Source : https://adventofcode.com/2024/about > Can I copy/redistribute part of Advent of Code? Please don't. Advent of Code is free to use, not free to copy. If you're posting a code repository somewhere, please don't include parts of Advent of Code like the puzzle text or your inputs. If you're making a website, please don't make it look like Advent of Code or name it something similar.

โค๏ธ 1

(def real-input (slurp "src/2024/day01"))

(defn parse-input [input]
  (->> (str "[" input "]")
       edn/read-string
       (partition 2)))

; 1
(let [input-data (parse-input real-input)
      first-list (sort (map first input-data))
      second-list (sort (map second input-data))
      distances (map (fn [a b] (abs (- b a))) first-list second-list)]
  (reduce + distances))

; 2
(let [input-data (parse-input real-input)
      first-list (map first input-data)
      second-list (map second input-data)
      _ (prn (frequencies second-list)) ;; didn't think about that one
      diff-scores (map (fn [a]
                         (* a (count (filter #{a} second-list))))
                       first-list)]
  (reduce + diff-scores))

1

The edn/read-string with the [] concat is really funny to me for some reason.

Love read-string for this ๐Ÿ™‚ Saw it first from Bruce Hauman in last yearโ€™s (correction: was 2022) advent of code threads: https://clojurians.slack.com/archives/C0GLTDB2T/p1670259468872829

(defn total-distance-between-lists
  "Given two sorted lists, return the sum of the absolute difference between each pair of numbers"
  [list-1 list-2]
  (reduce + (map #(Math/abs (- %1 %2)) list-1 list-2)))

(defn similarity-score
  "Given a frequency map and a number, return the similarity score"
  [frequency-map number]
  (* number (frequency-map number 0)))

(defn total-similarity-score
  "Given a sequence of numbers and a frequency map, return the total similarity score"
  [numbers frequency-map]
  (reduce (fn [total number]
            (+ total (similarity-score frequency-map number)))
          0
          numbers))

(defn- pairs->vectors
  "Given a sequence of pairs, return a pair of
  vectors containing the first and second elements of each pair"
  [pairs]
  (reduce (fn [[list-1 list-2] [a b]]
            [(conj list-1 a) (conj list-2 b)])
          [[] []]
          pairs))

(defn part-1
  [input]
  (let [pairs (utils/parse-long-pairs input)
        [list-1 list-2] (pairs->vectors pairs)
        sorted-list-1 (sort list-1)
        sorted-list-2 (sort list-2)]
    (total-distance-between-lists sorted-list-1 sorted-list-2)))

(defn part-2
  [input]
  (let [pairs (utils/parse-long-pairs input)
        [list-1 list-2] (pairs->vectors pairs)
        frequency-map (frequencies list-2)]
    (total-similarity-score list-1 frequency-map)))

(ns aoc2024.aoc01)

(def input (->> (slurp "/Users//aoc/aoc24/aoc1.txt")
                (re-seq #"\d+")
                (map parse-long)
                (partition 2)
                (apply map vector)))

(defn p1 [[l1 l2]]
  (reduce + (mapv (comp abs -) (sort l1) (sort l2))))

(defn p2 [[l1 l2]]
  (let [s (frequencies l2)]
    (transduce (map #(abs (* % (s % 0)))) + l1)))

๐Ÿ‘ 2

That's the second use of transduce I've seen. I really need to look into how that works.

โž• 1

Itโ€™s map + reduce (in this case)

Generally transduce is used when you have a reduce operation, but first you map/filter etc the input sequence. Granted you can just do that inside the reducing function in reduce but itโ€™s generally cleaner to use transduce . Also using transducers can be much faster.

โค๏ธ 2

Okay, I will play around with using that for my solution.

Thanks for the explanation!

@roklenarcic you define input and then two functions, but how do you connect the two?

I'm trying to port your solution to the squint playground... I guess just call p1 and p2 on input?

yes, just (p1 input)

usually I have input and test-input etcโ€ฆ so most of the time I have p1 and p2 functions that take an input so I can test with various inputs

Using read-string trick I can make it shorter: https://gist.github.com/RokLenarcic/18a9a9cd134ca7f53c8897396208149e

๐Ÿ’ก 1

@roklenarcic read-string isn't available in squint (yet) :)

Today was a fun Day1 puzzle, I enjoyed it. [Here](https://github.com/alexalemi/advent/blob/main/2024/clojure/p01.clj) is my clojure solution. I would have liked to make the whole thing a transduce but I couldn't figure out how to turn (apply map list) into a transducer immediately.

โค๏ธ 1
1

https://clojurians.slack.com/archives/C0GLTDB2T/p1733037898227799?thread_ts=1733029934.345259&cid=C0GLTDB2T Oops, I thought publishing my specific puzzle inputs was fine, as they're generated. Maybe it used to be fine, but they changed the policy? In any case, off to tweak my repo... ๐Ÿ˜…

I realized after that my use of zipmap was probably the wrong choice as it wouldnt have worked if there were repeating items in the lhs, but I got lucky. In any case, I didnt place on the leaderboard. This was my first AOC and it was fun

I tend to take advantage of day 1 being easy to explore a different language. just finished a Haskell book, so decided to put it to practice. https://github.com/FelipeCortez/advent-of-code/blob/master/2024/01.hs will switch to Clojure tomorrow!

๐Ÿ˜Ž 1

I corrected my improper use of zipmap and simplfied

(ns aoc.2024.day1
  (:require [clojure.string :as string]))

(defn parse []
  (->> (slurp "inputs/day1.txt")
       (string/split-lines)
       (map #(map parse-long (string/split % #"\s+")))
       (reduce (fn [acc items] (mapv conj acc items)) [[] []])
       (map sort)))

(defn part1 []
  (let [[left right] (parse)]
    (->> (map (comp abs -) left right)
         (reduce + 0))))

(defn part2 []
  (let [[left right] (parse)
        f (frequencies right)]
    (->> (map #(* % (get f % 0)) left)
         (reduce + 0))))

๐Ÿ‘€ 1

@dingelsz3 - I'm glad you found it helpful!

I have a feeling that the last time I used frequencies was in AOC23 :-)

(def input [...])

(def lists
  [(take-nth 2 input)
   (take-nth 2 (rest input))])

(defn part1 []
  (let [l1 (sort (first lists))
        l2 (sort (second lists))]
    (reduce + (map #(abs (- %1 %2)) l1 l2))))

(defn part2 []
  (let [l1 (first lists)
        l2f (frequencies (second lists))]
    (reduce #(+ %1 (* (get l2f %2 0) %2)) 0 l1)))

๐Ÿ‘ 1

take-nth I just learned about this

People say Clojure isn't a language where you have one obvious way to do something, but looking at all the solutions they're all almost identical. Great minds think alike ๐Ÿ˜… Here's mine https://codeberg.org/aciep/advent-of-code-2024-clojure/src/branch/master/src/aoc/d1.clj

(require '[ :as io]
         '[net.cgrand.xforms :as x])

(def xf (comp (mapcat (fn [ln] (re-seq #"\d+" ln)))
              (map parse-long)
              (x/multiplex {:xs (take-nth 2) :ys (comp (drop 1) (take-nth 2))})
              (x/by-key (comp (x/sort) (x/into [])))))

(let [{:keys [xs ys]} (into {} xf (io/lines-in *in*))]
  (println "Part A:" (reduce + (map (comp abs -) xs ys)))
  (println "Part B:" (let [frqs (frequencies ys)]
                       (transduce (map (fn [x] (* (get frqs x 0) x))) + xs))))
Trying to wrap my head around cgrand's xforms library a little, I'm sure theres more room for improvement here

๐Ÿ’ก 1

Oh! And not that I'll be playing for it this year, but is there a Clojure-specifichttps://adventofcode.com/2024/leaderboard/private? EDIT: Found it! Same as last year(s): https://adventofcode.com/2024/leaderboard/private/view/217019

๐Ÿ‘€ 1

We could maybe make a new one? Lots of people are obviously not participating.

Good idea! Let's make 2024 edition

๐Ÿ‘ 2

(preparing one, stay tuned)

current status: failed... I've created new github account for that purposes but: You are marked as spam, and therefore cannot authorize a third party application...

๐Ÿ˜ข 1

no worries - alternative solution works

Ok! Here is the new code for this year: 4534281-b9354839

what is the channel name?

Is the code something that can be shared?

what is the join code?

In the topic of the channel 217019-4a55b8eb

3
๐Ÿ™ 1

it says that private leaderboard is full. ๐Ÿ˜ข

I got a "that private leaderboard is full" as well....bummer!

set the channel topic: Happy Advent 2024! 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

๐Ÿ™ 1

We are not allowed to share the puzzle input on github (or other public site or repo) but since it's convenient to keep an archive of them I want to share my solution: keep it in the encrypted kv store file. I use H2 for that, feeding new input and examples every day (which I use in tests, and which are also under restriction).

๐Ÿ˜„ 1

And the following to update the store from data/inputs and data/examples folders

(do
    (add-all-data)
    (add-all-data "examples"))

Could you review my solution of day1? Is there room for improvements? https://github.com/reflechant/aoc2024-clj/tree/main/src/reflechant/aoc2024/day01

Part 1 looks ok for me. One comment for part 2: you can get rid of map -> filter -> map chain by setting a default value in get

๐Ÿ‘ 1

Thanks! Missed that ๐Ÿ™‚

Also (get freq % _default_) can be called as (freq % _default_)

๐Ÿ‘ 1

yeah, maps are functions of their keys. I tried to do it but my lsp was complaining for some reason

A very useful tool when parsing numbers, or anything that just repeats, is re-seq , instead of having to split:

(re-seq #"\d+" input) ; => ["1" "2" "3" "14" "12"])
The advantage is that it also parses things like
Rudolf flies at 14km/h, for 10 seconds, before having to rest for 133 seconds.
and gives you back only the numbers.

๐Ÿ˜ฎ 2
โ˜๏ธ 1

Oh, that's neat. Thanks!

Does anyone understand the ranking in the private leaderboard? For instance, the #1 slot has โ€œ398โ€ but I understand you can only get a maximum of 200 points per puzzle. Does the global leaderboard rank differently?

On a private leaderboard page, you can click [Ordering] to have this snippet appear:

Global and private rank differently.

The global leader on Day 1 finished Part 1 in 4 seconds and part 2 5 seconds later for a 9 second total. Wild stuff

It's someone who used an LLM. They actually apologized and deleted the link toward their repo. They were unaware it was discouraged to use AI as a solver and not just a crutch.

๐Ÿ’ฏ 2

How do you see the stats of other leaderboard rows? I can see mine but not others

i.e. how did you see that #1 took 4 seconds @chase-lambert?

If you go to the global leaderboard there are links to the individual days at the top

and thats crazy

slowest person was 1:24

I've never done it for time but I check out the times out of curiosity every now and then

i think i finished #1 in 14m, heh. Not even close