Fork me on GitHub
#adventofcode
<
2020-12-06
>
Vincent Cantin05:12:56

Good morning !

😁 12
fingertoe05:12:23

Hello! Today’s problem was pretty straightforward.. I am tied with the amount of problems I finished last year.. Not close to burning out.. I wonder if it is going easy on us this year?

Vincent Cantin05:12:26

I am awaiting the difficult problems like a surfer awaiting its wave.

alekszelark05:12:20

You can pick one from the last year ^_^

👍 3
💯 3
Vincent Cantin06:12:36

I will keep them for January.

mchampine05:12:36

Agree! #6 usually starts ramping way up.

kenj05:12:25

why give us a difficult problem on the weekend when you can save it for a weekday…

😆 6
Vincent Cantin06:12:17

During the first 1 min 30, I was staring at a blank page, waiting for the page to load.

plexus06:12:10

AoC really starts the first time you add

(set! *unchecked-math* :warn-on-boxed)
(set! *warn-on-reflection* true)
to a namespace

😏 9
👟 3
3
Vincent Cantin06:12:33

I like @dos’s solution, which did not separate the input loading from the processing for the solution. It might be faster to type in that way.

james06:12:21

This is the first year I'm (seriously) trying to do this. Does it usually get harder day by day?

james06:12:36

(Today's puzzle was pretty easy, but if they're going to get difficult I might not have time to see it through.)

markw06:12:57

Problems have been surprisingly simple so far this year

markw06:12:13

Last year for me, was by far the most difficult of them all

alekszelark06:12:10

That’s probably because we’re going to vacation 😃

😄 3
markw06:12:36

that or he’s lulling us into complacency just before dropping the hammer tomorrow

markw06:12:57

oh you got work Monday morning? Hope you remember A* search

😁 12
plexus06:12:40

I skipped AoC last year because the year before I ended up spending sometimes multiple hours on a single solution. If it gets like that again I'm out, but a bit more challenging than today's would be nice too 🙂

markw06:12:09

I’ve done them since 2015, finished most but not all of them.. Except last year i bailed very early

plexus06:12:34

Today's video: https://www.youtube.com/watch?v=b0a5siw85N4&amp;feature=youtu.be I also talk a bit about the different ways that people solved yesterday's puzzle

👍 6
plexus06:12:34

Many thanks to folks who dropped into the live chats or left comments!

Vincent Cantin07:12:42

Let me know if I leave too many comments during the streaming 😅 I have a hard time holding them while excited by the contest.

plexus07:12:58

All good, it's nice to see some activity :)

markw06:12:37

they definitely get difficult and I was spending hours on problems routinely, but i’m not a fast solver

markw06:12:34

last year by like day 14 you had implemented a VM for a made up language, and then implemented pong using that language

james06:12:39

I'm not a fast solver either, and also I'm doing them in Clojure, which I don't really know, so I'm extra slow.

markw06:12:11

i know the feeling… i’m trying to go back and do them in Go after I finish in Clojure, and it is … painful (i don’t know Go)

markw06:12:21

lots of typing

devn10:12:05

Day 6 Answers Thread - Post your answers here

devn10:12:57

(ns day6
  (:require [clojure.string :as str]
            [clojure.set :as set]))

(def input "...")

