1
1
module Day21
2
2
3
3
using AdventOfCode2024
4
-
4
+ using Memoize
5
5
6
6
function day21 (input:: String = readInput (joinpath (@__DIR__ , " .." , " data" , " day21.txt" )))
7
- numerical_keypad = [' #' ' #' ' #' ' #' ' #' ;
8
- ' #' ' 7' ' 8' ' 9' ' #' ;
9
- ' #' ' 4' ' 5' ' 6' ' #' ;
10
- ' #' ' 1' ' 2' ' 3' ' #' ;
11
- ' #' ' .' ' 0' ' A' ' #' ;
12
- ' #' ' #' ' #' ' #' ' #' ]
13
- directional_keypad = [' #' ' #' ' #' ' #' ' #' ;
14
- ' #' ' .' ' ^' ' A' ' #' ;
15
- ' #' ' <' ' v' ' >' ' #' ;
16
- ' #' ' #' ' #' ' #' ' #' ]
17
- layer1 = generate_instructions (" 029A" , numerical_keypad)
18
- layer2 = reduce (vcat, [generate_instructions (x, directional_keypad) for x ∈ layer1])
19
- end
20
-
21
- # function calculate_instructions(keypad::Matrix{Char}, from::Char, to::Char)
22
- # start = findall(x -> x == from, keypad)[1]
23
- # goal = findall(x -> x == to, keypad)[1]
24
- # dirs = (('v', [1, 0]), ('^', [-1, 0]), ('>', [0, 1]), ('<', [0, -1]))
25
- # visited = zeros(Bool, size(keypad)...)
26
- # current = [(start, "")]
27
- # while !isempty(current)
28
- # for (elem, st) ∈ current
29
- # if elem == goal
30
- # return st
31
- # end
32
- # visited[elem] = true
33
- # end
34
- # new_current = []
35
- # while !isempty(current)
36
- # elem, st = pop!(current)
37
- # for (c, dir) ∈ dirs
38
- # neighcoord = CartesianIndex((elem.I .+ dir)...)
39
- # if keypad[neighcoord] != '#' && !visited[neighcoord]
40
- # push!(new_current, (neighcoord, st * c))
41
- # end
42
- # end
43
- # end
44
- # current = new_current
45
- # end
46
- # end
47
-
48
- function from_to (keypad:: Matrix{Char} , from:: Char , to:: Char )
49
- start = findall (x -> x == from, keypad)[1 ]
50
- goal = findall (x -> x == to, keypad)[1 ]
51
- # dirs = (('v', [1, 0]), ('^', [-1, 0]), ('>', [0, 1]), ('<', [0, -1]))
7
+ data = split (rstrip (input), " \n " )
8
+ numpad = Dict {Char,Tuple{Int,Int}} (
9
+ ' A' => (4 , 3 ),
10
+ ' 0' => (4 , 2 ),
11
+ ' 1' => (3 , 1 ),
12
+ ' 2' => (3 , 2 ),
13
+ ' 3' => (3 , 3 ),
14
+ ' 4' => (2 , 1 ),
15
+ ' 5' => (2 , 2 ),
16
+ ' 6' => (2 , 3 ),
17
+ ' 7' => (1 , 1 ),
18
+ ' 8' => (1 , 2 ),
19
+ ' 9' => (1 , 3 )
20
+ )
21
+ dirpad = Dict {Char,Tuple{Int,Int}} (
22
+ ' A' => (1 , 3 ),
23
+ ' ^' => (1 , 2 ),
24
+ ' <' => (2 , 1 ),
25
+ ' v' => (2 , 2 ),
26
+ ' >' => (2 , 3 )
27
+ )
28
+ numpad_graph = create_graph (numpad, (4 , 1 ))
29
+ dirpad_graph = create_graph (dirpad, (1 , 1 ))
52
30
53
- diff = goal - start
54
- if diff[1 ] >= 0
55
- x = ' v'
56
- else
57
- x = ' ^'
31
+ p1, p2 = 0 , 0
32
+ for d ∈ data
33
+ p1 += solve (d, 3 , numpad_graph, dirpad_graph, true ) * parse (Int, d[1 : end - 1 ])
34
+ p2 += solve (d, 26 , numpad_graph, dirpad_graph, true ) * parse (Int, d[1 : end - 1 ])
58
35
end
59
- if diff[2 ] > 0
60
- y = ' >'
61
- else
62
- y = ' <'
63
- end
64
- return unique ([repeat (x, abs (diff[1 ])) * repeat (y, abs (diff[2 ])), repeat (y, abs (diff[2 ])) * repeat (x, abs (diff[1 ]))])
36
+ return [p1, p2]
65
37
end
66
38
67
- # function code_numerical(code::String, keypad::Matrix{Char})
68
- # instructions = ""
69
- # from = 'A'
70
- # for to ∈ code
71
- # instructions *= calculate_instructions(keypad, from, to) * 'A'
72
- # from = to
73
- # end
74
- # return instructions
75
- # end
76
-
77
- # function code_directional(code::String, keypad::Matrix{Char})
78
-
79
- # end
80
-
81
- # function generate_instructions(code::String, keypad::Matrix{Char})
82
- # instructions = ""
83
- # from = 'A'
84
- # for to ∈ code
85
- # instructions *= calculate_instructions(keypad, from, to) * 'A'
86
- # from = to
87
- # end
88
- # return instructions
89
- # end
90
-
91
- function generate_instructions (code:: String , keypad:: Matrix{Char} )
92
- instructions = Vector {String} ()
93
- from = ' A'
94
- for to ∈ code
95
- parts = from_to (keypad, from, to)
96
- if isempty (instructions)
97
- for instr ∈ parts
98
- push! (instructions, instr * ' A' )
99
- end
100
- end
101
- if length (parts) > 1
102
- cp = copy (instructions)
103
- end
104
- for (i, _) ∈ enumerate (instructions)
105
- instructions[i] *= parts[1 ] * ' A'
106
- end
107
- if length (parts) > 1
108
- for (i, _) ∈ enumerate (cp)
109
- push! (instructions, cp[i] * parts[2 ] * ' A' )
39
+ function create_graph (keypad, forbidden_coord)
40
+ graph = Dict {Char,Dict{Char,String}} ()
41
+ for key ∈ keys (keypad)
42
+ graph[key] = Dict {Char,String} ()
43
+ end
44
+ for (k1, (x1, y1)) ∈ keypad
45
+ for (k2, (x2, y2)) ∈ keypad
46
+ path = repeat (" <" , max (0 , y1- y2)) * repeat (" v" , max (0 , x2- x1)) * repeat (" ^" , max (0 , x1- x2)) * repeat (" >" , max (0 , y2- y1))
47
+ if forbidden_coord == (x1, y2) || forbidden_coord == (x2, y1)
48
+ path = reverse (path)
110
49
end
50
+ graph[k1][k2] = path * ' A'
111
51
end
112
52
end
113
- return instructions
53
+ return graph
114
54
end
115
55
56
+ @memoize function solve (sequence, iterations, numpad_graph, dirpad_graph, first)
57
+ iterations == 0 && return length (sequence)
58
+ prev = ' A'
59
+ total = 0
60
+ graph = first ? numpad_graph : dirpad_graph
61
+ for c ∈ sequence
62
+ total += solve (graph[prev][c], iterations - 1 , numpad_graph, dirpad_graph, false )
63
+ prev = c
64
+ end
65
+ return total
66
+ end
116
67
117
68
end # module
0 commit comments