main
parent
6db3326726
commit
5c2f1eb45f
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "2022/bqn/lib"]
|
||||||
|
path = 2022/bqn/lib
|
||||||
|
url = https://github.com/mlochbaum/bqn-libs.git
|
@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env jconsole
|
||||||
|
|
||||||
|
echo stdin
|
||||||
|
exit''
|
@ -0,0 +1,52 @@
|
|||||||
|
require "matrix"
|
||||||
|
require "set"
|
||||||
|
|
||||||
|
scanners = ARGF.read.strip.split("\n\n").to_h {|scanner|
|
||||||
|
id, *rest = scanner.split("\n")
|
||||||
|
id = id.scan(/\d+/)[0].to_i
|
||||||
|
coords = rest.map { _1.split(?,).map(&:to_i) }
|
||||||
|
[id, coords.map { Matrix.column_vector(_1) }]
|
||||||
|
}
|
||||||
|
|
||||||
|
first_scanner = scanners.shift
|
||||||
|
origin_beacon = first_scanner[1].first
|
||||||
|
origin_beacon = Matrix.column_vector([-618,-824,-621])
|
||||||
|
|
||||||
|
known_scanners = {
|
||||||
|
first_scanner[0] => [ origin_beacon.map { -_1 }, Matrix.identity(3) ],
|
||||||
|
}
|
||||||
|
known_beacons = Set.new(first_scanner[1].map {|beacon| beacon - origin_beacon })
|
||||||
|
|
||||||
|
rot_x = Matrix[ [1, 0, 0], [0, 0, -1], [0, 1, 0] ]
|
||||||
|
rot_y = Matrix[ [0, 0, 1], [0, 1, 0], [-1, 0, 0] ]
|
||||||
|
rot_z = Matrix[ [0, -1, 0], [1, 0, 0], [0, 0, 1] ]
|
||||||
|
id = Matrix.identity(3)
|
||||||
|
|
||||||
|
ROTATIONS = Set.new(
|
||||||
|
Array.new(4) { rot_x ** _1 }.flat_map {|x|
|
||||||
|
Array.new(4) { rot_y ** _1 }.flat_map {|y|
|
||||||
|
Array.new(4) { rot_z ** _1 }.map {|z| x * y * z }}}
|
||||||
|
)
|
||||||
|
|
||||||
|
def find_overlapping_scanner(known_beacons, scanners)
|
||||||
|
scanners.filter_map {|id, beacons|
|
||||||
|
haystack = ROTATIONS.flat_map {|r| beacons.map {|b| [ r*b, r ] }}
|
||||||
|
# haystack.select { _2 == Matrix.identity(3) }.map(&:first).each { p _1 }
|
||||||
|
haystack.find {|position, rotation|
|
||||||
|
translated_beacons = beacons.map { (rotation * _1) - position }
|
||||||
|
(known_beacons & translated_beacons).size >= 12
|
||||||
|
}&.then {|p,o| [id, p, o] }
|
||||||
|
}.first
|
||||||
|
end
|
||||||
|
|
||||||
|
until scanners.empty?
|
||||||
|
id, position, orientation = find_overlapping_scanner(known_beacons, scanners)
|
||||||
|
|
||||||
|
p [id, position, orientation]
|
||||||
|
|
||||||
|
known_scanners[id] = [position, orientation]
|
||||||
|
translated_beacons = scanners[id].map {|b| b.zip(position).map { _2 - _1 }.zip(orientation).map { _1 * _2 }}
|
||||||
|
known_beacons.merge(translated_beacons)
|
||||||
|
scanners.delete(id)
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,35 @@
|
|||||||
|
#############
|
||||||
|
#...........#
|
||||||
|
###B#C#B#D###
|
||||||
|
#A#D#C#A#
|
||||||
|
#########
|
||||||
|
|
||||||
|
#############
|
||||||
|
#...........#
|
||||||
|
###D#D#A#A###
|
||||||
|
#C#C#B#B#
|
||||||
|
#########
|
||||||
|
|
||||||
|
State = Struct.new(:spaces, :energy) do
|
||||||
|
ENERGY = { A: 1, B: 10, C: 100, D: 1000 }.transform_keys(&:to_s)
|
||||||
|
ROOMS = [2, 4, 6, 8]
|
||||||
|
|
||||||
|
def rooms = ROOMS.to_h { [_1, spaces.fetch(_1)] }
|
||||||
|
|
||||||
|
def valid_moves
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
spaces = Array.new(11) { [] }
|
||||||
|
# input = "DC DC AB AB"
|
||||||
|
input = "BA CD BC DA"
|
||||||
|
input.split(" ").map(&:chars).each.with_index do |amphipods, i|
|
||||||
|
spaces[(i+1) * 2] = amphipods
|
||||||
|
end
|
||||||
|
|
||||||
|
start = State.new(spaces, 0)
|
||||||
|
|
||||||
|
p start
|
||||||
|
p start.rooms
|
||||||
|
p start.valid_moves
|
@ -0,0 +1,58 @@
|
|||||||
|
INSTRUCTIONS = ARGF.read.split("\n").map { _1.split(/\s+/) }
|
||||||
|
|
||||||
|
# INSTRUCTIONS.each do |instruction, *args|
|
||||||
|
# a, b = *args
|
||||||
|
# case instruction
|
||||||
|
# when "inp"
|
||||||
|
# puts "#{a} = input.shift"
|
||||||
|
# when "add"
|
||||||
|
# puts "#{a} += #{b}"
|
||||||
|
# when "mul"
|
||||||
|
# puts "#{a} *= #{b}"
|
||||||
|
# when "div"
|
||||||
|
# puts "#{a} = (#{a} / #{b}.to_f).floor"
|
||||||
|
# when "mod"
|
||||||
|
# puts "#{a} %= #{b}"
|
||||||
|
# when "eql"
|
||||||
|
# puts "#{a} = #{a} == #{b} ? 1 : 0"
|
||||||
|
# else
|
||||||
|
# fail
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# exit
|
||||||
|
|
||||||
|
VARS = %w[ w x y z ]
|
||||||
|
def run(input)
|
||||||
|
vars = Hash.new(0)
|
||||||
|
|
||||||
|
INSTRUCTIONS.each do |instruction, *args|
|
||||||
|
a, b = *args
|
||||||
|
b = VARS.include?(b) ? vars[b] : b.to_i
|
||||||
|
case instruction
|
||||||
|
when "inp"
|
||||||
|
vars[a] = input.shift
|
||||||
|
when "add"
|
||||||
|
vars[a] += b
|
||||||
|
when "mul"
|
||||||
|
vars[a] *= b
|
||||||
|
when "div"
|
||||||
|
vars[a] = (vars[a] / b.to_f).floor
|
||||||
|
when "mod"
|
||||||
|
vars[a] %= b
|
||||||
|
when "eql"
|
||||||
|
vars[a] = vars[a] == b ? 1 : 0
|
||||||
|
else
|
||||||
|
fail
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vars
|
||||||
|
end
|
||||||
|
|
||||||
|
99999999999999.downto(11111111111111).lazy.map(&:to_s).reject { _1.include?(?0) }.each do |input|
|
||||||
|
vars = run(input.chars.map(&:to_i))
|
||||||
|
if vars[?z].zero?
|
||||||
|
puts input
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,262 @@
|
|||||||
|
def run(input)
|
||||||
|
w, x, y, z = 0, 0, 0, 0
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x = z % 26
|
||||||
|
# z = (z / 1.to_f).floor
|
||||||
|
# x += 13
|
||||||
|
# x = x == w ? 0 : 1
|
||||||
|
# y = 25 * x + 1 # either y = 26 or y = 1
|
||||||
|
# z *= y # 0
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y = (w + 13) * x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
# # puts
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x = z % 26
|
||||||
|
# z = (z / 1.to_f).floor
|
||||||
|
# x += 11
|
||||||
|
# x = x == w ? 0 : 1
|
||||||
|
# y = 25 * x + 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y = (w + 10) * x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
# # puts
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x = z % 26
|
||||||
|
# z = (z / 1.to_f).floor
|
||||||
|
# x += 15
|
||||||
|
# x = x == w ? 0 : 1
|
||||||
|
# y = (25 * x) + 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y = (w + 5) * x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
# # puts
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x = z % 26
|
||||||
|
# z = (z / 26.to_f).floor
|
||||||
|
# x += -11
|
||||||
|
# x = x == w ? 0 : 1
|
||||||
|
# y = (25 * x) + 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y = (w + 14) * x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
# # puts
|
||||||
|
|
||||||
|
# return [w, x, y, z]
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x = z % 26
|
||||||
|
# z = (z / 1.to_f).floor
|
||||||
|
# x += 14
|
||||||
|
# x = x == w ? 0 : 1
|
||||||
|
# y = 25 * x + 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y = (w + 5) * x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
# # puts
|
||||||
|
# # puts
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x = z % 26
|
||||||
|
# z = (z / 26.to_f).floor
|
||||||
|
# x += 0
|
||||||
|
# x = x == w ? 0 : 1
|
||||||
|
# y = 25 * x + 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y = (w + 15) * x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
# # puts
|
||||||
|
|
||||||
|
# return [w, x, y, z]
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x = z % 26
|
||||||
|
# z = (z / 1.to_f).floor
|
||||||
|
# x += 12
|
||||||
|
# x = x == w ? 0 : 1
|
||||||
|
# y = 25 * x + 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y *= 0
|
||||||
|
# y += w
|
||||||
|
# y += 4
|
||||||
|
# y *= x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x *= 0
|
||||||
|
# x += z
|
||||||
|
# x %= 26
|
||||||
|
# z = (z / 1.to_f).floor
|
||||||
|
# x += 12
|
||||||
|
# x = x == w ? 1 : 0
|
||||||
|
# x = x == 0 ? 1 : 0
|
||||||
|
# y *= 0
|
||||||
|
# y += 25
|
||||||
|
# y *= x
|
||||||
|
# y += 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y *= 0
|
||||||
|
# y += w
|
||||||
|
# y += 11
|
||||||
|
# y *= x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x *= 0
|
||||||
|
# x += z
|
||||||
|
# x %= 26
|
||||||
|
# z = (z / 1.to_f).floor
|
||||||
|
# x += 14
|
||||||
|
# x = x == w ? 1 : 0
|
||||||
|
# x = x == 0 ? 1 : 0
|
||||||
|
# y *= 0
|
||||||
|
# y += 25
|
||||||
|
# y *= x
|
||||||
|
# y += 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y *= 0
|
||||||
|
# y += w
|
||||||
|
# y += 1
|
||||||
|
# y *= x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
# # puts
|
||||||
|
# # puts
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x *= 0
|
||||||
|
# x += z
|
||||||
|
# x %= 26
|
||||||
|
# z = (z / 26.to_f).floor
|
||||||
|
# x += -6
|
||||||
|
# x = x == w ? 1 : 0
|
||||||
|
# x = x == 0 ? 1 : 0
|
||||||
|
# y *= 0
|
||||||
|
# y += 25
|
||||||
|
# y *= x
|
||||||
|
# y += 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y *= 0
|
||||||
|
# y += w
|
||||||
|
# y += 15
|
||||||
|
# y *= x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# return [w, x, y, z]
|
||||||
|
|
||||||
|
# w = input.shift
|
||||||
|
# x *= 0
|
||||||
|
# x += z
|
||||||
|
# x %= 26
|
||||||
|
# z = (z / 26.to_f).floor
|
||||||
|
# x += -10
|
||||||
|
# x = x == w ? 1 : 0
|
||||||
|
# x = x == 0 ? 1 : 0
|
||||||
|
# y *= 0
|
||||||
|
# y += 25
|
||||||
|
# y *= x
|
||||||
|
# y += 1
|
||||||
|
# z *= y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# y *= 0
|
||||||
|
# y += w
|
||||||
|
# y += 12
|
||||||
|
# y *= x
|
||||||
|
# z += y
|
||||||
|
# # p [w, x, y, z]
|
||||||
|
|
||||||
|
# return [w, x, y, z]
|
||||||
|
|
||||||
|
w = input.shift
|
||||||
|
x *= 0
|
||||||
|
x += z
|
||||||
|
x %= 26
|
||||||
|
z = (z / 26.to_f).floor
|
||||||
|
x += -12
|
||||||
|
x = x == w ? 1 : 0
|
||||||
|
x = x == 0 ? 1 : 0
|
||||||
|
y *= 0
|
||||||
|
y += 25
|
||||||
|
y *= x
|
||||||
|
y += 1
|
||||||
|
z *= y
|
||||||
|
# p [w, x, y, z]
|
||||||
|
|
||||||
|
y *= 0
|
||||||
|
y += w
|
||||||
|
y += 8
|
||||||
|
y *= x
|
||||||
|
z += y
|
||||||
|
# p [w, x, y, z]
|
||||||
|
|
||||||
|
return [w, x, y, z]
|
||||||
|
|
||||||
|
w = input.shift
|
||||||
|
x = z % 26
|
||||||
|
z = (z / 26.to_f).floor
|
||||||
|
x += -3
|
||||||
|
x = x == w ? 0 : 1
|
||||||
|
y = 25 * x + 1
|
||||||
|
z *= y
|
||||||
|
# p [w, x, y, z]
|
||||||
|
|
||||||
|
y = (w + 14) * x
|
||||||
|
z += y
|
||||||
|
# p [w, x, y, z]
|
||||||
|
|
||||||
|
w = input.shift
|
||||||
|
x = z % 26 # z - 5 must be w
|
||||||
|
z = (z / 26.to_f).floor # z must be < 26
|
||||||
|
x += -5 # w must be x - 5
|
||||||
|
x = x == w ? 0 : 1 # x must be w
|
||||||
|
y = 25 * x + 1
|
||||||
|
z *= y # z must be 0
|
||||||
|
# p [w, x, y, z]
|
||||||
|
|
||||||
|
y = (w + 9) * x # x must be 0
|
||||||
|
z += y # y must be 0
|
||||||
|
|
||||||
|
[w, x, y, z]
|
||||||
|
end
|
||||||
|
|
||||||
|
# 99999999999999.downto(11111111111111).lazy.map(&:to_s).reject { _1.include?(?0) }.each do |input|
|
||||||
|
vars = run(input.chars.map(&:to_i))
|
||||||
|
p [input, vars[3]] if vars[3] < 400
|
||||||
|
if vars[3].zero?
|
||||||
|
puts input
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b90e26c29b1742bf164b6121275b5e1ee8a56365
|
@ -0,0 +1,19 @@
|
|||||||
|
(fn dbg [tbl]
|
||||||
|
(each [_ chunk (ipairs tbl)]
|
||||||
|
(print (accumulate [x "" _ i (ipairs chunk)]
|
||||||
|
(.. x ", " i)))))
|
||||||
|
|
||||||
|
(local input (accumulate [input [[]] line (io.lines :../day_01.txt)]
|
||||||
|
(do
|
||||||
|
(if (= (length line) 0)
|
||||||
|
(table.insert input [])
|
||||||
|
(table.insert (. input (length input)) (tonumber line)))
|
||||||
|
input)))
|
||||||
|
|
||||||
|
(fn sum [l]
|
||||||
|
(accumulate [sum 0 _ n (ipairs l)]
|
||||||
|
(+ sum n)))
|
||||||
|
|
||||||
|
(local l (icollect [_ l (ipairs input)] (sum l)))
|
||||||
|
(table.sort l)
|
||||||
|
(print (. l (length l)))
|
@ -1 +1 @@
|
|||||||
3.1
|
3.2
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
require "set"
|
||||||
|
|
||||||
|
rocks = <<~ROCKS.split("\n\n")
|
||||||
|
####
|
||||||
|
|
||||||
|
.#.
|
||||||
|
###
|
||||||
|
.#.
|
||||||
|
|
||||||
|
..#
|
||||||
|
..#
|
||||||
|
###
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
##
|
||||||
|
##
|
||||||
|
ROCKS
|
||||||
|
rocks = rocks
|
||||||
|
.map {|rock| rock.lines(chomp: true).reverse.map(&:chars) }
|
||||||
|
.map {|rock|
|
||||||
|
rock.each.with_index.with_object(Set.new) {|(row, y), rocks|
|
||||||
|
row.each.with_index do |c, x|
|
||||||
|
rocks << [x, y] if c == ?#
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rocks = rocks.cycle
|
||||||
|
|
||||||
|
jet_pattern = ARGF.read.strip.chars
|
||||||
|
jet_pattern = jet_pattern.cycle
|
||||||
|
|
||||||
|
chamber = Hash.new {|_,(x,y)| !(0...7).cover?(x) || y.negative? }
|
||||||
|
|
||||||
|
def move_rock(chamber, rock, dx, dy)
|
||||||
|
next_rock = rock.map {|x,y| [x+dx, y+dy] }
|
||||||
|
|
||||||
|
if next_rock.any? {|x,y| chamber[[x, y]] }
|
||||||
|
rock
|
||||||
|
else
|
||||||
|
next_rock
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def debug(chamber, rock)
|
||||||
|
max_y = [chamber.keys.map(&:last).max || 0, rock.map(&:last).max || 0].max
|
||||||
|
|
||||||
|
puts
|
||||||
|
puts max_y.downto(0).map {|y|
|
||||||
|
(0...7).map {|x|
|
||||||
|
(chamber[[x,y]] || rock.include?([x,y])) ? ?# : ?.
|
||||||
|
}.join
|
||||||
|
}.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
2022.times do
|
||||||
|
rock = rocks.next
|
||||||
|
|
||||||
|
y = chamber.empty? ? 3 : chamber.keys.map(&:last).max + 4
|
||||||
|
x = 2
|
||||||
|
rock = move_rock(chamber, rock, x, y)
|
||||||
|
|
||||||
|
loop do
|
||||||
|
rock = case jet = jet_pattern.next
|
||||||
|
when ?< then move_rock(chamber, rock, -1, 0)
|
||||||
|
when ?> then move_rock(chamber, rock, 1, 0)
|
||||||
|
else fail "invalid jet pattern: #{jet}"
|
||||||
|
end
|
||||||
|
|
||||||
|
next_rock = move_rock(chamber, rock, 0, -1)
|
||||||
|
break if rock == next_rock
|
||||||
|
rock = next_rock
|
||||||
|
end
|
||||||
|
|
||||||
|
chamber.merge!(rock.to_h { [_1, true] })
|
||||||
|
end
|
||||||
|
|
||||||
|
# debug(chamber, Set.new)
|
||||||
|
max_y = chamber.keys.map(&:last).max + 1
|
||||||
|
p max_y
|
||||||
|
|
||||||
|
candidates = (0..max_y).select {|y| (0...7).count {|x| chamber[[x,y]] } == 6 }
|
||||||
|
# max_delta = candidates.each_cons(2).map { _2 - _1 }.max
|
||||||
|
candidates.
|
||||||
|
p candidates
|
||||||
|
p max_delta
|
@ -0,0 +1,92 @@
|
|||||||
|
SEEN = []
|
||||||
|
|
||||||
|
class Factory
|
||||||
|
attr_reader :time, :robots, :resources
|
||||||
|
|
||||||
|
def initialize(
|
||||||
|
blueprint,
|
||||||
|
time=0,
|
||||||
|
robots={ ore: 1, clay: 0, obsidian: 0, geode: 0 },
|
||||||
|
resources={ ore: 0, clay: 0, obsidian: 0, geode: 0 }
|
||||||
|
)
|
||||||
|
@blueprint = blueprint
|
||||||
|
@time = time
|
||||||
|
@robots = robots
|
||||||
|
@resources = resources
|
||||||
|
end
|
||||||
|
|
||||||
|
def max_geodes
|
||||||
|
if @time == 20
|
||||||
|
pp self if @robots.values_at(:ore, :clay, :obsidian, :geode) == [1, 4, 2, 1]
|
||||||
|
return @resources.fetch(:geode)
|
||||||
|
end
|
||||||
|
|
||||||
|
resources = @resources.merge(@robots) { _2 + _3 }
|
||||||
|
branches = @blueprint.filter_map {|robot, cost|
|
||||||
|
if cost.all? {|res, qty| @resources.fetch(res) >= qty }
|
||||||
|
Factory.new(
|
||||||
|
@blueprint,
|
||||||
|
@time + 1,
|
||||||
|
@robots.merge({robot => 1}) { _2 + _3 },
|
||||||
|
resources.merge(cost) { _2 - _3 },
|
||||||
|
)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
if @blueprint.any? {|_, cost| cost.any? {|res, qty| @robots.fetch(res) > 0 && @resources.fetch(res) < qty }}
|
||||||
|
pp self
|
||||||
|
branches << Factory.new(@blueprint, @time + 1, @robots, resources)
|
||||||
|
end
|
||||||
|
|
||||||
|
branches = branches.reject {|factory|
|
||||||
|
SEEN.any? {|other|
|
||||||
|
%i[ ore clay obsidian geode ].all? {|res|
|
||||||
|
factory.robots.fetch(res) <= other.robots.fetch(res) &&
|
||||||
|
factory.resources.fetch(res) <= other.resources.fetch(res) &&
|
||||||
|
factory.time >= other.time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SEEN.concat(branches)
|
||||||
|
|
||||||
|
return @resources.fetch(:geode) if branches.empty?
|
||||||
|
|
||||||
|
branches.map(&:max_geodes).max
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"<time: #@time robots: #{@robots.values} resources: #{@resources.values}>"
|
||||||
|
end
|
||||||
|
alias_method :inspect, :to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
blueprints = ARGF.read
|
||||||
|
.split("\n\n").map { _1.lines(chomp: true).join }
|
||||||
|
.map { _1.scan(/\d+/).map(&:to_i) }
|
||||||
|
.map {
|
||||||
|
_1.shift # id
|
||||||
|
{
|
||||||
|
ore: {ore: _1.shift },
|
||||||
|
clay: {ore: _1.shift },
|
||||||
|
obsidian: {ore: _1.shift, clay: _1.shift },
|
||||||
|
geode: {ore: _1.shift, obsidian: _1.shift },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p Factory.new(blueprints[0]).max_geodes
|
||||||
|
p SEEN.count
|
||||||
|
|
||||||
|
__END__
|
||||||
|
Blueprint 1:
|
||||||
|
Each ore robot costs 4 ore.
|
||||||
|
Each clay robot costs 2 ore.
|
||||||
|
Each obsidian robot costs 3 ore and 14 clay.
|
||||||
|
Each geode robot costs 2 ore and 7 obsidian.
|
||||||
|
|
||||||
|
Blueprint 2:
|
||||||
|
Each ore robot costs 2 ore.
|
||||||
|
Each clay robot costs 3 ore.
|
||||||
|
Each obsidian robot costs 3 ore and 8 clay.
|
||||||
|
Each geode robot costs 3 ore and 12 obsidian.
|
@ -0,0 +1,78 @@
|
|||||||
|
require "strscan"
|
||||||
|
|
||||||
|
include Math
|
||||||
|
|
||||||
|
map, path = ARGF.read.chomp.split("\n\n")
|
||||||
|
|
||||||
|
map = map.split("\n").each.with_index.with_object({}) {|(row,y),map|
|
||||||
|
row.chars.each.with_index do |tile,x|
|
||||||
|
map[[y,x]] = tile if tile != " "
|
||||||
|
end
|
||||||
|
}
|
||||||
|
max_y = map.keys.map(&:first).max
|
||||||
|
max_x = map.keys.map(&:last).max
|
||||||
|
|
||||||
|
start_x = map.keys.select { _1.first.zero? }.map(&:last).min
|
||||||
|
|
||||||
|
current = [0, start_x]
|
||||||
|
facing = 0
|
||||||
|
|
||||||
|
ss = StringScanner.new(path)
|
||||||
|
until ss.eos?
|
||||||
|
case
|
||||||
|
when n = ss.scan(/\d+/)
|
||||||
|
n = n.to_i
|
||||||
|
n.times do
|
||||||
|
y, x = current.zip([-sin(facing),cos(facing)]).map { _1 + _2 }.map(&:to_i)
|
||||||
|
next_tile = map[[y,x]]
|
||||||
|
|
||||||
|
unless next_tile
|
||||||
|
puts
|
||||||
|
p [y,x, facing]
|
||||||
|
y, x = case facing
|
||||||
|
when 0 then [y, 0]
|
||||||
|
when PI/2 then [max_y, x]
|
||||||
|
when PI then [y, max_x]
|
||||||
|
when 3*PI/2 then [0, x]
|
||||||
|
else fail "unexpected facing: #{facing}"
|
||||||
|
end
|
||||||
|
next_tile = map[[y,x]]
|
||||||
|
while next_tile.nil?
|
||||||
|
y, x = [y, x].zip([-sin(facing),cos(facing)]).map { _1 + _2 }.map(&:to_i)
|
||||||
|
next_tile = map[[y,x]]
|
||||||
|
end
|
||||||
|
|
||||||
|
p [y,x,next_tile]
|
||||||
|
end
|
||||||
|
|
||||||
|
case next_tile
|
||||||
|
when ?.
|
||||||
|
current = [y,x]
|
||||||
|
when ?#
|
||||||
|
break
|
||||||
|
else
|
||||||
|
fail "unexpected tile: #{next_tile}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
when dir = ss.scan(/R|L/)
|
||||||
|
facing += case dir
|
||||||
|
when ?R then -PI/2
|
||||||
|
when ?L then PI/2
|
||||||
|
else fail "unexpected dir: #{dir}"
|
||||||
|
end
|
||||||
|
facing %= 2*PI
|
||||||
|
else
|
||||||
|
fail ss.rest
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
row, col = current.map { _1 + 1 }
|
||||||
|
facing = case facing
|
||||||
|
when 0 then 0
|
||||||
|
when PI/2 then 3
|
||||||
|
when PI then 2
|
||||||
|
when 3*PI/2 then 2
|
||||||
|
else
|
||||||
|
fail "unexpected facing: #{facing}"
|
||||||
|
end
|
||||||
|
p [1000, 4, 1].zip([row, col, facing]).sum { _1 * _2 }
|
@ -0,0 +1,93 @@
|
|||||||
|
require "set"
|
||||||
|
|
||||||
|
walls = Set.new
|
||||||
|
blizzards = Hash.new {|h,k| h[k] = Set.new }
|
||||||
|
clear_ground = Set.new
|
||||||
|
|
||||||
|
ARGF.read.lines(chomp: true).each.with_index do |row, y|
|
||||||
|
row.chars.each.with_index do |pos,x|
|
||||||
|
case pos
|
||||||
|
when ?#
|
||||||
|
walls.add([y,x])
|
||||||
|
when /[v^<>]/
|
||||||
|
blizzards[pos].add([y,x])
|
||||||
|
when ?.
|
||||||
|
clear_ground.add([y,x])
|
||||||
|
else
|
||||||
|
fail pos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
x_range = Range.new(*walls.map(&:last).minmax)
|
||||||
|
y_range = Range.new(*walls.map(&:first).minmax)
|
||||||
|
|
||||||
|
debug = ->() do
|
||||||
|
puts
|
||||||
|
puts y_range.map {|y|
|
||||||
|
x_range.map {|x|
|
||||||
|
if walls.include?([y,x])
|
||||||
|
?#
|
||||||
|
elsif blizzards.any? {|_,pos| pos.include?([y,x])}
|
||||||
|
b = blizzards.select {|_,pos| pos.include?([y,x])}
|
||||||
|
(b.size == 1) ? b.keys[0] : b.size
|
||||||
|
else
|
||||||
|
?.
|
||||||
|
end
|
||||||
|
}.join
|
||||||
|
}.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
start = [0, clear_ground.find {|y,x| y == 0 }.last]
|
||||||
|
goal = [y_range.end, clear_ground.find {|y,x| y == y_range.end }.last]
|
||||||
|
|
||||||
|
dir_deltas = {
|
||||||
|
?^ => [-1, 0],
|
||||||
|
?v => [ 1, 0],
|
||||||
|
?< => [ 0, -1],
|
||||||
|
?> => [ 0, 1],
|
||||||
|
}
|
||||||
|
moves = [*dir_deltas.values, [0, 0]]
|
||||||
|
|
||||||
|
frontier = [start]
|
||||||
|
(1..).each do |time|
|
||||||
|
if (time % 1).zero?
|
||||||
|
puts time
|
||||||
|
# p frontier
|
||||||
|
# debug.()
|
||||||
|
end
|
||||||
|
|
||||||
|
blizzards = blizzards.to_h {|dir,positions|
|
||||||
|
delta = dir_deltas.fetch(dir)
|
||||||
|
edges, positions = positions
|
||||||
|
.map {|pos| pos.zip(delta).map { _1 + _2 }}
|
||||||
|
.partition { walls.include?(_1) }
|
||||||
|
positions.concat(edges.map {|(y,x)|
|
||||||
|
case dir
|
||||||
|
when ?^ then [y_range.end - 1, x]
|
||||||
|
when ?v then [y_range.begin + 1, x]
|
||||||
|
when ?< then [y, x_range.end - 1]
|
||||||
|
when ?> then [y, x_range.end + 1]
|
||||||
|
else fail dir
|
||||||
|
end
|
||||||
|
})
|
||||||
|
[dir, positions]
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_ground = y_range.map {|y| x_range.map {|x| [y, x] }}.flatten(1)
|
||||||
|
.reject {|pos| walls.include?(pos) || blizzards.any? { _2.include?(pos) }}
|
||||||
|
|
||||||
|
options = frontier.map {|current|
|
||||||
|
moves.filter_map {|delta|
|
||||||
|
pos = current.zip(delta).map { _1 + _2 }
|
||||||
|
clear_ground.include?(pos) && pos
|
||||||
|
}
|
||||||
|
}.flatten(1)
|
||||||
|
|
||||||
|
frontier = options.uniq
|
||||||
|
|
||||||
|
if frontier.include?(goal)
|
||||||
|
puts time + 1
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,12 @@
|
|||||||
|
seconds = ARGF.read.strip.lines(chomp: true)
|
||||||
|
.sum {|line|
|
||||||
|
line.strip.split(/\s+/).fetch(4)
|
||||||
|
.split(?:).map(&:to_i)
|
||||||
|
.zip([60*60, 60, 1])
|
||||||
|
.sum { _1 * _2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
hours, seconds = seconds.divmod(60 * 60)
|
||||||
|
minutes, seconds = seconds.divmod(60)
|
||||||
|
|
||||||
|
puts "#{hours} hours, #{minutes} minutes, #{seconds} seconds"
|
Loading…
Reference in new issue