Add updated solutions, including day 20.
This commit is contained in:
parent
77c91f8386
commit
32895b3e17
27
day15.cr
27
day15.cr
@ -2,27 +2,14 @@ require "advent"
|
|||||||
INPUT = input(2020, 15).split(",").map(&.to_i32)
|
INPUT = input(2020, 15).split(",").map(&.to_i32)
|
||||||
|
|
||||||
def run(input, times)
|
def run(input, times)
|
||||||
ls = {} of Int32 => {Int32,Int32}
|
ls = {} of Int32 => Int32
|
||||||
last = 0
|
temp = 0
|
||||||
input.each_with_index do |n, i|
|
(times-1).times do |i|
|
||||||
ls[n] ||= {-1,-1}
|
n = input[i]? || temp
|
||||||
f,s = ls[n]
|
temp = i - (ls[n]? || i)
|
||||||
ls[n] = {i,f}
|
ls[n] = i
|
||||||
last = n
|
|
||||||
end
|
end
|
||||||
count = input.size
|
return temp
|
||||||
while count < times
|
|
||||||
n = 0
|
|
||||||
if ls[last][1] != -1
|
|
||||||
n = ls[last][0] - ls[last][1]
|
|
||||||
end
|
|
||||||
last = n
|
|
||||||
ls[n] ||= {-1,-1}
|
|
||||||
f,s = ls[n]
|
|
||||||
ls[n] = {count,f}
|
|
||||||
count += 1
|
|
||||||
end
|
|
||||||
last
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def part1(input)
|
def part1(input)
|
||||||
|
51
day17.cr
51
day17.cr
@ -1,46 +1,47 @@
|
|||||||
require "advent"
|
require "advent"
|
||||||
|
require "benchmark"
|
||||||
|
|
||||||
INPUT = input(2020, 17).lines.map(&.chars)
|
INPUT = input(2020, 17).lines.map(&.chars)
|
||||||
|
|
||||||
def part1(input)
|
def solve(input, dim)
|
||||||
step = input.clone
|
step = input.clone
|
||||||
cubes = Set({Int32,Int32,Int32,Int32}).new
|
cubes = Set(Array(Int32)).new
|
||||||
new_cubes = Set({Int32,Int32,Int32,Int32}).new
|
new_cubes = Set(Array(Int32)).new
|
||||||
input.each_with_index do |row, y|
|
input.each_with_index do |row, y|
|
||||||
row.each_with_index do |c, x|
|
row.each_with_index do |c, x|
|
||||||
cubes << {x,y,0,0} if c == '#'
|
cubes << [x,y].concat([0] * (dim-2)) if c == '#'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
6.times do |i|
|
8.times do |i|
|
||||||
neighbor_count = {} of {Int32,Int32,Int32,Int32} => Int32
|
print '.'
|
||||||
cubes.each do |c|
|
neighbor_count = Hash(Array(Int32), Int32).new(0)
|
||||||
x,y,z,w = c
|
Array.product([[-1,0,1]] * dim).each do |diff|
|
||||||
(-1..1).each do |dx|
|
next if diff.all? &.==(0)
|
||||||
(-1..1).each do |dy|
|
cubes.each do |c|
|
||||||
(-1..1).each do |dz|
|
neighbor_count[c.zip_with(diff) { |a,b| a+b }] += 1
|
||||||
(-1..1).each do |dw|
|
|
||||||
next if dx == 0 && dy == 0 && dz == 0 && dw == 0
|
|
||||||
neighbor_count[{x+dx,y+dy,z+dz,w+dw}] = (neighbor_count[{x+dx,y+dy,z+dz,w+dw}]? || 0) + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
new_cubes.clear
|
new_cubes.clear
|
||||||
neighbor_count.each do |n, i|
|
neighbor_count.each do |n, i|
|
||||||
if cubes.includes?(n)
|
new_cubes << n if i == 3 || (cubes.includes?(n) && i == 2)
|
||||||
new_cubes << n if (i == 2 || i == 3)
|
|
||||||
elsif i == 3
|
|
||||||
new_cubes << n
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
new_cubes, cubes = cubes, new_cubes
|
new_cubes, cubes = cubes, new_cubes
|
||||||
end
|
end
|
||||||
cubes.size
|
cubes.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def part2(input)
|
def part1(input)
|
||||||
|
solve(input, 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
puts part1(INPUT.clone)
|
def part2(input)
|
||||||
puts part2(INPUT.clone)
|
solve(input, 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
(3..).each do |i|
|
||||||
|
print "Dim #{i} "
|
||||||
|
bm = Benchmark.measure { puts " #{solve(INPUT, i)}" }
|
||||||
|
puts bm.real * 1000
|
||||||
|
end
|
||||||
|
54
day18.cr
Normal file
54
day18.cr
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
require "advent"
|
||||||
|
INPUT = input(2020, 18).lines
|
||||||
|
|
||||||
|
class Array(T)
|
||||||
|
def push_op(op)
|
||||||
|
r = pop
|
||||||
|
l = pop
|
||||||
|
self << ((op == '*') ? (l*r) : (l+r))
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_op?
|
||||||
|
!empty? && last != '('
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def translate(toks, prec)
|
||||||
|
output = [] of Int64
|
||||||
|
stack = [] of Char
|
||||||
|
toks.each do |tok|
|
||||||
|
case tok
|
||||||
|
when .number? then output << tok.to_i64
|
||||||
|
when '(' then stack << '('
|
||||||
|
when ')'
|
||||||
|
while stack.has_op?
|
||||||
|
output.push_op(stack.pop)
|
||||||
|
end
|
||||||
|
stack.pop
|
||||||
|
else
|
||||||
|
while stack.has_op? && prec[stack.last] < prec[tok]
|
||||||
|
output.push_op(stack.pop)
|
||||||
|
end
|
||||||
|
stack << tok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
while stack.has_op?
|
||||||
|
output.push_op(stack.pop)
|
||||||
|
end
|
||||||
|
output.last
|
||||||
|
end
|
||||||
|
|
||||||
|
def part1(input)
|
||||||
|
input.sum do |line|
|
||||||
|
translate(line.chars.reject &.==(' '), {'*' => 0, '+' => 0})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def part2(input)
|
||||||
|
input.sum do |line|
|
||||||
|
translate(line.chars.reject &.==(' '), {'*' => 1, '+' => 0})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
puts part1(INPUT.clone)
|
||||||
|
puts part2(INPUT.clone)
|
68
day19.cr
Normal file
68
day19.cr
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
require "advent"
|
||||||
|
|
||||||
|
rlines, _, strings = input(2020, 19).partition("\n\n")
|
||||||
|
strings = strings.lines
|
||||||
|
rules = {} of String => String
|
||||||
|
rlines.lines.map do |l|
|
||||||
|
rule, _, text = l.partition(": ")
|
||||||
|
rules[rule] = text
|
||||||
|
end
|
||||||
|
|
||||||
|
alias Matcher = Proc(String,Int32,Array(Int32))
|
||||||
|
|
||||||
|
def char(c)
|
||||||
|
->(str : String, i : Int32) { str[i]? == c ? [i+1] : [] of Int32 }
|
||||||
|
end
|
||||||
|
|
||||||
|
def any(ps)
|
||||||
|
->(str : String, i : Int32) { ps.flat_map { |p| p.call(str, i) } }
|
||||||
|
end
|
||||||
|
|
||||||
|
def seq(ps)
|
||||||
|
->(str : String, i : Int32) {
|
||||||
|
base = [i]
|
||||||
|
ps.each do |p|
|
||||||
|
base = base.flat_map { |i| p.call(str, i) }
|
||||||
|
end
|
||||||
|
base
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_regex(rules, rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_rule(rules, built, rule) : Matcher
|
||||||
|
if exists = built[rule]?
|
||||||
|
return exists
|
||||||
|
end
|
||||||
|
|
||||||
|
body = rules[rule]
|
||||||
|
return built[rule] = char body[1] if body.matches? /"."/
|
||||||
|
|
||||||
|
branches = [] of Matcher
|
||||||
|
top = any(branches)
|
||||||
|
built[rule] = top
|
||||||
|
branches.concat(body.split(" | ").map { |b| seq(b.split(" ").map { |subrule| build_rule(rules, built, subrule) }) })
|
||||||
|
top
|
||||||
|
end
|
||||||
|
|
||||||
|
def part1(input)
|
||||||
|
rules, lines = input
|
||||||
|
matcher = build_rule(rules, {} of String => Matcher, "0")
|
||||||
|
lines.count do |l|
|
||||||
|
matcher.call(l, 0).includes? l.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def part2(input)
|
||||||
|
rules, lines = input
|
||||||
|
rules["8"] = "42 | 42 8"
|
||||||
|
rules["11"] = "42 31 | 42 11 31"
|
||||||
|
matcher = build_rule(rules, {} of String => Matcher, "0")
|
||||||
|
lines.count do |l|
|
||||||
|
matcher.call(l, 0).includes? l.size
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
puts part1({rules,strings})
|
||||||
|
puts part2({rules,strings})
|
166
day20.cr
Normal file
166
day20.cr
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
require "advent"
|
||||||
|
tiles = input(2020, 20).split "\n\n"
|
||||||
|
tiles.pop
|
||||||
|
thash = {} of Int32 => Array(Array(Char))
|
||||||
|
tiles = tiles.map do |t|
|
||||||
|
tl = t.lines
|
||||||
|
tid = tl[0].match(/Tile (\d+):/).not_nil![1].to_i32
|
||||||
|
tls = tl[1..]
|
||||||
|
thash[tid] = tls.map &.chars
|
||||||
|
end
|
||||||
|
|
||||||
|
class Array(T)
|
||||||
|
def matches?(other)
|
||||||
|
zip_with(other) { |l,r| l == r }.all?
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotate
|
||||||
|
reverse.transpose
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check(side_a, side_b)
|
||||||
|
return :normal if side_a.matches?(side_b)
|
||||||
|
return :flip if side_a.matches?(side_b.reverse)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_all(side_a, other, other_t)
|
||||||
|
check(side_a, other.first) || check(side_a, other.last) || check(side_a, other_t.first) || check(side_a, other_t.last)
|
||||||
|
end
|
||||||
|
|
||||||
|
MONSTER = [ {0, 1}, {1, 0}, {4, 0}, {5, 1}, {6, 1}, {7, 0}, {10, 0}, {11,1}, {12, 1}, {13, 0}, {16, 0},
|
||||||
|
{17, 1}, {18, 1}, {18, 2}, {19, 1} ]
|
||||||
|
|
||||||
|
def stitch(m, thash, corner)
|
||||||
|
image = Array(Array(Char)).new(12*8) do |y|
|
||||||
|
Array(Char).new(12*8) do |x|
|
||||||
|
'.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tile = thash[corner]
|
||||||
|
tile_id = corner
|
||||||
|
tile.reverse! if m[corner].has_key? :top
|
||||||
|
tile.each &.reverse! if m[corner].has_key? :left
|
||||||
|
|
||||||
|
12.times do |row|
|
||||||
|
tile = tile.not_nil!
|
||||||
|
|
||||||
|
row_tile = tile
|
||||||
|
row_id = tile_id
|
||||||
|
|
||||||
|
12.times do |col|
|
||||||
|
row_tile = row_tile.not_nil!
|
||||||
|
|
||||||
|
(0..7).each do |y|
|
||||||
|
(0..7).each do |x|
|
||||||
|
image[col*8+y][row*8+x] = row_tile[y+1][x+1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
matches = nil
|
||||||
|
thash.each do |other_id, other_tile|
|
||||||
|
next if matches
|
||||||
|
next if other_id == row_id
|
||||||
|
4.times do
|
||||||
|
if row_tile.last.matches? other_tile.first
|
||||||
|
row_id = other_id
|
||||||
|
matches = other_tile
|
||||||
|
elsif row_tile.last.matches? other_tile.first.reverse
|
||||||
|
row_id = other_id
|
||||||
|
matches = other_tile.map &.reverse
|
||||||
|
end
|
||||||
|
other_tile = other_tile.rotate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
row_tile = matches
|
||||||
|
end
|
||||||
|
|
||||||
|
rot = tile.rotate
|
||||||
|
matches = nil
|
||||||
|
thash.each do |other_id, other_tile|
|
||||||
|
next if matches
|
||||||
|
next if other_id == tile_id
|
||||||
|
|
||||||
|
4.times do
|
||||||
|
if rot.last.matches? other_tile.first
|
||||||
|
tile_id = other_id
|
||||||
|
matches = other_tile.rotate.rotate.rotate
|
||||||
|
elsif rot.last.matches? other_tile.first.reverse
|
||||||
|
tile_id = other_id
|
||||||
|
matches = other_tile.map(&.reverse).rotate.rotate.rotate
|
||||||
|
end
|
||||||
|
other_tile = other_tile.rotate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
tile = matches
|
||||||
|
end
|
||||||
|
image
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_dragons(stitch)
|
||||||
|
dragons = [] of {Int32,Int32}
|
||||||
|
stitch.each_with_index do |row, y|
|
||||||
|
row.each_with_index do |c, x|
|
||||||
|
is_dragon = MONSTER.all? do |dx, dy|
|
||||||
|
(stitch[y+dy]?.try &.[x+dx]?) == '#'
|
||||||
|
end
|
||||||
|
dragons << {x,y} if is_dragon
|
||||||
|
end
|
||||||
|
end
|
||||||
|
dragons
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_all_dragons(stitch)
|
||||||
|
dragons = [] of {Int32,Int32}
|
||||||
|
4.times do
|
||||||
|
dragons.concat find_dragons(stitch)
|
||||||
|
dragons.concat find_dragons(stitch.reverse)
|
||||||
|
stitch = stitch.rotate
|
||||||
|
end
|
||||||
|
dragons
|
||||||
|
end
|
||||||
|
|
||||||
|
def match(thash, tile)
|
||||||
|
matches = {} of Symbol => {Int32, Symbol}
|
||||||
|
cs = thash[tile]
|
||||||
|
tcs = cs.transpose
|
||||||
|
|
||||||
|
thash.each do |t, ocs|
|
||||||
|
next if t == tile
|
||||||
|
tocs = ocs.transpose
|
||||||
|
top = check_all(cs.first, ocs, tocs)
|
||||||
|
bottom = check_all(cs.last, ocs, tocs)
|
||||||
|
left = check_all(tcs.first, ocs, tocs)
|
||||||
|
right = check_all(tcs.last, ocs, tocs)
|
||||||
|
|
||||||
|
matches[:top] = {t, top} if top
|
||||||
|
matches[:left] = {t, left} if left
|
||||||
|
matches[:bottom] = {t, bottom} if bottom
|
||||||
|
matches[:right] = {t, right} if right
|
||||||
|
end
|
||||||
|
matches
|
||||||
|
end
|
||||||
|
|
||||||
|
def part1(input)
|
||||||
|
corners = input.select do |t, i|
|
||||||
|
match(input, t).size == 2
|
||||||
|
end
|
||||||
|
corners.keys.map(&.to_i64).product
|
||||||
|
end
|
||||||
|
|
||||||
|
def part2(input)
|
||||||
|
matches = {} of Int32 => Hash(Symbol, {Int32, Symbol})
|
||||||
|
corners = input.select do |t, i|
|
||||||
|
matches[t] = match(input, t)
|
||||||
|
match(input, t).size == 2
|
||||||
|
end
|
||||||
|
stitched = stitch(matches, input, corners.first[0])
|
||||||
|
dragons = find_all_dragons(stitched)
|
||||||
|
stitched.sum(&.count(&.==('#'))) - (dragons.size * MONSTER.size)
|
||||||
|
end
|
||||||
|
|
||||||
|
puts part1(thash.clone)
|
||||||
|
puts part2(thash.clone)
|
Loading…
Reference in New Issue
Block a user