cem 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|