Fork me on GitHub
#adventofcode
<
2022-12-19
>
norman07:12:07

Day 19 - Solutions

norman07:12:40

https://gitlab.com/maximoburrito/advent2022/-/blob/main/src/day19/main.clj This is really a terrible effort. The code is very slow - basically I'm searching the space with some really sketchy pruning out of states when geodes and obsidian can be made. But I'm doing the pruning kind of late. It's a mess... I started rewriting while waiting for part1 to finish, anticipating I'd need to do something better for part2, should my solution work at all. It turns out it did and that part2 required almost no changes, so I dropped it in favor of sleep. Almost ashamed to post this...

misha13:12:33

^^^ © basically everyone on reddit kappa

norman15:12:52

Ha - yeah, seems like it. My first attempt was raw full search. Then I rewrote so that if you could build any bot it would build it, but that go stuck building ores and clays. Then I went back to full search trying to filter out previously seen states, thinking that would help prune enough. It didn't. I added the max geode check as a test to see if always building geodes worked but otherwise not constraining. It did, but it was slow. Then I added the max obsidian check for states that had the max geodes. Looking at the code this morning I don't think that check is exactly doing what I wanted. But it works. Weird. It didn't really speed things up much, but it gets to the answer. It seems lots of people are doing some variant of these checks, but I'm not seeing anything that stands out as a "good" way

Callum Oakley16:12:22

https://github.com/callum-oakley/advent-of-code/blob/main/src/aoc/2022/19.clj this one was a real beast, also unhappy with what feels like a huge pile of hacks and poorly justified "heuristics" 😅 • branch and bound with a truly awful bound of "assume you can build another geo robot in every remaining minute" • if you can afford a geo robot, always build it immediately • if we opted not to build a robot we could have built last turn, don't build it this turn either (it would have been better to build it before) • don't build a robot if we have more than 16 of its resource already (horrible hack, but cuts the search space down a lot) finishes in 4.6s for part 1 and 1.6s for part 2

bellissimo 1
misha18:12:56

(sort of) fast p1 solution gave wrong result for sample p2 => (42 62) instead of => (56 62) p1 "Elapsed time: 19290.007506 msecs" with heuristic p2 "Elapsed time: 23966.599927 msecs" with commented out heuristic

tschady18:12:08

> The second blueprint has ID 2 and can open 12 geodes Anybody stuck with 10 geodes then figure it out? Or if anyone has the full path for the answer to the example ID2, I’d appreciate it. I get the correct answer “9” for ID1, and my answer path has the same as provided. I’m missing some case, data would help. (Edit: think I found it)

Miķelis Vindavs19:12:26

I'm sure this can all be expressed as a matrix of costs in materials/time, and solved in more or less constant time somehow

Miķelis Vindavs19:12:16

@U1Z392WMQ do you still need the path for p2?

Callum Oakley19:12:26

I was stuck on 10 for example 2 for a bit too, obviously a carefully chosen counter example!

Miķelis Vindavs19:12:02

For me, p2 on the example is many times slower than both parts on the real input

rjray20:12:47

Whelp. First pass at part 1 overflows the stack on the first blueprint of the test data. And that's with some (weak) heuristics to prune the search-space.

Callum Oakley20:12:25

@UEF091BP0 sure you're not in an infinite loop somehow? I would have thought the recursion depth would be 24 at most even if you're doing a full on brute force? :thinking_face:

rjray20:12:59

I'm doing it as a BFS search, but I can't rule out an infinite loop. I'm basing this on a Python solution from reddit. The Python is slow, but it succeeds.

rjray20:12:28

I just think my tail-recursion loop constructs are passing values that grow too large for the stack.

Miķelis Vindavs20:12:34

btw @U1Z392WMQ here’s what i get for the p2 example for the second blueprint

Miķelis Vindavs20:12:37

0 wait
 1 wait
 2 ore
 3 wait
 4 ore
 5 clay
 6 clay
 7 clay
 8 clay
 9 clay
10 clay
11 obsidian
12 obsidian
13 obsidian
14 obsidian
15 ore
16 obsidian
17 geo
18 obsidian
19 geo
20 obsidian
21 geo
22 obsidian
23 geo
24 obsidian
25 geo
26 geo
27 geo
28 clay
29 geo
30 geo
31 geo

❤️ 1
Miķelis Vindavs20:12:36

@UEF091BP0 what are your loop variables? for collections, the size should not matter as the only thing on the stack is the pointer to them

Miķelis Vindavs20:12:32

if i had to guess, your stop condition is probably incorrect , e.g. it keeps going after time is zero, or doesn’t decrement time when recursing

rjray20:12:06

Three elements: a list of moves, the current best value, and a set of seen states.

