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,113 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/18 part 1 and 2
|
4
|
+
#
|
5
|
+
# Demonstrates Grid and Object#peql. For an rspec based variant see day18_rspec.rb
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'cem'
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
def run(inputFilename, part1, debug)
|
12
|
+
|
13
|
+
lines = []
|
14
|
+
File.readlines(inputFilename, chomp: true).each { |line|
|
15
|
+
lines << line.rstrip
|
16
|
+
}
|
17
|
+
|
18
|
+
maxY = lines.size
|
19
|
+
maxX = lines[0].length
|
20
|
+
|
21
|
+
@m = Grid.new(maxX, maxY, '.')
|
22
|
+
|
23
|
+
@map = []
|
24
|
+
lines.each_with_index { |l, y|
|
25
|
+
result = []
|
26
|
+
|
27
|
+
l.chars.each_with_index { |c, x|
|
28
|
+
result << c
|
29
|
+
@m[y,x] = c
|
30
|
+
}
|
31
|
+
@map << result
|
32
|
+
}
|
33
|
+
|
34
|
+
puts "Initial State" if debug
|
35
|
+
puts @m if debug
|
36
|
+
|
37
|
+
intermediates = Set.new
|
38
|
+
|
39
|
+
startIteration = nil
|
40
|
+
periodicity = nil
|
41
|
+
tickResultCache = nil
|
42
|
+
|
43
|
+
# Read board
|
44
|
+
(1..1000000000).each { |i|
|
45
|
+
|
46
|
+
@m2 = @m.clone
|
47
|
+
|
48
|
+
@map.each_with_index { |l, y|
|
49
|
+
|
50
|
+
l.each_with_index { |c, x|
|
51
|
+
|
52
|
+
# puts "Adja: #{x} #{y}"
|
53
|
+
ajda = @m.adja_index(x,y)
|
54
|
+
case @m[y,x]
|
55
|
+
when '.'
|
56
|
+
@m2[y,x] = ajda.select { |p| @m[p] == '|' }.size >= 3 ? '|' : '.'
|
57
|
+
when '|'
|
58
|
+
@m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 3 ? '#' : '|'
|
59
|
+
when '#'
|
60
|
+
@m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 1 && ajda.select { |p| @m[p] == '|' }.size >= 1 ? '#' : '.'
|
61
|
+
end
|
62
|
+
|
63
|
+
puts "#{y} #{x} was #{@m[y,x]} is now #{@m2[y,x]}: #{ajda.inspect}" if debug
|
64
|
+
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
@m = @m2
|
69
|
+
|
70
|
+
if part1 && i == 10
|
71
|
+
puts "Part 1: Score after #{i} tick is #{@m.count('#') * @m.count('|')}" # if debug
|
72
|
+
break
|
73
|
+
end
|
74
|
+
|
75
|
+
puts @m if debug if debug
|
76
|
+
gets if debug
|
77
|
+
|
78
|
+
if !part1
|
79
|
+
tickResult = @m.to_a
|
80
|
+
|
81
|
+
if periodicity == nil && tickResultCache == tickResult
|
82
|
+
periodicity = i - startIteration
|
83
|
+
# puts periodicity
|
84
|
+
elsif periodicity
|
85
|
+
if ((1000000000 - i) % periodicity) == 0
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
if startIteration == nil && intermediates.include?(tickResult)
|
91
|
+
startIteration = i
|
92
|
+
tickResultCache = tickResult
|
93
|
+
elsif startIteration == nil
|
94
|
+
intermediates.add(tickResult)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
}
|
99
|
+
|
100
|
+
@m.count('#') * @m.count('|')
|
101
|
+
end
|
102
|
+
|
103
|
+
debug = false
|
104
|
+
|
105
|
+
{
|
106
|
+
"inputs/day18_test.txt" => [1147, 0],
|
107
|
+
"inputs/day18_input.txt" => [589931, 222332],
|
108
|
+
}.each_pair { |k,v|
|
109
|
+
|
110
|
+
peql(run(k, true, debug), v[0], "Testing #{k.inspect} part 1")
|
111
|
+
peql(run(k, false, debug), v[1], "Testing #{k.inspect} part 2")
|
112
|
+
|
113
|
+
}
|
@@ -0,0 +1,131 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# https://adventofcode.com/2018/day/18 part 1 and 2
|
4
|
+
#
|
5
|
+
# Demonstrates Grid and Object#peql. For a variant without rspec see day18.rb
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'cem'
|
9
|
+
require 'set'
|
10
|
+
|
11
|
+
def run(inputFilename, part1, debug)
|
12
|
+
|
13
|
+
lines = []
|
14
|
+
File.readlines(inputFilename, chomp: true).each { |line|
|
15
|
+
lines << line.rstrip
|
16
|
+
}
|
17
|
+
|
18
|
+
maxY = lines.size
|
19
|
+
maxX = lines[0].length
|
20
|
+
|
21
|
+
@m = Grid.new(maxX, maxY, '.')
|
22
|
+
|
23
|
+
@map = []
|
24
|
+
lines.each_with_index { |l, y|
|
25
|
+
result = []
|
26
|
+
|
27
|
+
l.chars.each_with_index { |c, x|
|
28
|
+
result << c
|
29
|
+
@m[y,x] = c
|
30
|
+
}
|
31
|
+
@map << result
|
32
|
+
}
|
33
|
+
|
34
|
+
puts "Initial State" if debug
|
35
|
+
puts @m if debug
|
36
|
+
|
37
|
+
intermediates = Set.new
|
38
|
+
|
39
|
+
startIteration = nil
|
40
|
+
periodicity = nil
|
41
|
+
tickResultCache = nil
|
42
|
+
|
43
|
+
# Read board
|
44
|
+
(1..1000000000).each { |i|
|
45
|
+
|
46
|
+
@m2 = @m.clone
|
47
|
+
|
48
|
+
@map.each_with_index { |l, y|
|
49
|
+
|
50
|
+
l.each_with_index { |c, x|
|
51
|
+
|
52
|
+
# puts "Adja: #{x} #{y}"
|
53
|
+
ajda = @m.adja_index(x,y)
|
54
|
+
case @m[y,x]
|
55
|
+
when '.'
|
56
|
+
@m2[y,x] = ajda.select { |p| @m[p] == '|' }.size >= 3 ? '|' : '.'
|
57
|
+
when '|'
|
58
|
+
@m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 3 ? '#' : '|'
|
59
|
+
when '#'
|
60
|
+
@m2[y,x] = ajda.select { |p| @m[p] == '#' }.size >= 1 && ajda.select { |p| @m[p] == '|' }.size >= 1 ? '#' : '.'
|
61
|
+
end
|
62
|
+
|
63
|
+
puts "#{y} #{x} was #{@m[y,x]} is now #{@m2[y,x]}: #{ajda.inspect}" if debug
|
64
|
+
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
@m = @m2
|
69
|
+
|
70
|
+
if part1 && i == 10
|
71
|
+
puts "Part 1: Score after #{i} tick is #{@m.count('#') * @m.count('|')}" # if debug
|
72
|
+
break
|
73
|
+
end
|
74
|
+
|
75
|
+
puts @m if debug if debug
|
76
|
+
gets if debug
|
77
|
+
|
78
|
+
if !part1
|
79
|
+
tickResult = @m.to_a
|
80
|
+
|
81
|
+
if periodicity == nil && tickResultCache == tickResult
|
82
|
+
periodicity = i - startIteration
|
83
|
+
# puts periodicity
|
84
|
+
elsif periodicity
|
85
|
+
if ((1000000000 - i) % periodicity) == 0
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
if startIteration == nil && intermediates.include?(tickResult)
|
91
|
+
startIteration = i
|
92
|
+
tickResultCache = tickResult
|
93
|
+
elsif startIteration == nil
|
94
|
+
intermediates.add(tickResult)
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
}
|
99
|
+
|
100
|
+
@m.count('#') * @m.count('|')
|
101
|
+
end
|
102
|
+
|
103
|
+
debug = false
|
104
|
+
|
105
|
+
require 'rspec'
|
106
|
+
|
107
|
+
RSpec.configure do |config|
|
108
|
+
config.color = true # Use color in STDOUT
|
109
|
+
config.tty = true # Use color not only in STDOUT but also in pagers and files
|
110
|
+
config.formatter = :documentation
|
111
|
+
end
|
112
|
+
|
113
|
+
describe $__FILE__ do
|
114
|
+
|
115
|
+
{
|
116
|
+
"inputs/day18_test.txt" => [1147, 1],
|
117
|
+
"inputs/day18_input.txt" => [589931, 222332],
|
118
|
+
}.each_pair { |k,v|
|
119
|
+
|
120
|
+
it "testing #{k.inspect} part 1" do
|
121
|
+
expect(run(k, true, debug)).to eq(v[0])
|
122
|
+
end
|
123
|
+
|
124
|
+
it "testing #{k.inspect} part 2" do
|
125
|
+
expect(run(k, false, debug)).to eq(v[1])
|
126
|
+
end
|
127
|
+
}
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
RSpec::Core::Runner.run([$__FILE__])
|
@@ -0,0 +1,145 @@
|
|
1
|
+
#
|
2
|
+
# https://adventofcode.com/2018/day/19 part 1 and 2
|
3
|
+
#
|
4
|
+
|
5
|
+
# My code was too slow to handle this problem, so this is really more analytical from observing the state of the machine and figuring out what it does.
|
6
|
+
|
7
|
+
shortcut = true
|
8
|
+
if shortcut
|
9
|
+
|
10
|
+
result = 0
|
11
|
+
(1..930).each { |i|
|
12
|
+
result += i if 930 % i == 0
|
13
|
+
}
|
14
|
+
puts "Part 1: #{result}"
|
15
|
+
|
16
|
+
result = 0
|
17
|
+
(1..10551330).each { |i|
|
18
|
+
result += i if 10551330 % i == 0
|
19
|
+
}
|
20
|
+
puts "Part 2: #{result}"
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
[1,2].each { |part|
|
26
|
+
|
27
|
+
lines = File.readlines("inputs/day19_input.txt", chomp: true)
|
28
|
+
|
29
|
+
commandQueue = []
|
30
|
+
|
31
|
+
reg = [part - 1, 0, 0, 0, 0, 0]
|
32
|
+
|
33
|
+
ip = nil
|
34
|
+
lines.each { |line|
|
35
|
+
|
36
|
+
if line =~ /^#ip ([+-]?\d+)$/
|
37
|
+
ip = $1.to_i
|
38
|
+
end
|
39
|
+
|
40
|
+
if line =~ /^(\w+) ([+-]?\d+) ([+-]?\d+) ([+-]?\d+)$/
|
41
|
+
verb = $1
|
42
|
+
v1 = $2.to_i
|
43
|
+
v2 = $3.to_i
|
44
|
+
v3 = $4.to_i
|
45
|
+
|
46
|
+
commandQueue << [verb, v1, v2, v3]
|
47
|
+
end
|
48
|
+
}
|
49
|
+
|
50
|
+
if false
|
51
|
+
puts "Command queue:"
|
52
|
+
commandQueue.each { |x|
|
53
|
+
puts " " + x.inspect
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
ipp = 0
|
58
|
+
i = 0
|
59
|
+
reset = true
|
60
|
+
|
61
|
+
while ipp >= 0 && ipp < commandQueue.size
|
62
|
+
|
63
|
+
reg[ip] = ipp
|
64
|
+
command = commandQueue[ipp]
|
65
|
+
|
66
|
+
puts command.inspect + " " + reg.inspect if i % (256*1024) == 0
|
67
|
+
i += 1
|
68
|
+
|
69
|
+
case command[0]
|
70
|
+
|
71
|
+
when "addr"
|
72
|
+
# addr (add register) stores into register C the result of adding register A and register B.
|
73
|
+
reg[command[3]] = reg[command[1]] + reg[command[2]]
|
74
|
+
|
75
|
+
when "addi"
|
76
|
+
# addi (add immediate) stores into register C the result of adding register A and value B.
|
77
|
+
reg[command[3]] = reg[command[1]] + command[2]
|
78
|
+
|
79
|
+
when "mulr"
|
80
|
+
# mulr (multiply register) stores into register C the result of multiplying register A and register B.
|
81
|
+
reg[command[3]] = reg[command[1]] * reg[command[2]]
|
82
|
+
|
83
|
+
when "muli"
|
84
|
+
# muli (multiply immediate) stores into register C the result of multiplying register A and value B.
|
85
|
+
reg[command[3]] = reg[command[1]] * command[2]
|
86
|
+
|
87
|
+
when "banr"
|
88
|
+
# banr (bitwise AND register) stores into register C the result of the bitwise AND of register A and register B.
|
89
|
+
reg[command[3]] = reg[command[1]] & reg[command[2]]
|
90
|
+
|
91
|
+
when "bani"
|
92
|
+
# bani (bitwise AND immediate) stores into register C the result of the bitwise AND of register A and value B.
|
93
|
+
reg[command[3]] = reg[command[1]] & command[2]
|
94
|
+
|
95
|
+
when "borr"
|
96
|
+
# borr (bitwise OR register) stores into register C the result of the bitwise OR of register A and register B.
|
97
|
+
reg[command[3]] = reg[command[1]] | reg[command[2]]
|
98
|
+
|
99
|
+
when "bori"
|
100
|
+
# bori (bitwise OR immediate) stores into register C the result of the bitwise OR of register A and value B.
|
101
|
+
reg[command[3]] = reg[command[1]] | command[2]
|
102
|
+
|
103
|
+
when "setr"
|
104
|
+
# setr (set register) copies the contents of register A into register C. (Input B is ignored.)
|
105
|
+
reg[command[3]] = reg[command[1]]
|
106
|
+
|
107
|
+
when "seti"
|
108
|
+
# seti (set immediate) stores value A into register C. (Input B is ignored.)
|
109
|
+
reg[command[3]] = command[1]
|
110
|
+
|
111
|
+
when "gtir"
|
112
|
+
# 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.
|
113
|
+
reg[command[3]] = command[1] > reg[command[2]] ? 1 : 0
|
114
|
+
|
115
|
+
when "gtri"
|
116
|
+
# 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.
|
117
|
+
reg[command[3]] = reg[command[1]] > command[2] ? 1 : 0
|
118
|
+
|
119
|
+
when "gtrr"
|
120
|
+
# 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.
|
121
|
+
reg[command[3]] = reg[command[1]] > reg[command[2]] ? 1 : 0
|
122
|
+
|
123
|
+
when "eqir"
|
124
|
+
# eqir (equal immediate/register) sets register C to 1 if value A is equal to register B. Otherwise, register C is set to 0.
|
125
|
+
reg[command[3]] = command[1] == reg[command[2]] ? 1 : 0
|
126
|
+
|
127
|
+
when "eqri"
|
128
|
+
# eqri (equal register/immediate) sets register C to 1 if register A is equal to value B. Otherwise, register C is set to 0.
|
129
|
+
reg[command[3]] = reg[command[1]] == command[2] ? 1 : 0
|
130
|
+
|
131
|
+
when "eqrr"
|
132
|
+
# eqrr (equal register/register) sets register C to 1 if register A is equal to register B. Otherwise, register C is set to 0.
|
133
|
+
reg[command[3]] = reg[command[1]] == reg[command[2]] ? 1 : 0
|
134
|
+
|
135
|
+
else
|
136
|
+
raise "Error"
|
137
|
+
end
|
138
|
+
|
139
|
+
ipp = reg[ip]
|
140
|
+
ipp += 1
|
141
|
+
end
|
142
|
+
|
143
|
+
puts reg.inspect
|
144
|
+
puts "Part#{part}: #{reg[0]}"
|
145
|
+
}
|
@@ -0,0 +1,103 @@
|
|
1
|
+
#
|
2
|
+
# https://adventofcode.com/2018/day/20 part 1 and 2
|
3
|
+
#
|
4
|
+
# Took 1:10 min for both parts (not bad!)
|
5
|
+
#
|
6
|
+
# Could have been faster, but ruzzles parts had to be created for this:
|
7
|
+
#
|
8
|
+
# - Grid.minmax
|
9
|
+
# - Point2D.from_s
|
10
|
+
# - Point2D.to_dir_bitmask / from_dir_bitmask
|
11
|
+
# - Dirs2D
|
12
|
+
#
|
13
|
+
|
14
|
+
require 'cem'
|
15
|
+
|
16
|
+
line = File.read("inputs/day20_input.txt")
|
17
|
+
|
18
|
+
stack = [[Point2D.new(500,500)]]
|
19
|
+
|
20
|
+
grid = Grid.new(1000, 1000, 0)
|
21
|
+
|
22
|
+
line.chars.each { |c|
|
23
|
+
case c
|
24
|
+
|
25
|
+
when '$'
|
26
|
+
# ignore
|
27
|
+
when '^'
|
28
|
+
# ignore
|
29
|
+
when "\n"
|
30
|
+
# ignore
|
31
|
+
|
32
|
+
when '('
|
33
|
+
newCurCursor = stack.last.map { |p| p.dup }
|
34
|
+
stack << [] # One below top() are all cursors we collected as part of this opening brace group
|
35
|
+
stack << newCurCursor # Stack.top() is all current cursor position we are tracking
|
36
|
+
|
37
|
+
when ')'
|
38
|
+
lastGroup = stack.pop
|
39
|
+
otherGroupsInBrace = stack.pop
|
40
|
+
replacedGroup = stack.pop
|
41
|
+
stack << (lastGroup + otherGroupsInBrace).uniq
|
42
|
+
|
43
|
+
when 'E', 'N', 'S', 'W'
|
44
|
+
dir = Point2D.from_s(c)
|
45
|
+
|
46
|
+
stack.last.map! { |p|
|
47
|
+
grid[p] |= dir.to_dir_bitmask
|
48
|
+
p += dir
|
49
|
+
grid[p] |= dir.flip.to_dir_bitmask
|
50
|
+
p
|
51
|
+
}
|
52
|
+
when '|'
|
53
|
+
lastGroup = stack.pop
|
54
|
+
stack.last.concat lastGroup
|
55
|
+
stack << stack[-2].map { |p| p.dup }
|
56
|
+
|
57
|
+
else
|
58
|
+
raise "Unknown char '#{c.inspect}'"
|
59
|
+
end
|
60
|
+
}
|
61
|
+
|
62
|
+
if false # Print Grid for debugging
|
63
|
+
|
64
|
+
min, max = grid.minmax(0)
|
65
|
+
count = 0
|
66
|
+
|
67
|
+
(min.y..max.y).each {|y|
|
68
|
+
a = ""
|
69
|
+
b = ""
|
70
|
+
(min.x..max.x).each { |x|
|
71
|
+
count += 1 if grid[y,x] > 0
|
72
|
+
a += "#" + (grid[y,x] & 1 == 1 ? "|" : "#")
|
73
|
+
b += (grid[y,x] & 8 == 8 ? "-" : "#") + (grid[y,x] > 0 ? "." : "#")
|
74
|
+
}
|
75
|
+
puts a + "#"
|
76
|
+
puts b + "#"
|
77
|
+
}
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
# Run BFS search
|
82
|
+
q = [[Point2D.new(500,500), 0]]
|
83
|
+
|
84
|
+
maxSteps = 0
|
85
|
+
rooms = 0
|
86
|
+
while q.size > 0
|
87
|
+
p, maxSteps = q.shift
|
88
|
+
|
89
|
+
if maxSteps >= 1000
|
90
|
+
rooms += 1
|
91
|
+
end
|
92
|
+
|
93
|
+
Point2D.from_dir_bitmask(grid[p]).each { |dir|
|
94
|
+
grid[p+dir] &= ~dir.flip.to_dir_bitmask # Close door we walked through. Due to BFS, we never have to get to it again
|
95
|
+
|
96
|
+
q << [p+dir, maxSteps+1]
|
97
|
+
}
|
98
|
+
grid[p] = 0
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
puts "Part 1: #{maxSteps}"
|
103
|
+
puts "Part 2: #{rooms}"
|