Skip to content

Commit 1f16d5d

Browse files
committed
add day 07: Bridge Repair
1 parent 97c48fa commit 1f16d5d

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

07_bridge_repair.rb

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
verbose = ARGV.delete('-v')
2+
3+
calib = ARGF.map { |line|
4+
l, r = line.split(': ', 2)
5+
[Integer(l), r.split.map(&method(:Integer)).freeze].freeze
6+
}.freeze
7+
8+
# work from right to left
9+
10+
tot = 0
11+
[false, true].each { |concat|
12+
good, calib = calib.partition { |tv, vs|
13+
make = ->(a, i) {
14+
return vs[0] == a if i == 0
15+
x = vs[i]
16+
((p10 = 10 ** x.to_s.size; make[a / p10, i - 1] if a % p10 == x) if concat) || (make[a / x, i - 1] if a % x == 0) || (make[a - x, i - 1] if x <= a)
17+
}
18+
make[tv, vs.size - 1]
19+
}.map(&:freeze)
20+
p good.map(&:first) if verbose
21+
puts tot += good.sum(&:first)
22+
}
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
require 'benchmark'
2+
3+
bench_candidates = []
4+
5+
bench_candidates << def drop1(calib)
6+
calib.sum { |tv, vs|
7+
vs.drop(1).reverse.reduce([tv]) { |acc, x|
8+
acc.flat_map { |a|
9+
[
10+
(a - x if x <= a),
11+
(a / x if a % x == 0),
12+
(p10 = 10 ** x.to_s.size; a / p10 if a % p10 == x),
13+
].compact
14+
}
15+
}.include?(vs[0]) ? tv : 0
16+
}
17+
end
18+
19+
bench_candidates << def no_drop(calib)
20+
calib.sum { |tv, vs|
21+
vs.reverse.reduce([tv]) { |acc, x|
22+
acc.flat_map { |a|
23+
[
24+
(a - x if x <= a),
25+
# no_drop specifically needs a > 0, because it checks for 0 at the end!
26+
(a / x if a > 0 && a % x == 0),
27+
(p10 = 10 ** x.to_s.size; a / p10 if a % p10 == x),
28+
].compact
29+
}
30+
}.include?(0) ? tv : 0
31+
}
32+
end
33+
34+
bench_candidates << def rec_add_first(calib)
35+
calib.sum { |tv, vs|
36+
make = ->(a, i) {
37+
return vs[0] == a if i == 0
38+
x = vs[i]
39+
(make[a - x, i - 1] if x <= a) || (make[a / x, i - 1] if a > 0 && a % x == 0) || (p10 = 10 ** x.to_s.size; make[a / p10, i - 1] if a % p10 == x)
40+
}
41+
make[tv, vs.size - 1] ? tv : 0
42+
}
43+
end
44+
45+
bench_candidates << def rec_mul_first(calib)
46+
calib.sum { |tv, vs|
47+
make = ->(a, i) {
48+
return vs[0] == a if i == 0
49+
x = vs[i]
50+
(make[a / x, i - 1] if a > 0 && a % x == 0) || (make[a - x, i - 1] if x <= a) || (p10 = 10 ** x.to_s.size; make[a / p10, i - 1] if a % p10 == x)
51+
}
52+
make[tv, vs.size - 1] ? tv : 0
53+
}
54+
end
55+
56+
bench_candidates << def rec_concat_first(calib)
57+
calib.sum { |tv, vs|
58+
make = ->(a, i) {
59+
return vs[0] == a if i == 0
60+
x = vs[i]
61+
(p10 = 10 ** x.to_s.size; make[a / p10, i - 1] if a % p10 == x) || (make[a / x, i - 1] if a > 0 && a % x == 0) || (make[a - x, i - 1] if x <= a)
62+
}
63+
make[tv, vs.size - 1] ? tv : 0
64+
}
65+
end
66+
67+
calib = ARGF.map { |line|
68+
l, r = line.split(': ', 2)
69+
[Integer(l), r.split.map(&method(:Integer)).freeze].freeze
70+
}.freeze
71+
72+
# work from right to left
73+
74+
results = {}
75+
76+
Benchmark.bmbm { |bm|
77+
bench_candidates.each { |f|
78+
bm.report(f) { 100.times { results[f] = send(f, calib) } }
79+
}
80+
}
81+
82+
# Obviously the benchmark would be useless if they got different answers.
83+
if results.values.uniq.size != 1
84+
results.each { |k, v| puts "#{k} #{v}" }
85+
raise 'differing answers'
86+
end

0 commit comments

Comments
 (0)