rjray20:12:00

I had a similar problem with day 16, and just used my own Python code to get the points and stars for that one. I still don't have a Clojure version for that day.

rjray20:12:17

Just using some simple prn-based debugging lines, I can see my queue of moves growing to almost 30000 before I stopped it.

Miķelis Vindavs20:12:03

where do you track time?

rjray20:12:13

It's the last element of each move-value.

Miķelis Vindavs20:12:15

also, i might be wrong but i think in this puzzle there is no benefit to searching breadth first, so instead of a large queue, you could use a stack to conj/pop , or just use recursion

rjray20:12:15

Dunno. Busy with my "real" job for now, will have to look at it later.

misha21:12:12

concat/cons (instead of into) of lazy seqs can overflow on fairly small amounts in loop s

rjray21:12:24

Hmmm... I do have that. I use concat to ensure that the new moves go at the end of the list.

misha21:12:07

(first (loop [i 3500 xs []]
         (if (pos? i)
           (recur (dec i) (concat xs (range 0 i)))
           xs)))
Execution error (StackOverflowError) at (REPL:1).
null

misha21:12:31

use queue

misha21:12:54

(defn queue [init]
  #?(:cljs (into #queue[] init)
     :clj  (into PersistentQueue/EMPTY init)))

misha21:12:35

peek will take first, into will append

alekszelark22:12:47

The worst day, even if you solve it for your input, it doesn’t mean that it will work for others. Hate these type of problems.

rjray22:12:08

Well, that was educational. I replaced my makeshift-queue with PersistentQueue and got the first part correct. Once I've finished part 2, I'll try to fix Day 16 with PersistentQUeue, as well.

alekszelark22:12:28

I wrote a solution similar as @U0954HGDQ did, and it looked like it worked fine until I got a wrong answer. Moreover, when I tested it with another input (for which I knew correct number of geodes), It turned out only for exactly one blueprint it got a wrong answer.

rjray23:12:58

Aaaand... part 2 results in an OutOfMemoryError in Java heap space...

rjray23:12:07

Interesting. Bumped up the heap and restarted my CIDER REPL and it still dies on the test input. But run it from lein on the real data and I get the correct answer. I guess nREPL has it's own overhead...

bhauman23:12:37

I’m still working hard on this

bhauman23:12:59

That's not the right answer; your answer is too low.

bhauman23:12:34

I like my approach of doing a bfs one level at a time sorting the results via a geo heavy heuristic and taking the top 2000?

bhauman23:12:41

I’m still widening my heuristic until it stabilizes somewhere.

bhauman23:12:32

And part 1 is done!

bhauman00:12:35

I think that’s the trick, doing bfs level by level and sorting and trimming each level as input to the next level

bhauman00:12:10

(defn do-turn [blu robot]
  (cond-> blu
    robot (pay-for-robot robot)
    true robots-work
    robot (add-robot robot)))

(defn children [blu]
  (->> (conj (can-build? blu) nil)
       (map (partial do-turn blu))
       (map #(update % ::depth inc))))

(defn bfs-leveler [previous-level]
  (->> previous-level
       (mapv children)
       (reduce into #{})
       (sort-by blu-value >)
       (take 3000)))

(defn optimizing-game-player [blueprint minutes]
  (->> (iterate bfs-leveler [(assoc blueprint ::depth 0)])
       (take (inc minutes))
       last
       first))

AC00:12:21

I spent way too much time overthinking how to prune states and still haven’t come up with anything I like. (I’ve been skimming responses to avoid spoilers). I’ve gotten it down to ~3 minutes, but I’m not proud of it. I’m going to take that as a win for now and go back to Day 15 Part 2. I think I know what I need to do but I just can’t get motivated to write it.

bhauman00:12:55

Yeah I’m heading back to day 17 part 2

Alex Alemi03:12:50

Today was brutal, but I ended up with something I'm not too embarrassed by: https://github.com/alexalemi/advent/blob/main/2022/clojure/p19.clj

Alex Alemi03:12:11

Trick was to set a target machine and fast-forward potentially many steps

Alex Alemi03:12:08

In the end, gets part 1 in 4 seconds and part 2 in 25 seconds

👍 1
wevrem01:01:38

Part II was my last holdout and for the life of me I couldn’t get the right answer. After rebuilding my code from scratch, and testing carefully all the way (and, admittedly, finding a few places that could be improved and learning a thing or two) I realized I was still just adding the top three blueprints, when the instructions clearly said to multiply. Oh bothers. I don’t want to think about how much time I wasted and hairs I lost trying to figure out why I couldn’t get the right answer. At least now I can finally say that AoC 2022 is wrapped up.

🎄 4