(def groups (str/split input #"\n\n"))

;; Part I
(apply + (for [group groups] (count (distinct (str/replace group #"\n" "")))))

;; Part II
(apply + (for [group groups
               :let [people (str/split-lines group)
                     answer-sets (map set people)]]
           (count (apply set/intersection answer-sets))))

tws10:12:28

(ns aoc.2020.d06
  (:require [aoc.file-util :as file-util]
            [clojure.set :refer [intersection]]
            [clojure.string :as str]))

(def input (map str/split-lines (file-util/read-chunks "2020/d06.txt")))

(defn part-1 [input]
  (reduce + (map (comp count distinct (partial apply str)) input)))

(defn part-2 [input]
  (reduce + (map (comp count (partial apply intersection) (partial map set)) input)))

tws10:12:45

first pass, feels inelegant

devn10:12:02

i feel the same way, but 🤷

devn11:12:43

im guessing there’s a frequencies-based solution

benoit12:12:58

I misread part1 and actually solve part2 first 🙂 https://github.com/benfle/advent-of-code-2020/blob/main/day6.clj

st3fan16:12:29

@U1G869VNV nice ... (str/split input #"*\n\n*") that did not occur to me, I do a (partition-by empty?) 🙂

metal 3
💯 3
Narve Saetre20:12:19

Noob code coming up - but I am actually quite happy with this code, it reads nicely I think:

(defn count-group [group]
  (->> group
       (string/split-lines)
       (map set)
       (apply clojure.set/intersection)
       (count)))

(->> (string/split (slurp "adv6.input.txt") #"\n\n")
     (map count-group)
     (reduce +))

Narve Saetre20:12:55

I love the -> and ->> macros, but sometimes they can't be used because the place to put the previous form is different ... any tips for that particular problem? Is there a -?> which "does the right thing depending on the form 😄

Narve Saetre20:12:46

Answering my self: I just searched and found as->, a very nice function. This allows me to write e.g.

(as-> "adv6.input.txt" v
      (slurp v)
      (string/split v #"\n\n")
      (map count-group v)
      (reduce + v))

tws22:12:05

@USAGL3YUS YMMV, but I try not to use as->, I find it has maintenance problems for me. I like to just pull out the different one as a let, so there’s only 1 threading type. In this case, could do:

(let [groups (-> path slurp (str/split #"\n\n")]
  (->> groups...))

Narve Saetre06:12:08

yeah, I c your point. I can also use minor (-> or (->> lines within the larger thread-block as well. Just gotta pick the right tool for the job 🙂

st3fan16:12:41

Day 7 Answers Thread - Post your answers here

Vincent Cantin06:12:32

I need to improve my regex capture skills. Let me know if you have a fast way to do the parsing/capturing, I am interested to learn.

alekszelark06:12:56

not ideal, but I came up with this for parsing

(defn parse-entry [entry]
  (let [p  (re-find #"\w+ \w+" entry)
        cs (->> (re-seq #"(\d+) (\w+ \w+)" entry)
                (reduce (fn [m [_ v k]] (assoc m k (Long/parseLong v))) {}))]
    [p cs]))

(def bags (into {} (map parse-entry (str/split-lines input))))

Vincent Cantin07:12:34

I just realized that the algorithm for part2 could be used for part1

oxalorg (Mitesh)07:12:35

My naive solution: https://github.com/oxalorg/aoc/blob/main/src/puzzle7.clj Using some kind of memo could speed up first pass, but this works! ^_^

erwinrooijakkers08:12:00

Mine: https://github.com/transducer/adventofcode/blob/master/src/adventofcode/2020/day7.clj I don’t know why exactly I had to call set on the tree-seq entries in part 1 nor why I had to do apply + 1 in part 2, but it works 🙂

❤️ 6
Vincent Cantin08:12:25

I forgot about tree-seq … that’s a good idea.

erwinrooijakkers08:12:26

🙂 i now see set is because you have to find amount of different colors and + 1 is because you also have to count the containing bag

erwinrooijakkers08:12:32

(into (set found-bags) (mapcat #(find-outer-bags bags %) found-bags)) nice @U067R559Q

3
😁 3
erwinrooijakkers09:12:55

Wow nice, I tried to use core.logic last year for a somewhat similar problem (https://adventofcode.com/2019/day/14) but I did not manage

👍 3
alekszelark09:12:57

@U2PGHFU5U thanks to your solution for part 2, I simplified mine. Now it’s pretty straightforward

(defn count-bags [bags [bag n]]
  (* n (apply + 1 (map #(count-bags bags %) (get bags bag)))))

😊 6
Dosbol09:12:20

(loop [bags #{"shiny gold"}
       old-bags #{}]
  (if (= bags old-bags)
    (dec (count bags))
    (let [new-bags (into bags (map first
                                   (filter #(seq (clojure.set/intersection bags (second %))) data)))]
      (recur new-bags bags))))

Dosbol09:12:02

(defn get-bags-inside [times [color amount]]
  [(mapv (partial get-bags-inside (* times amount)) (data color)) (* times amount)])

(dec (apply + (flatten (get-bags-inside 1 ["shiny gold" 1]))))

benoit13:12:42

Nothing very exciting in my solution but I will post anyway 🙂 https://github.com/benfle/advent-of-code-2020/blob/main/day7.clj It took me way too long to figure out I was off by one for part 2 because I was counting the top shiny gold bag :)

jculp15:12:03

What am I missing with this regex? Works fine for groups of 1 or two but fails with 3 or more (the second group gets improperly matched)

(\w+ \w+) bags? contain ((\d+) (\w+ \w+).*? bags?)(, (\d+) (\w+ \w+) bags?)*\.

tws15:12:57

the * doesn’t repeat the capture group like you think it does

tws15:12:49

i’d consider re-seq

alekszelark15:12:03

> What am I missing with this regex? @U0ESCTA1E if you repeat a group, this group will be overwritten by the next match. For such cases you need to split a line, or just write 2 regex. Check my solution above for example.

Ben List16:12:20

heres mine, O'm definitely interested to see what others came up with today as I'm fairly new to clojure still https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/07.clj

rjray20:12:27

Here's mine: https://github.com/rjray/advent-2020-clojure/blob/master/src/advent_of_code/day07.clj Writing the parsing took longer than I'd like, but I really got stuck in part 1 due to a small logic-error. Part 2 only took about 10 more minutes.

Joe20:12:46

https://redpenguin101.github.io/posts/2020_12_07_aoc2020_day7.html. So impressed at how concise some of the answers here are. That was a fun problem though!

3
mchampine23:12:07

Again, lots of effort spent on processing the raw input into a nice shape. I notice my part 2 recursive function has the same pattern as several others. Took me some grinding to get it working. Still not pretty, oh well.

;; with input processed as:
;;     ["dull aqua" ([4 "dark fuchsia"] [1 "shiny purple"])]
(defn count-nestedbags [inp topbag]
  (letfn [(rcount [bag]
            (let [[_ bt] bag
                  contained (second (first (filter #(= bt (first %)) inp)))]
              (apply + 1
                     (for [[bc bn :as thebag] contained]
                       (if (= bn "no other") bc
                         (* bc (rcount thebag)))))))]
    (dec (rcount [1 topbag]))))

(count-nestedbags input-part2 "shiny gold")

pez23:12:07

This was so hard for me. It took me a lot of time to realize my first regex approach would not work. Then I had struggles wrapping my head around the recursion I needed. Then I made all sorts of silly mistakes even though the structure was right… And the result aint pretty!

(comment ; step 1
  (def input (util/fetch-input 7))
  (->> (clojure.string/split-lines input)
       (map #(clojure.string/split % #"[ ,]"))
       (map #(->> %
                  (partition 2 5)
                  (map vec)
                  (map (partial apply str))))
       ((fn dig [look-for found rules]
          (let [directs (reduce (fn [acc [bag & bags]]
                                  (if (seq (clojure.set/intersection (set bags) look-for))
                                    (conj acc bag)
                                    acc))
                                #{}
                                rules)]
            (if (seq directs)
              (dig directs (conj found directs) rules)
              found)))
        #{"shinygold"} #{})
       (apply clojure.set/union)
       (count)))

(comment ; step 2
  (def input (util/fetch-input 7))
  (->> (clojure.string/split-lines input)
       (map #(clojure.string/split (str "1 " %) #"[ ,]"))
       (remove #((set %) "no"))
       (map #(->> %
                  (partition 3 5)
                  (map (fn [[n c1 c2]]
                         [(Integer/parseInt n) (str c1 c2)]))))
       ((fn dig [look-for found rules]
          (let [directs (reduce (fn [acc [[_n bag-color] & bags]]
                                  (->> (for [color look-for
                                             :when (= color bag-color)]
                                         (map #(repeat (first %) %) bags))
                                       (apply concat)
                                       (apply concat)
                                       (into acc)))
                                []
                                rules)]
            (if (seq directs)
              (dig (map second directs) (into found directs) rules)
              found)))
        ["shinygold"] [])
       (count)))

pez23:12:42

when I have troubles naming things, I know I don’t know what I am doing, but I pressed on on sheer intuition. ¯\(ツ)

devn19:12:36

@U067R559Q is my hero. his solution in this thread blows me away.

6
devn19:12:07

I didn’t finish Part II in this style yet, but I decided to try and do day7 in a rules engine (#clara). There’s a better way to write this, but this gets the right answer:

(defrecord ContainerBag [type contained-bags])
(defrecord IntermediateBag [parent-type type])
(defrecord GoldBag [parent-type])

(defrule produce-intermediate-bags
  [ContainerBag
   (= ?type type)
   (= ?contained-bags contained-bags)]
  =>
  (when (seq ?contained-bags)
    (insert-all!
     (mapv (fn [[kind num]]
             (if (= kind "shiny gold")
               (map->GoldBag {:parent-type ?type})
               (map->IntermediateBag {:parent-type ?type
                                      :type kind})))
           ?contained-bags))))

(defrule indirect-gold-bags
  [ContainerBag
   (= ?type type)]
  [IntermediateBag
   (= ?type parent-type)
   (= ?intermediate-type type)]
  [GoldBag
   (= ?intermediate-type parent-type)]
  =>
  (insert! (map->GoldBag {:parent-type ?type})))

(defquery gold-bags []
  [?gold-bags <- (acc/distinct :parent-type) :from [GoldBag]])

(defn run-rules []
  (-> (mk-session :cache false)
      (insert-all (doall (for [[k vs] (parse input)]
                           (map->ContainerBag {:type k
                                               :contained-bags vs}))))
      (fire-rules)))
;; Part I
(-> (run-rules)
    (query gold-bags)
    first
    :?gold-bags
    count)
;; => 179

devn19:12:27

It would be cool to dynamically generate defrules for each line

st3fan16:12:48

Day 8 Answers Thread - Post your answers here

alekszelark07:12:32

(defn run-code [code]
  (let [history (atom #{})]
    (loop [acc 0
           ip  0]
      (let [[op arg] (nth code ip [:hlt 0])]
        (if (contains? @history ip)
          {:inf-loop acc}
          (do (swap! history conj ip)
              (case op
                :hlt {:halt acc}
                :nop (recur acc (inc ip))
                :acc (recur (+ acc arg) (inc ip))
                :jmp (recur acc (+ ip arg)))))))))

alekszelark08:12:00

And my final solution: https://github.com/zelark/AoC-2020/blob/master/src/zelark/aoc_2020/day_08.clj in the Part 2 firstly I used case , but re-implement it with a hash-map as @U07FP7QJ0 showed on the live stream.

fingertoe08:12:54

I always feel filthy when I use atoms…. This one is pretty dirty, but I got it done: https://github.com/jreighley/aoc2020/blob/master/src/day8.clj

motform12:12:40

definitely a bit engineered, but I’m not getting caught off-guard by a part 2: intcode boogaloo https://github.com/motform/advent-of-clojure/blob/master/src/advent-of-clojure/2020/eight.clj

Lars Nilsson15:12:24

Day 8 makes me appreciate immutable data structures and defmulti. I am fairly happy with my code for a change. https://github.com/chamaeleon/aoc2020-clj/blob/master/src/aoc2020/day08.clj

Joe18:12:00

https://redpenguin101.github.io/posts/2020_12_08_aoc2020_day8.html - this one did give me some flashbacks to intcode 😨

👍 3
Ben List19:12:41

I really liked the intcode ones last year so I hope there's some future days that build this one up Anyways my solution for day 08 https://github.com/listba/advent-of-code-2020/blob/master/clojure/src/aoc_2020/days/08.clj

pez22:12:59

I tried for so long do step 2 in a tree-ish way. Gave up. The brute force was with me though. Copying the program and modifying each one differently worked. I want my gold stars! Glad I learned about cond-> the other day.

(defn parse [input]
  (->> (clojure.string/split-lines input)
       (map #(clojure.string/split % #" "))
       (mapv (fn [[op arg]] [op (Integer/parseInt arg)]))))

(defn run [program]
  (let [length (count program)]
    (reduce (fn [cpu _]
              (let [{:keys [pc pcs]} cpu]
                (if (< pc length)
                  (let [[op arg]         (nth program pc)]
                    (if (pcs pc)
                      (reduced cpu)
                      (cond-> cpu
                        (= op "acc")        (update :acc #(+ % arg))
                        (#{"acc" "nop"} op) (update :pc inc)
                        (= op "jmp")        (update :pc #(+ % arg))
                        :always             (update :pcs conj pc))))
                  (reduced cpu))))
            {:acc    0
             :pc     0
             :length (count program)
             :pcs    #{}}
            (range))))

(comment
  (def input (util/fetch-input 8))
  ; step 1
  (->> input
       (parse)
       (run)
       :acc)

  ; step 2
  (->> input
       (parse)
       (#(repeat (count %) %))
       (keep-indexed (fn [i program]
                       (let [[op val] (program i)]
                         (assoc program i [(cond
                                             (= "nop" op) "jmp"
                                             (= "jmp" op) "nop"
                                             :else        op)
                                           val]))))
       (map run)
       (filter #(= (:pc %) (:length %)))
       (first)
       :acc))

🎉 3
kenj06:12:50

I’m officially a day behind now and late to the party https://gist.github.com/KennyMonster/9b9db6daa056e41413112d0fb31a5e47

kenj06:12:10

feels like part 2 could be way nice even brute forcing it… but I dunno how

pez21:12:26

A reason part 2 took me so long is that I was looking at it as a tree problem. So I was able to build a structure something like so (simplyfied):

[[nop jmp]
 [acc]
 [acc]
 [jmp nop]
 [acc]]
But then I failed building the programs from this. Which for the example above would be:
[[nop acc acc jmp acc]
 [jmp acc acc jmp acc]
 [nop acc acc nop acc]
 [jmp acc acc nop acc]]
Does anyone have any pointers on how to go about it?

Vincent Cantin01:12:50

@pez Here is what I would do to optimize this problem: • Collect all the switch-indexes , indexes of the nop and jmp where the original program go before an infinite loop is detected, because the solution is to flip one of those indexes. • Build the reverse-jmp-graph, where edges are from jmp-targets to jmp-sources. • In this graph, collect all land-indexes which are reachable from the end of the program. • Find which change on instructions at switch-indexes let the program go into instructions at land-indexes .

Stuart19:12:27

I've learnt a few neat functions from looking at you guys solution so far this year 🙂

💯 3
tws22:12:58

In case you haven’t seen it, I highly recommend being well versed in all these base functions, really helps to know what’s possible. https://clojure.org/api/cheatsheet

👍 3
st3fan22:12:35

I am doing 2015 in parallel 😕

Vincent Cantin06:12:24

split keyboard? 😉

Vincent Cantin01:12:50

@pez Here is what I would do to optimize this problem: • Collect all the switch-indexes , indexes of the nop and jmp where the original program go before an infinite loop is detected, because the solution is to flip one of those indexes. • Build the reverse-jmp-graph, where edges are from jmp-targets to jmp-sources. • In this graph, collect all land-indexes which are reachable from the end of the program. • Find which change on instructions at switch-indexes let the program go into instructions at land-indexes .