cem 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/aoc2018/.gitignore +2 -0
- data/examples/aoc2018/day10.rb +61 -0
- data/examples/aoc2018/day11.rb +66 -0
- data/examples/aoc2018/day12.rb +61 -0
- data/examples/aoc2018/day13.rb +167 -0
- data/examples/aoc2018/day14.rb +31 -0
- data/examples/aoc2018/day14_2.rb +71 -0
- data/examples/aoc2018/day15.rb +271 -0
- data/examples/aoc2018/day16.rb +158 -0
- data/examples/aoc2018/day17.rb +203 -0
- data/examples/aoc2018/day18.rb +113 -0
- data/examples/aoc2018/day18_rspec.rb +131 -0
- data/examples/aoc2018/day19.rb +145 -0
- data/examples/aoc2018/day20.rb +103 -0
- data/examples/aoc2018/day21.rb +158 -0
- data/examples/aoc2018/day21_v2.rb +137 -0
- data/examples/aoc2018/day21_v3.rb +157 -0
- data/examples/aoc2018/day21_v4.rb +141 -0
- data/examples/aoc2018/day22.rb +212 -0
- data/examples/aoc2018/day23.rb +148 -0
- data/examples/aoc2018/day24.rb +156 -0
- data/examples/aoc2018/day25.rb +52 -0
- data/examples/aoc2018/day9.rb +51 -0
- data/examples/aoc2018/day9_circular.rb +125 -0
- data/examples/aoc2018/inputs/day10_input.txt +395 -0
- data/examples/aoc2018/inputs/day11_input.txt +1 -0
- data/examples/aoc2018/inputs/day12_input.txt +34 -0
- data/examples/aoc2018/inputs/day12_input2.txt +16 -0
- data/examples/aoc2018/inputs/day13_input.txt +150 -0
- data/examples/aoc2018/inputs/day13_test.txt +6 -0
- data/examples/aoc2018/inputs/day14_input.txt +1 -0
- data/examples/aoc2018/inputs/day15_input.txt +32 -0
- data/examples/aoc2018/inputs/day15_input10.txt +32 -0
- data/examples/aoc2018/inputs/day15_input11.txt +32 -0
- data/examples/aoc2018/inputs/day15_input12.txt +32 -0
- data/examples/aoc2018/inputs/day15_input13.txt +32 -0
- data/examples/aoc2018/inputs/day15_input14.txt +32 -0
- data/examples/aoc2018/inputs/day15_input2.txt +7 -0
- data/examples/aoc2018/inputs/day15_input3.txt +9 -0
- data/examples/aoc2018/inputs/day15_input4.txt +7 -0
- data/examples/aoc2018/inputs/day15_input5.txt +7 -0
- data/examples/aoc2018/inputs/day15_input6.txt +7 -0
- data/examples/aoc2018/inputs/day15_input7.txt +7 -0
- data/examples/aoc2018/inputs/day15_input8.txt +5 -0
- data/examples/aoc2018/inputs/day15_input9.txt +7 -0
- data/examples/aoc2018/inputs/day15_test.txt +9 -0
- data/examples/aoc2018/inputs/day16_input.txt +3865 -0
- data/examples/aoc2018/inputs/day17_input.txt +2229 -0
- data/examples/aoc2018/inputs/day17_input_test.txt +8 -0
- data/examples/aoc2018/inputs/day18_input.txt +50 -0
- data/examples/aoc2018/inputs/day18_test.txt +10 -0
- data/examples/aoc2018/inputs/day19_input.txt +48 -0
- data/examples/aoc2018/inputs/day20_input.txt +1 -0
- data/examples/aoc2018/inputs/day21_input.txt +32 -0
- data/examples/aoc2018/inputs/day22_input.txt +2 -0
- data/examples/aoc2018/inputs/day23_input.txt +1000 -0
- data/examples/aoc2018/inputs/day23_input2.txt +9 -0
- data/examples/aoc2018/inputs/day24_input.txt +24 -0
- data/examples/aoc2018/inputs/day25_input.txt +1483 -0
- data/examples/aoc2018/inputs/day9_input.txt +1 -0
- data/lib/cem.rb +0 -6
- data/lib/cem/ccommon.rb +45 -0
- data/lib/cem/cruzzles.rb +93 -38
- data/lib/cem/version.rb +1 -1
- metadata +62 -2
@@ -0,0 +1,141 @@
|
|
1
|
+
#
|
2
|
+
# https://adventofcode.com/2018/day/21 part 1 and part 2
|
3
|
+
#
|
4
|
+
# Does not use any 'cem' functions
|
5
|
+
#
|
6
|
+
# Rev 4: Replace the register array access with local variables => Double speed up.
|
7
|
+
#
|
8
|
+
require 'cem'
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
lines = File.readlines("inputs/day21_input.txt", chomp: true)
|
12
|
+
|
13
|
+
commandQueue = []
|
14
|
+
|
15
|
+
r0 = r1 = r2 = r3 = r4 = r5 = 0
|
16
|
+
@s = Set.new
|
17
|
+
@last = nil
|
18
|
+
|
19
|
+
def command(verb, v1, v2, v3)
|
20
|
+
|
21
|
+
case verb
|
22
|
+
when "addr"
|
23
|
+
# addr (add @register) stores into @register C the result of adding @register A and @register B.
|
24
|
+
" r#{v3} = r#{v1} + r#{v2} "
|
25
|
+
|
26
|
+
when "addi"
|
27
|
+
# addi (add immediate) stores into @register C the result of adding @register A and value B.
|
28
|
+
" r#{v3} = r#{v1} + #{v2} "
|
29
|
+
|
30
|
+
when "mulr"
|
31
|
+
# mulr (multiply @register) stores into @register C the result of multiplying @register A and @register B.
|
32
|
+
" r#{v3} = r#{v1} * r#{v2} "
|
33
|
+
|
34
|
+
when "muli"
|
35
|
+
# muli (multiply immediate) stores into @register C the result of multiplying @register A and value B.
|
36
|
+
" r#{v3} = r#{v1} * #{v2} "
|
37
|
+
|
38
|
+
when "banr"
|
39
|
+
# banr (bitwise AND @register) stores into @register C the result of the bitwise AND of @register A and @register B.
|
40
|
+
" r#{v3} = r#{v1} & r#{v2} "
|
41
|
+
|
42
|
+
when "bani"
|
43
|
+
# bani (bitwise AND immediate) stores into @register C the result of the bitwise AND of @register A and value B.
|
44
|
+
" r#{v3} = r#{v1} & #{v2} "
|
45
|
+
|
46
|
+
when "borr"
|
47
|
+
# borr (bitwise OR @register) stores into @register C the result of the bitwise OR of @register A and @register B.
|
48
|
+
" r#{v3} = r#{v1} | r#{v2} "
|
49
|
+
|
50
|
+
when "bori"
|
51
|
+
# bori (bitwise OR immediate) stores into @register C the result of the bitwise OR of @register A and value B.
|
52
|
+
" r#{v3} = r#{v1} | #{v2} "
|
53
|
+
|
54
|
+
when "setr"
|
55
|
+
# setr (set @register) copies the contents of @register A into @register C. (Input B is ignored.)
|
56
|
+
" r#{v3} = r#{v1} "
|
57
|
+
|
58
|
+
when "seti"
|
59
|
+
# seti (set immediate) stores value A into @register C. (Input B is ignored.)
|
60
|
+
" r#{v3} = #{v1} "
|
61
|
+
|
62
|
+
when "gtir"
|
63
|
+
# gtir (greater-than immediate/@register) sets @register C to 1 if value A is greater than @register B. Otherwise, @register C is set to 0.
|
64
|
+
" r#{v3} = #{v1} > r#{v2} ? 1 : 0 "
|
65
|
+
|
66
|
+
when "gtri"
|
67
|
+
# gtri (greater-than @register/immediate) sets @register C to 1 if @register A is greater than value B. Otherwise, @register C is set to 0.
|
68
|
+
" r#{v3} = r#{v1} > #{v2} ? 1 : 0 "
|
69
|
+
|
70
|
+
when "gtrr"
|
71
|
+
# gtrr (greater-than @register/@register) sets @register C to 1 if @register A is greater than @register B. Otherwise, @register C is set to 0.
|
72
|
+
" r#{v3} = r#{v1} > r#{v2} ? 1 : 0 "
|
73
|
+
|
74
|
+
when "eqir"
|
75
|
+
# eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0.
|
76
|
+
" r#{v3} = #{v1} == r#{v2} ? 1 : 0 "
|
77
|
+
|
78
|
+
when "eqri"
|
79
|
+
# eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0.
|
80
|
+
" r#{v3} = r#{v1} == #{v2} ? 1 : 0 "
|
81
|
+
|
82
|
+
when "eqrr"
|
83
|
+
# eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.
|
84
|
+
" r#{v3} = r#{v1} == r#{v2} ? 1 : 0
|
85
|
+
|
86
|
+
if #{v2} == 0
|
87
|
+
if @s.size == 0
|
88
|
+
puts \"Part 1: \#{r#{v1}}\"
|
89
|
+
end
|
90
|
+
|
91
|
+
puts \"\#{@s.size.to_s.rjust(10)} - \#{r#{v1}}\" if @s.size % 64 == 0
|
92
|
+
|
93
|
+
if @s.include?(r#{v1})
|
94
|
+
puts \"Part 2: \#{@last}\"
|
95
|
+
exit
|
96
|
+
end
|
97
|
+
@s.add r#{v1}
|
98
|
+
@last = r#{v1}
|
99
|
+
end
|
100
|
+
"
|
101
|
+
else
|
102
|
+
puts "error" # raise "Error"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
ip = nil
|
108
|
+
lines.each { |line|
|
109
|
+
|
110
|
+
if line =~ /^#ip ([+-]?\d+)$/
|
111
|
+
ip = $1.to_i
|
112
|
+
end
|
113
|
+
|
114
|
+
if line =~ /^(\w+) ([+-]?\d+) ([+-]?\d+) ([+-]?\d+)$/
|
115
|
+
verb = $1
|
116
|
+
v1 = $2.to_i
|
117
|
+
v2 = $3.to_i
|
118
|
+
v3 = $4.to_i
|
119
|
+
|
120
|
+
commandQueue << command(verb, v1, v2, v3)
|
121
|
+
end
|
122
|
+
}
|
123
|
+
|
124
|
+
ndigits = commandQueue.size.digits.size
|
125
|
+
|
126
|
+
commandQueue = <<~EOS
|
127
|
+
while
|
128
|
+
|
129
|
+
case r#{ip}
|
130
|
+
#{commandQueue.each_with_index.map { |v, i| "when #{i.to_s.rjust(ndigits)} then #{v}"}.join("\n")}
|
131
|
+
else
|
132
|
+
raise
|
133
|
+
end
|
134
|
+
|
135
|
+
r#{ip} += 1
|
136
|
+
|
137
|
+
end
|
138
|
+
EOS
|
139
|
+
|
140
|
+
puts commandQueue
|
141
|
+
eval(commandQueue)
|
@@ -0,0 +1,212 @@
|
|
1
|
+
#
|
2
|
+
# https://adventofcode.com/2018/day/22 part 1 and 2
|
3
|
+
#
|
4
|
+
# Demonstrates some use of Grid and Point2D
|
5
|
+
#
|
6
|
+
# Why this was hard: Did not read spec precisely!
|
7
|
+
|
8
|
+
require 'set'
|
9
|
+
require 'cem'
|
10
|
+
|
11
|
+
EXTRAX = 10
|
12
|
+
EXTRAY = 10
|
13
|
+
|
14
|
+
verbose = false
|
15
|
+
|
16
|
+
lines = File.readlines("inputs/day22_input.txt", chomp: true)
|
17
|
+
|
18
|
+
depth = nil
|
19
|
+
target = nil
|
20
|
+
|
21
|
+
lines.each { |line|
|
22
|
+
|
23
|
+
if line =~ /^depth: ([+-]?\d+)$/
|
24
|
+
depth = $1.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
if line =~ /^target: ([+-]?\d+),([+-]?\d+)$/
|
28
|
+
target = Point2D.new($1.to_i, $2.to_i)
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
@depth = depth
|
33
|
+
@target = target
|
34
|
+
|
35
|
+
def erode(x)
|
36
|
+
return (x + @depth) % 20183
|
37
|
+
end
|
38
|
+
|
39
|
+
grid = Grid.new(target.x + EXTRAX + 1, target.y + EXTRAY + 1)
|
40
|
+
grid[0,0] = 0
|
41
|
+
|
42
|
+
(1..target.x + EXTRAX).each { |x|
|
43
|
+
grid[0,x] = erode(x * 16807)
|
44
|
+
}
|
45
|
+
(1..target.y + EXTRAY).each { |y|
|
46
|
+
grid[y,0] = erode(y * 48271)
|
47
|
+
}
|
48
|
+
|
49
|
+
(1..target.y + EXTRAY).each { |y|
|
50
|
+
(1..target.x + EXTRAX).each { |x|
|
51
|
+
if target.x == x && target.y == y
|
52
|
+
grid[y,x] = erode(0)
|
53
|
+
else
|
54
|
+
grid[y,x] = erode(grid[y-1,x] * grid[y,x-1])
|
55
|
+
end
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
puts "Part 1: #{grid[0..target.y, 0..target.x].flatten.sum { |g| g % 3 }}"
|
60
|
+
|
61
|
+
if verbose
|
62
|
+
grid[0..target.y, 0..target.x].each { |y|
|
63
|
+
y.each { |c|
|
64
|
+
case c % 3
|
65
|
+
when 0
|
66
|
+
print '.'
|
67
|
+
when 1
|
68
|
+
print '='
|
69
|
+
when 2
|
70
|
+
print '|'
|
71
|
+
end
|
72
|
+
}
|
73
|
+
puts
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Part 2
|
79
|
+
#
|
80
|
+
|
81
|
+
neighter = 0
|
82
|
+
torch = 1
|
83
|
+
gear = 2
|
84
|
+
|
85
|
+
toolGrid = [0,1,2,4].map { |t| Grid.new(target.x + EXTRAX + 1, target.y + EXTRAY + 1, -1)}
|
86
|
+
|
87
|
+
toolGrid[torch][0,0] = 0
|
88
|
+
|
89
|
+
define_method :toChar do |p|
|
90
|
+
case grid[p] % 3
|
91
|
+
when 0
|
92
|
+
'.'
|
93
|
+
when 1
|
94
|
+
'='
|
95
|
+
when 2
|
96
|
+
'|'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
define_method :supportedTools do |p|
|
101
|
+
|
102
|
+
case grid[p] % 3
|
103
|
+
when 0 # rocky
|
104
|
+
[gear, torch]
|
105
|
+
when 1 # wet
|
106
|
+
[neighter, gear]
|
107
|
+
when 2 # narrow
|
108
|
+
[neighter, torch]
|
109
|
+
else
|
110
|
+
raise
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
q = [[Point2D.new(0,0), torch]]
|
115
|
+
while q.size > 0
|
116
|
+
|
117
|
+
p, tool = q.shift
|
118
|
+
|
119
|
+
#puts "#{p.inspect} - #{tool} - #{toolGrid[tool][p]} - #{supportedTools(p)}"
|
120
|
+
|
121
|
+
sTools = supportedTools(p)
|
122
|
+
otherTools = ([0,1,2] - [tool]) & supportedTools(p)
|
123
|
+
|
124
|
+
otherTools.each { |t|
|
125
|
+
raise if t == tool
|
126
|
+
raise if !sTools.any? { |t2| t == t2 }
|
127
|
+
}
|
128
|
+
|
129
|
+
raise if toolGrid[tool][p] == -1
|
130
|
+
|
131
|
+
otherTools.each { |other|
|
132
|
+
if (toolGrid[other][p] == -1) || toolGrid[tool][p] + 7 < toolGrid[other][p]
|
133
|
+
toolGrid[other][p] = toolGrid[tool][p] + 7
|
134
|
+
q << [p, other]
|
135
|
+
end
|
136
|
+
}
|
137
|
+
|
138
|
+
grid.nsew_index(p).each { |p2|
|
139
|
+
# puts "#{p2.inspect} is adjacent to #{p} and supports the following tools #{supportedTools(p2)}"
|
140
|
+
|
141
|
+
if supportedTools(p2).include?(tool) && (toolGrid[tool][p2] == -1 || toolGrid[tool][p] + 1 < toolGrid[tool][p2])
|
142
|
+
toolGrid[tool][p2] = toolGrid[tool][p] + 1
|
143
|
+
q << [p2, tool]
|
144
|
+
end
|
145
|
+
}
|
146
|
+
|
147
|
+
q.sort_by! { |n|
|
148
|
+
p, tool = n
|
149
|
+
toolGrid[tool][p]
|
150
|
+
}
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
puts "Part 2: #{[toolGrid[torch][target], toolGrid[gear][target] + 7].min}"
|
155
|
+
|
156
|
+
if 0 == 1
|
157
|
+
(0..target.y + EXTRAY).each { |y|
|
158
|
+
(0..target.x + EXTRAX).each { |x|
|
159
|
+
|
160
|
+
case grid[y,x] % 3
|
161
|
+
|
162
|
+
when 0
|
163
|
+
print '.'
|
164
|
+
when 1
|
165
|
+
print '='
|
166
|
+
when 2
|
167
|
+
print '|'
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
print (toolGrid[torch][y,x].to_s + "," + toolGrid[neighter][y,x].to_s + "," +toolGrid[gear][y,x].to_s).rjust(8)
|
172
|
+
}
|
173
|
+
puts ""
|
174
|
+
} if DEBUG
|
175
|
+
|
176
|
+
reversePath = [[target, toolGrid[torch][target], torch]]
|
177
|
+
p = target
|
178
|
+
curTool = torch
|
179
|
+
while !(p.x == 0 && p.y == 0)
|
180
|
+
|
181
|
+
moves = grid.nsew_index(p).select { |p2| supportedTools(p2).include?(curTool) }.map { |p2| [p2, toolGrid[curTool][p2], curTool]} +
|
182
|
+
(supportedTools(p) - [curTool]).map { |t| [p, toolGrid[t][p], t, :toolChange] }
|
183
|
+
|
184
|
+
p moves
|
185
|
+
bestMove = moves.min_by { |x| x[1] }
|
186
|
+
|
187
|
+
reversePath.unshift bestMove
|
188
|
+
|
189
|
+
# puts p.inspect
|
190
|
+
|
191
|
+
p = bestMove[0]
|
192
|
+
curTool = bestMove[2]
|
193
|
+
end
|
194
|
+
|
195
|
+
reversePath.each { |x|
|
196
|
+
puts "[#{x[0].x}, #{x[0].y}, #{x[2]}] #{toChar(x[0])} #{x[1]} #{x.size > 3 ? x[3] : ""}"
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
|
211
|
+
|
212
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
#
|
2
|
+
# https://adventofcode.com/2018/day/23 part 1 and part 2
|
3
|
+
#
|
4
|
+
# Uses Point3D. I probably need to revisit how to subclass Point3D, Point2D.
|
5
|
+
#
|
6
|
+
require 'cem'
|
7
|
+
|
8
|
+
Bot = Struct.new("Bot", :x, :y, :z, :r) {
|
9
|
+
|
10
|
+
def [](i)
|
11
|
+
case i
|
12
|
+
when 0
|
13
|
+
x
|
14
|
+
when 1
|
15
|
+
y
|
16
|
+
when 2
|
17
|
+
z
|
18
|
+
when 3
|
19
|
+
r
|
20
|
+
else
|
21
|
+
raise
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
}
|
26
|
+
|
27
|
+
def manhattan(other, bot)
|
28
|
+
(other.z - bot.z).abs + (other.y - bot.y).abs + (other.x - bot.x).abs
|
29
|
+
end
|
30
|
+
|
31
|
+
def manhattan_box(bot, min, max)
|
32
|
+
|
33
|
+
result = (0..2).sum { |i|
|
34
|
+
if bot[i] >= min[i] && bot[i] <= max[i]
|
35
|
+
0
|
36
|
+
elsif bot[i] < min[i]
|
37
|
+
min[i] - bot[i]
|
38
|
+
else
|
39
|
+
bot[i] - max[i]
|
40
|
+
end
|
41
|
+
}
|
42
|
+
|
43
|
+
#puts "#{bot.inspect} - #{min} - #{max} - #{result}"
|
44
|
+
return result
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
lines = File.readlines("inputs/day23_input.txt", chomp: true)
|
49
|
+
|
50
|
+
input = []
|
51
|
+
|
52
|
+
lines.each { |line|
|
53
|
+
|
54
|
+
if line =~ /^pos=<([+-]?\d+),([+-]?\d+),([+-]?\d+)>, r=([+-]?\d+)$/
|
55
|
+
v1 = $1.to_i
|
56
|
+
v2 = $2.to_i
|
57
|
+
v3 = $3.to_i
|
58
|
+
v4 = $4.to_i
|
59
|
+
|
60
|
+
input << Bot.new(v1,v2,v3,v4)
|
61
|
+
end
|
62
|
+
|
63
|
+
}
|
64
|
+
|
65
|
+
#
|
66
|
+
# Part I
|
67
|
+
#
|
68
|
+
bot = input.max_by { |bot| bot.r }
|
69
|
+
|
70
|
+
strength = 0
|
71
|
+
input.each { |other|
|
72
|
+
|
73
|
+
if manhattan(bot, other) <= bot.r
|
74
|
+
strength += 1
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
puts "Part I: #{strength}"
|
79
|
+
|
80
|
+
#
|
81
|
+
# Part II
|
82
|
+
#
|
83
|
+
|
84
|
+
# Start with the largest group we can trivially find
|
85
|
+
best = []
|
86
|
+
bestScore = -1
|
87
|
+
|
88
|
+
min = Point3D.new(*[0,1,2].map { |i| input.map { |b| b[i] }.min })
|
89
|
+
max = Point3D.new(*[0,1,2].map { |i| input.map { |b| b[i] }.max })
|
90
|
+
|
91
|
+
todo = []
|
92
|
+
|
93
|
+
# todo == [ queue of [Box min, Box max, number of elements fully covering box, number of elements still under considerations] ]
|
94
|
+
todo << [min, max, 0, input]
|
95
|
+
|
96
|
+
i = 0
|
97
|
+
while todo.size > 0
|
98
|
+
|
99
|
+
mi, ma, covered, bots = todo.shift
|
100
|
+
|
101
|
+
puts "Iteration #{i} - Still todo: #{todo.size} - Cover: #{covered} Bots: #{bots.size} Cur Size: #{(ma-mi).manhattan} - BestScore: #{bestScore}" if i % 128 == 0
|
102
|
+
i += 1
|
103
|
+
|
104
|
+
if mi == ma
|
105
|
+
hit, miss = bots.partition { |bot| manhattan(bot, mi) <= bot.r }
|
106
|
+
|
107
|
+
if bestScore < covered + hit.size
|
108
|
+
bestScore = covered + hit.size
|
109
|
+
best = [mi]
|
110
|
+
elsif bestScore == covered + hit.size
|
111
|
+
best << mi
|
112
|
+
end
|
113
|
+
|
114
|
+
next
|
115
|
+
end
|
116
|
+
|
117
|
+
# Which bots do touch the current min-max box
|
118
|
+
hit, miss = bots.partition { |bot| manhattan_box(bot, mi, ma) <= bot.r }
|
119
|
+
next if covered + hit.size < bestScore # We don't have to dig in, if we have a better high score anyway
|
120
|
+
|
121
|
+
# Which bots do completely cover the entire box and which don't? Check 8 corners to find out
|
122
|
+
corners = (0..7).map { |i| Point3D.new(i & 4 == 0 ? mi.x : ma.x, i & 2 == 0 ? mi.y : ma.y, i & 1 == 0 ? mi.z : ma.z) }
|
123
|
+
total, partial = hit.partition { |bot| corners.count { |c| manhattan(bot, c) <= bot.r } == 8 }
|
124
|
+
|
125
|
+
# Split the largest dimension of the box in half (mi to midI, midA to ma)
|
126
|
+
minDim = [0,1,2].max_by { |i| ma[i] - mi[i] }
|
127
|
+
|
128
|
+
midI = ma.clone
|
129
|
+
midI[minDim] = mi[minDim] + (ma[minDim] - mi[minDim]) / 2
|
130
|
+
|
131
|
+
midA = mi.clone
|
132
|
+
midA[minDim] = mi[minDim] + (ma[minDim] - mi[minDim]) / 2 + 1
|
133
|
+
|
134
|
+
todo << [mi, midI, covered + total.size, partial]
|
135
|
+
todo << [midA, ma, covered + total.size, partial]
|
136
|
+
|
137
|
+
todo.sort_by! { |t| -(t[2] + t[3].size) * (max-min).manhattan + manhattan(t[0], t[1]) } if i % 4 == 0
|
138
|
+
end
|
139
|
+
|
140
|
+
puts "Best Positions: " + best.to_s
|
141
|
+
puts "Number of Bots In Range: #{bestScore}"
|
142
|
+
puts "Lowest Manhattan Distance to 0,0,0: #{best.map { |b| b.manhattan }.min}"
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
|