-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday8.bqn
163 lines (139 loc) · 5.02 KB
/
day8.bqn
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env cbqn
# Trying out namespaces and control flow today.
# https://mlochbaum.github.io/BQN/doc/namespace.html
# https://mlochbaum.github.io/BQN/spec/system.html#control
# https://mlochbaum.github.io/BQN/doc/control.html
# First and last have been swapped to better match input data where AAA and ZZZ are within the list somewhere.
e1 ← ⟨
"RL"
""
"ZZZ = (ZZZ, ZZZ)"
"BBB = (DDD, EEE)"
"CCC = (ZZZ, GGG)"
"DDD = (DDD, DDD)"
"EEE = (EEE, EEE)"
"GGG = (GGG, GGG)"
"AAA = (BBB, CCC)"
⟩
e2 ← ⟨
"LLR"
""
"ZZZ = (ZZZ, ZZZ)"
"BBB = (AAA, ZZZ)"
"AAA = (BBB, BBB)"
⟩
# Pretty print a block, for debugging purposes
PPrintB ← { (⊣≍˘𝕩⊸•ns.Get¨) •ns.Keys𝕩 }
Parse ← {
# Help! How do I train?
ParseNode ← (3⊸↑ ⋈ ((3⊸↑7⊸↓) ⋈ (3⊸↑12⊸↓)))
path‿node_map ← (⊑⋈2⊸↓) 𝕩
[nodes, node_dirs] ← ⍉>ParseNode ¨ node_map
path ⇐
start‿end ⇐ nodes⊐"AAA"‿"ZZZ"
[left, right] ⇐ nodes⊐⍉>node_dirs
}
# 𝕨 is the output of Parse
# 𝕩 is a state space { steps, node } for steps taken and current node
Cond ← {
data ← 𝕨
state ← 𝕩
data.end ≠ state.node
}
Step ← {
data ← 𝕨
state ← 𝕩
path_ix ← (≠data.path)|state.steps
dir ← ⊑path_ix↓data.path
{
dir = 'L' ?
steps ⇐ state.steps + 1
node ⇐ ⊑state.node↓data.left ;
steps ⇐ state.steps + 1
node ⇐ ⊑state.node↓data.right
}
}
Part1 ← {
data ← Parse 𝕩
(data Step •_while_ Cond { steps ⇐ 0 ⋄ node ⇐ data.start }).steps
}
•Show ⟨"Example 1 Part 1", Part1 e1⟩
•Show ⟨"Example 2 Part 1", Part1 e2⟩
e3 ← ⟨
"LR"
""
"11A = (11B, XXX)"
"11B = (XXX, 11Z)"
"11Z = (11B, XXX)"
"22A = (22B, XXX)"
"22B = (22C, 22C)"
"22C = (22Z, 22Z)"
"22Z = (22B, 22B)"
"XXX = (XXX, XXX)"
⟩
# Bah, I could make this take a function 𝕨 to get the start
ParseA ← {
# Help! How do I train?
ParseNode ← (3⊸↑ ⋈ ((3⊸↑7⊸↓) ⋈ (3⊸↑12⊸↓)))
path‿node_map ← (⊑⋈2⊸↓) 𝕩
[nodes, node_dirs] ← ⍉>ParseNode ¨ node_map
path ⇐
starts ⇐ /'A'=¯1⊑¨nodes
ends ⇐ /'Z'=¯1⊑¨nodes
[left, right] ⇐ nodes⊐⍉>node_dirs
}
CondZ ← {
data ← 𝕨
state ← 𝕩
¬ ∨´ state.node ⍷ data.ends
}
Part2 ← {
data ← ParseA 𝕩
inits ← { steps ⇐ 0 ⋄ node ⇐ 𝕩 }¨ data.starts
each ← (data⊸(Step •_while_ CondZ))¨ inits
•math.LCM´ (•ns.Get⟜"steps")¨ each
}
•Show ⟨"Example 3 Part 3", Part2 e3⟩
# Part 1 Initial Thoughts:
# The input sequence is heckin' long, as is the number of nodes. There's
# probably a "smarter" algorithm at play here. Parsing this is going to be a
# bitch too. The 2nd example should give me a hint - there's a cycle going on
# there and if I can work out the properties maybe I can figure out a formula
# without having to deal with it.
# One question to consider, is if i'll reaching the end is odne on a multiple of
# the instructions or not.
# After Part 1:
# There's a bit to learn when it comes to namespaces. They seem pretty handy to
# keep things clean but also introduce quite a bit of boilerplate.
# Not the most keen that my functions that use state before I get a chance to
# define it, and I'm guessing it's all dynamic.
# It's really quite terse, which explains the desire to have short variable
# names.
# After writing the initial solution I tought it would be quite inefficient.
# Turns out not to be the case. Parsing was also far easier than expected - it's
# a lot eaiser when the data is structured by index and not by arbitary length
# seperators.
# Part 2 Initial Thoughts:
# The difficulty here will really depend on how many nodes end with A. If there
# are too many then there's probably a trick, but part A was deceptively simple.
# The simple approach, which may be inefficient is to:
# 1. Find all that ends with A
# 2. Run the loop against each of them
# 3. Calculate the least common multiple between them
# Final thoughts
# This was supringly easy, and I thought I would have to reach for a more
# complex tool than the LCM. The lack of automatic PPrintB adds just the touch
# of friction to using namespaces instead of ad-hoc ‿s or 𝕨 𝕩.
# I've used the system versions of •_while_ and •math.LCM for simplicity, but I
# should really take a look at how they are implemented - especially LCM/GCD.
# I'm now a few days behind, and I still need to get back to day 5. Day 9 looks
# easy enough, with `, •_while_ and list wrangling. 10 looks like a bitch -
# there's annoying parsing in addition to more moore neighborhood stuff. Last
# time (day 3) I did it cellular automata style but this time I should try
# keeping an index list.
# bqn.js doens't support •FLines, but does support •GetLine.
# This snippet was kindly shared with me by funmaker
# input ← 1 ↓ ¯1 ↓ (⊢ ∾⟜< •GetLine)•_while_(@ ≢ ¯1 ⊑ ⊢) ⟨""⟩
input ← •FLines "inputs/day8.txt"
•Show ⟨"Part 1", Part1 input⟩
•Show ⟨"Part 2", Part2 input⟩