This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-12-05
Channels
- # adventofcode (138)
- # announcements (1)
- # babashka (4)
- # beginners (71)
- # biff (2)
- # calva (7)
- # cider (20)
- # clj-kondo (4)
- # cljsrn (4)
- # clojure (36)
- # clojure-europe (37)
- # clojure-nl (2)
- # clojure-norway (27)
- # clojure-portugal (1)
- # clojure-uk (4)
- # clojurescript (8)
- # emacs (3)
- # graphql (1)
- # hugsql (4)
- # humbleui (6)
- # hyperfiddle (1)
- # jobs-discuss (18)
- # joyride (2)
- # malli (17)
- # meander (7)
- # membrane (8)
- # off-topic (16)
- # pathom (14)
- # portal (4)
- # rdf (36)
- # reitit (4)
- # releases (2)
- # remote-jobs (1)
- # scittle (15)
- # shadow-cljs (13)
- # tools-deps (40)
;; 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"
(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")
Let'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
https://github.com/wevre/advent-of-code/blob/master/src/advent_of_code/2022/day_05_cranes.clj
https://github.com/genmeblog/advent-of-code/blob/master/src/advent_of_code_2022/day05.clj
https://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.
https://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@U076FM90B isn’t (update from #(drop move %))
the same as (update from drop move)
?
@U2PGHFU5U the latter will do (update from #(drop % move))
ah thanks you’re right 🙂
yes, unfortunately update
, like thread first
macro, is optimized for single value, not a collection
https://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 ;)https://github.com/benjamin-asdf/advent-of-code/blob/master/src/Y2022/day5.clj barely got my stars
I 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.
I could/should consider rewriting my parsing code. I won't. https://coyotesqrl.github.io/advent-of-code/2022/src/coyotesqrl/2022/day05.html
I am not proud of this code 😅 make it work, make it good, make it fast, right? well, this works...
That'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. 😆
Here'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 🙂
Took 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)))
Not 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
little 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. :))(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))))))
Really 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"
)
struggled with parsing the original structure, but after that it was simple
Parsing the input became so involved: https://github.com/pwojnowski/advent-of-code/blob/master/src/aoc/aoc2022.clj#L102
Mine 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'))))))]))
I wonder how the people (sic!) from the top of the leaderboard got that parsed that fast, but probably something really straigthforward...
Thats's why I wrote "people" 😉
With gpt3 the advent became so depressing... 😭
This is sad, but it appears so.
Finally 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
(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))))
@U4VDXB2TU That's so pretty! Learned a lot reading that.
@U04BA34MCDN thank you! Yes I’ve learnt a lot from other’s solutions here as well (@UP82LQR9N looking at you among others)
(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))
I 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.
I 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?
It's awesome but you gotta get this up on github pages or else it doesn't count @raymcdermott
I 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
Then 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 %))))
That 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)))
read-string
is such a dangerous function, that I don't let my brain even consider it 🙂
AND just quell the controversy I’m going to use clojure.end/read-string even when I’m hacking. 🥲
Pity. I was waiting for when the file input would be massaged to be code so that read-string proper would spit out the answer.
Although thinking about it I could have used some code to accomplish the same thing as the emacs rectangle macros.
I 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 :dyeah, 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)]
And 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)))
hey, 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 🧵
(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)))
I don’t have time to debug this but I suggest getting rid of the atom and trying it on the sample input first
Oh, 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
Oh good point @U076FM90B! I accounted for this earlier and then changed my code and forgot to update that part 😅
I 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).
That's a good tip, thanks @U05476190! I didn't even know about reductions
until now.
Another potential gotcha with the crates: the input lines are not all equal length, so the transpose might cut off some rows/columns.
Yeah, 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.
@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)
@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
I'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 " )))"))))
I 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).
hey @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
I'm having a blast 🙂 lg is still extremely barebones but it's surprisingly workable for what it is at the moment
I have the same state with #C03QZH5PG6M and #C03U8L2NXNC: it's doable but some things are obviously missing
it 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
however, the API for this is not entirely fleshed out, I'm still experimenting on how to make it super comfy
here'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
Since 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.Similar 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))))
I 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&cid=C0GLTDB2T
what's transpose
@UK00KCK6D?
Here 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)})
I 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))))
This 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.
You can pad your short stacks first. That should get you over that hump.
Ah, 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.
Yeah. In code. You’d need to update that sample code between the first line of the threading macro and the reduce fn.
I 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
Anybody 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).
Ultimately 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 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:).
@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
This editor does support the barfing/slurping stuff: https://nextjournal.github.io/clojure-mode
Thank 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. 🙂
The 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
'Unavailable' as in: you simply can't enter those key chords in a standard mobile browser keyboard, surely?
🙂 Well, I would love for someone or some team to do it better.