adventofcode 2022-12-02

Dear 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

πŸ‘ 2
πŸ‘€ 2

Nice idea, this automatic download of the input. I also applied it to my AoC project.

πŸ‘ 1

FYI I am doing the challenges using scittle

πŸ”₯ 4
2

I'm improving the visuals as I go along and ideas are welcome

Why not use Joyride for Advent of Code this year around? A first version of a Use #joyride for Advent of Code 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

πŸ‘€ 1

Why is map-invert in the set namespace ? πŸ€”

I'll put it in let-go's core I think

Also, fun fact: (set/map-invert who-beats-who) = (comp who-beats-who who-beats-who)

πŸ‘€ 2

@alexalemi good one! didn't occur to me

it's basically shifting the table

@qmstuart because maps can be regarded as sets of key-value pairs? it beats me :)

All these beautiful, explicit solutions and I'm just playing code golf πŸ˜…

please share πŸ™‚

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

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

πŸ‘ 2

(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)}))

πŸ‘ 1

@piotr.kaznowski 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)])

Of course! Thanks for the hint, @pshapiro.

modest improvements to the UI

πŸš€ 1
1
πŸŽ‰ 3
🀘 1

Hey 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/

❀️ 7

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

Thanks - wish I had time to make more.

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

πŸ‘ 1
πŸ‘πŸΌ 1

The rust version as an appendix would be cool! 🀠 but I just thinking about AoC and Joyride on my walk so looking forward either way!

man, I like it when I paste a giant fn from clojure.core and it just works

I'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).

You 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

Thanks. 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 πŸ™‚

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

Yeah, in this particular case, it was two instances where I'd renamed a binding but forgotten to update the references to it.

Perhaps the better solution is something that assists in refactorings like this (although that might be overkill for something like an AOC puzzle).

Day 2 - looks like we need a solutions thread

(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 +)))

πŸ‘ 3

https://github.com/ValentinMouret/advent-2022/blob/main/src/day_02.clj's longer, but might be more readable. Feedback is welcome. πŸ™‚

I 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

πŸ‘ 3

(ns aoc2022.day-2
  (:require [aoc2022.misc :as misc]))

(defmulti score identity)

(defmacro score-methods [points]
  `(do
     ~@(for [they ["A" "B" "C"]
             I ["X" "Y" "Z"]]
         `(defmethod score ~(format "%s %s" they I) [_#]
            ~(+ (get-in points [I I])
                (get-in points [I they]))))))

(defn solve-1 []
  (score-methods {"X" {"X" 1
                       "A" 3
                       "B" 0
                       "C" 6}
                  "Y" {"Y" 2
                       "A" 6
                       "B" 3
                       "C" 0}
                  "Z" {"Z" 3
                       "A" 0
                       "B" 6
                       "C" 3}})
  (binding [misc/*day* 2]
    (misc/read-lines
     (fn [rounds]
       (transduce
        (map score)
        + 0
        rounds)))))

(defn solve-2 []
  (score-methods {"X" {"X" 0
                       "A" 3
                       "B" 1
                       "C" 2}
                  "Y" {"Y" 3
                       "A" 1
                       "B" 2
                       "C" 3}
                  "Z" {"Z" 6
                       "A" 2
                       "B" 3
                       "C" 1}})
  (binding [misc/*day* 2]
    (misc/read-lines
     (fn [rounds]
       (transduce
        (map score)
        + 0
        rounds)))))

(time
 (dotimes [_ 1000]
   (solve-1)))
;; 334ms

(time
 (dotimes [_ 1000]
   (solve-2)))
;; 291ms
with dynamic multimethods and macro πŸ™‚

Mine 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%)

Dictionary 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

πŸ‘ 1

I parsed the file into "rock" "paper" "scissors" because "A", "B", "C", "X", "Y", "Z" was confusing me.

Isn't this a link to a private repository?

it's 404 for us

yeah, shit was private. I had no idea. SHould be public now πŸ™‚

πŸ‘ 2

https://github.com/v-garcia/aoc_2022/blob/main/day2.clj with rock paper scissors encoded as 0 1 2

πŸ‘€ 1

https://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 +))))

I did an alternative approach for day 2 using core.logic, which was pretty fun: https://github.com/formsandlines/aoc2022-clojure/blob/main/src/advent_of_clerk/day_02_logic.cljc Unfortunately, Babashka doesn’t seem to work with core.logic, so I couldn’t get my tests to run with it.

πŸ‘ 2

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

A bit late to the game : / day job intervened, let's see if I can catch up

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

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