--- Day 21: Keypad Conundrum ---Finally done. I have mixed feelings about this one. Actually, a bit confused by the instructions given for the test case.
I'm particularly referring to the second directional keypad expansion for the test case (for code 029A).
<vA<AA>>^AvAA<^A>A<v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A
v<<A>>^A<A>AvA<^AA>A<vAAA>^A
<A^A>^^AvvvA
029A
I am pointing out the oversize bits of code, all <v<.
This is obviously wrong expansion, that is, in this particular case (part1 problem with only 2 directional keypads, and this expansion being from the second (last) keypad), it does yield the correct result. Since this expansion could not be used for the first expansion, it made me believe, that two different expansions are required (for part1) to solve the problem. This, of-course would complicate very much part2 with 25 directional keypads.
A better explanation why sequence <v< is wrong, is that it includes 2 changes of direction: from < to v, and then from v to <, and every change costs more moves in the next expansion. This <v< could be written as <<v or v<<, because both of these include only one change of direction.
So, this example, I regard as misdirection (pun intended) in day21 instructions.
As it turned out only one directional expansion is necessary, but the one that requires very fine control over which path to choose.
The actual problem of solving working with 25 generations (and trillions of moves) was relatively easy. Same technique as for one of the older AOC problems (75 generations of changing stones). Just go all the way left and fully expand one move at a time. The trick with this is that it is not possible to start this right away after the numerical keypad expansion, because even only the first move would expand into 337trillion / 12, which can not fit into the RAM. So a judicious mix of first using ordinary (part1) sequence of expansions, and then continuing with memoized version on the first move is the solution. I found (just experimenting) that the optimal mix is 11 generations of part1 expansion, continued with 14 generations of memoized version yields the fastest execution time (5.4s on banana), and does not use memory. Only 0.1 GB increase during running of the program.
Code:
;;; Advent of code 2024 - day21, part1 & part2, on BPI-F3 RISC-V;;; Chez code --- Day 21: Keypad Conundrum ---(load "utils.so")(define movest (make-hashtable equal-hash equal? 64))(define xpandt (make-hashtable equal-hash equal? 64))(define dkplt '(((#\A . #\^) (#\< #\A)) ((#\^ . #\A) (#\> #\A)) ((#\A . #\>) (#\v #\A)) ((#\> . #\A) (#\^ #\A)) ((#\A . #\v) (#\< #\v #\A)) ((#\v . #\A) (#\^ #\> #\A)) ((#\A . #\<) (#\v #\< #\< #\A)) ((#\< . #\A) (#\> #\> #\^ #\A)) ((#\^ . #\v) (#\v #\A)) ((#\v . #\^) (#\^ #\A)) ((#\^ . #\>) (#\v #\> #\A)) ((#\> . #\^) (#\< #\^ #\A)) ((#\^ . #\<) (#\v #\< #\A)) ((#\< . #\^) (#\> #\^ #\A)) ((#\v . #\>) (#\> #\A)) ((#\> . #\v) (#\< #\A)) ((#\v . #\<) (#\< #\A)) ((#\< . #\v) (#\> #\A)) ((#\> . #\<) (#\< #\< #\A)) ((#\< . #\>) (#\> #\> #\A)) ((#\A . #\A) (#\A)) ((#\^ . #\^) (#\A)) ((#\> . #\>) (#\A)) ((#\v . #\v) (#\A)) ((#\< . #\<) (#\A))))...(define (memoize-expand f) (lambda (x y z) (let ((seen (hashtable-ref xpandt (cons x y) #f))) (or seen (let ((result (f x y z))) (hashtable-set! xpandt (cons x y) result) result))))) (set! expand (memoize-expand expand))
Code:
hrvoje@BPI-F3:~/Projects/advent-of-code/2024/day-21/Chez$ schemeChez Scheme Version 10.1.0Copyright 1984-2024 Cisco Systems, Inc.> (load "day21.ss")> (time2 (lambda () (day21 "input.txt")))278748337744744231414#<time-duration 5.363827205>
I'm particularly referring to the second directional keypad expansion for the test case (for code 029A).
<vA<AA>>^AvAA<^A>A<v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A
v<<A>>^A<A>AvA<^AA>A<vAAA>^A
<A^A>^^AvvvA
029A
I am pointing out the oversize bits of code, all <v<.
This is obviously wrong expansion, that is, in this particular case (part1 problem with only 2 directional keypads, and this expansion being from the second (last) keypad), it does yield the correct result. Since this expansion could not be used for the first expansion, it made me believe, that two different expansions are required (for part1) to solve the problem. This, of-course would complicate very much part2 with 25 directional keypads.
A better explanation why sequence <v< is wrong, is that it includes 2 changes of direction: from < to v, and then from v to <, and every change costs more moves in the next expansion. This <v< could be written as <<v or v<<, because both of these include only one change of direction.
So, this example, I regard as misdirection (pun intended) in day21 instructions.
As it turned out only one directional expansion is necessary, but the one that requires very fine control over which path to choose.
The actual problem of solving working with 25 generations (and trillions of moves) was relatively easy. Same technique as for one of the older AOC problems (75 generations of changing stones). Just go all the way left and fully expand one move at a time. The trick with this is that it is not possible to start this right away after the numerical keypad expansion, because even only the first move would expand into 337trillion / 12, which can not fit into the RAM. So a judicious mix of first using ordinary (part1) sequence of expansions, and then continuing with memoized version on the first move is the solution. I found (just experimenting) that the optimal mix is 11 generations of part1 expansion, continued with 14 generations of memoized version yields the fastest execution time (5.4s on banana), and does not use memory. Only 0.1 GB increase during running of the program.
Statistics: Posted by hrvoje064 — Thu Jan 30, 2025 4:01 am