Compare commits
1 Commits
main
...
renovate/c
Author | SHA1 | Date |
---|---|---|
Renovate Bot | cb08f14406 | 2 years ago |
@ -1,3 +0,0 @@
|
|||||||
[submodule "2022/bqn/lib"]
|
|
||||||
path = 2022/bqn/lib
|
|
||||||
url = https://github.com/mlochbaum/bqn-libs.git
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env jconsole
|
|
||||||
|
|
||||||
echo stdin
|
|
||||||
exit''
|
|
@ -1,52 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
|||||||
#############
|
|
||||||
#...........#
|
|
||||||
###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
|
|
@ -1,58 +0,0 @@
|
|||||||
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
|
|
@ -1,262 +0,0 @@
|
|||||||
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
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit b90e26c29b1742bf164b6121275b5e1ee8a56365
|
|
@ -1,19 +0,0 @@
|
|||||||
(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.2
|
3.1
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
require "set"
|
|
||||||
|
|
||||||
Valve = Data.define(:name, :flow_rate, :tunnels)
|
|
||||||
|
|
||||||
valves = ARGF.read.scan(/Valve (.+) has flow rate=(\d+); tunnels? leads? to valves? ((?~\n))/)
|
|
||||||
.map {|name, flow_rate, tunnels|
|
|
||||||
Valve.new(name, flow_rate.to_i, tunnels.split(", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
Network = Data.define(:valves) do
|
|
||||||
def initialize(*)
|
|
||||||
@connections = Hash.new {|h,start|
|
|
||||||
current = [[start]]
|
|
||||||
result = { start => %w[ AA ] }
|
|
||||||
|
|
||||||
until current.empty?
|
|
||||||
path = current.shift
|
|
||||||
links = valves.fetch(path.last).tunnels
|
|
||||||
.reject { result.has_key?(_1) }
|
|
||||||
.map { path + [_1] }
|
|
||||||
result.merge!(links.to_h { [_1.last, _1] })
|
|
||||||
current.concat(links)
|
|
||||||
end
|
|
||||||
|
|
||||||
h[start] = result
|
|
||||||
}
|
|
||||||
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
def connections(start) = @connections[start]
|
|
||||||
end
|
|
||||||
|
|
||||||
Move = Data.define(:reward, :target, :path) do
|
|
||||||
def cost = path.length
|
|
||||||
end
|
|
||||||
|
|
||||||
State = Data.define(:net, :current, :max, :turn, :pressure, :opened) do
|
|
||||||
def best_moves(best)
|
|
||||||
best_state = self
|
|
||||||
|
|
||||||
best[opened] = [best.fetch(opened, pressure), pressure].max
|
|
||||||
|
|
||||||
moves.each do |move|
|
|
||||||
next_state = applied(move)
|
|
||||||
next_state = next_state.best_moves(best);
|
|
||||||
if next_state.pressure > best_state.pressure
|
|
||||||
best_state = next_state
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
best_state
|
|
||||||
end
|
|
||||||
|
|
||||||
def applied(move)
|
|
||||||
self.class.new(
|
|
||||||
net,
|
|
||||||
move.target,
|
|
||||||
max,
|
|
||||||
turn + move.cost,
|
|
||||||
pressure + move.reward,
|
|
||||||
Set[*opened, move.target],
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def moves
|
|
||||||
return enum_for(__method__) unless block_given?
|
|
||||||
|
|
||||||
net
|
|
||||||
.connections(current)
|
|
||||||
.reject { opened.include?(_1) }
|
|
||||||
.each do |name, path|
|
|
||||||
flow = net.valves.fetch(name).flow_rate
|
|
||||||
reward = flow * (turns_left - path.length)
|
|
||||||
if reward.positive?
|
|
||||||
yield Move.new(reward, name, path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def turns_left = max - turn
|
|
||||||
end
|
|
||||||
|
|
||||||
network = Network.new(valves.to_h { [_1.name, _1] })
|
|
||||||
|
|
||||||
# part 1
|
|
||||||
# state = State.new(network, "AA", 30, 0, 0, [])
|
|
||||||
# best_state = state.best_moves({})
|
|
||||||
# pp best_state
|
|
||||||
|
|
||||||
# part 2
|
|
||||||
state = State.new(network, "AA", 26, 0, 0, [])
|
|
||||||
|
|
||||||
best = {}
|
|
||||||
state.best_moves(best)
|
|
||||||
|
|
||||||
pp best
|
|
||||||
.transform_keys(&:to_set)
|
|
||||||
.to_a
|
|
||||||
.combination(2)
|
|
||||||
.select { _1[0].disjoint?(_2[0]) }
|
|
||||||
.map { _1[1] + _2[1] }
|
|
||||||
.max
|
|
@ -1,89 +0,0 @@
|
|||||||
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
|
|
@ -1,92 +0,0 @@
|
|||||||
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.
|
|
@ -1,78 +0,0 @@
|
|||||||
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 }
|
|
@ -1,93 +0,0 @@
|
|||||||
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
|
|
File diff suppressed because it is too large
Load Diff
@ -1,140 +0,0 @@
|
|||||||
.....................#......#...................#...............#........................................#..................................
|
|
||||||
...........................................................#.............................................................#..................
|
|
||||||
.....................................................................#.........#......#...........#.............#...........................
|
|
||||||
.....................................................#.......................................#..............................................
|
|
||||||
......#.................................#..........................................................................................#........
|
|
||||||
....................#.........#.............................................................................#...............................
|
|
||||||
..#.........................................................#.............................................................................#.
|
|
||||||
........................................................................................#...........#..................#....................
|
|
||||||
........#....................................#........................#.........................................................#...........
|
|
||||||
..............................................................................#................................#............................
|
|
||||||
..................................................#............#............................................................................
|
|
||||||
.........................#......#........#................................................#..........................................#......
|
|
||||||
......#..............................................................................#...............#......................................
|
|
||||||
...................................................................#........................................................................
|
|
||||||
....................#...........................#............................................................#..............#.....#.........
|
|
||||||
..................................#....................#.........................................#......#..............................#....
|
|
||||||
.#..........................................................................................................................................
|
|
||||||
........#.....#........................#...........#.............#.....................#....................................................
|
|
||||||
..........................#.................................#.....................#.........................................................
|
|
||||||
.............................................................................................................................#.............#
|
|
||||||
...................................#......................................................#....................#............................
|
|
||||||
.....................#...................#............#..................#.............................................#...........#........
|
|
||||||
..............................................................................................#.............................................
|
|
||||||
....#..........#...............#..........................................................................#.................................
|
|
||||||
.............................................#..............................................................................................
|
|
||||||
...................................................................#..............#.................................#.......................
|
|
||||||
..................#........................................................#................................................................
|
|
||||||
..#.................................#...................#..............................#.........................................#.......#..
|
|
||||||
...............................................................#...............#.....................#..........#.........#.................
|
|
||||||
.........#......................#.............................................................#.............................................
|
|
||||||
..............#...............................#.............................................................................................
|
|
||||||
........................................#.................................#............................................................#....
|
|
||||||
..............................................................................................................#......#......#...............
|
|
||||||
.........................#..........#.............................................#........#................................................
|
|
||||||
....................................................................#.....................................#.................................
|
|
||||||
....#...............#........#...............................#........................#........................................#............
|
|
||||||
........................................................#...................................................................................
|
|
||||||
............................................#...........................#......................#.....#......................................
|
|
||||||
.........................................................................................#.............................................#....
|
|
||||||
...........#....................#..................................#.................................................#...........#..........
|
|
||||||
.#..........................................................................................................................................
|
|
||||||
................#........................#..........#.......................................................................................
|
|
||||||
........................#........................................................................................#..........................
|
|
||||||
........................................................................#.........#...................#...................#.................
|
|
||||||
........................................................#......................................................................#............
|
|
||||||
.....#.....................................................................................#................................................
|
|
||||||
...............#...................................#.................#..............................................................#.......
|
|
||||||
.........#..................#..................................#..................................................#.........................
|
|
||||||
......................................#.......#....................................#......................................................#.
|
|
||||||
..........................................................................................................#......................#..........
|
|
||||||
...#..............#.......................#.....................................................#...........................................
|
|
||||||
................................#...............................................#..........#................................................
|
|
||||||
..........................#......................#......................#...................................................................
|
|
||||||
..................................................................#................................#........................................
|
|
||||||
......................................................#.................................#.........................#...................#.....
|
|
||||||
..............#..........................#..................................................................................#...............
|
|
||||||
......#......................#.................................................................#...........#................................
|
|
||||||
.............................................................................#..............................................................
|
|
||||||
.......................#..........................#......................................................................#..........#.......
|
|
||||||
.#.................................#................................................................#....................................#..
|
|
||||||
........#......#................................................#...............................................#...........................
|
|
||||||
..........................................................................#.....#.........................#...........#.....#...............
|
|
||||||
............................#..............#..........#....................................#................................................
|
|
||||||
............................................................................................................................................
|
|
||||||
............#..........#....................................................................................................................
|
|
||||||
............................................................#.......................#..............#........................................
|
|
||||||
.....................................#...............................#...................................#..................................
|
|
||||||
.........#.....................................................................#.....................................#...............#.....#
|
|
||||||
#.............#.............................................................................................................................
|
|
||||||
......................................................#....................................#....................................#...........
|
|
||||||
...................................................................#............................................#...........................
|
|
||||||
............................................................................................................................................
|
|
||||||
....................#............................#................................................#......................................#..
|
|
||||||
.............................#...................................................#..........................................................
|
|
||||||
.........................................................................#...............#.................#................................
|
|
||||||
.............#.........#.........#.....#......................#............................................................#................
|
|
||||||
............................................................................................................................................
|
|
||||||
.............................................#..........#.....................#..................................#..........................
|
|
||||||
............................................................................................................................................
|
|
||||||
...................................#.............#................#.....#.....................................................#.............
|
|
||||||
....#.....................#..................................#..............................................................................
|
|
||||||
............................................................................................................................................
|
|
||||||
#.....................................#...................................................................................#.................
|
|
||||||
...............................................#......................#.....#...................................#...........................
|
|
||||||
.........#...................#.....................................................#.................#......................................
|
|
||||||
.......................#...............................#........................................#..............................#............
|
|
||||||
...#.....................................#..................................................................#...............................
|
|
||||||
...................................................#......................................#...........................................#.....
|
|
||||||
.................#..........................................................................................................................
|
|
||||||
...................................................................................................................#......#.................
|
|
||||||
.................................#..............#.....#......................#.................#.........#..................................
|
|
||||||
#....................................................................#........................................#...........................#.
|
|
||||||
............................................................................................................................................
|
|
||||||
.........................#..................................................................................................................
|
|
||||||
...............................#.......................................................................................#....................
|
|
||||||
..........#...................................#..................#.....................#....................#...............................
|
|
||||||
............................................................................#.....#.........................................................
|
|
||||||
....#............#............................................................................#.......#..........#..........................
|
|
||||||
..................................................................................................................................#.........
|
|
||||||
...................................#...........................................#............................................................
|
|
||||||
.............................#..........................#.................................#........#........................................
|
|
||||||
..............#....................................................#........................................#.............#...........#.....
|
|
||||||
...............................................#.............#.......................................................#......................
|
|
||||||
........#..............................................................#....................................................................
|
|
||||||
.......................................................................................#........#...........................................
|
|
||||||
......................#........#.........................#..................#........................#......................#...............
|
|
||||||
.#.........#.....#..............................................#........................................................................#..
|
|
||||||
.....................................................#......................................................................................
|
|
||||||
.........................................#...........................#..............................................#.......................
|
|
||||||
.............................................................#................................................#................#............
|
|
||||||
......#.......................................#.......................................#...............#.....................................
|
|
||||||
....................#.......#............................#................#...........................................................#.....
|
|
||||||
...........#.....................................................................................................#..........................
|
|
||||||
..........................................................................................#..............#..................................
|
|
||||||
..................................................#..........................................................................#..............
|
|
||||||
...............#............................................#.....................................................................#.........
|
|
||||||
........................#...........................................#............................#..................#.......................
|
|
||||||
................................................................................#..............................#.......................#....
|
|
||||||
......................................#...................................#..............#..............#...................................
|
|
||||||
..#............................................#..............#...........................................................#.................
|
|
||||||
.........#........................#...................#.....................................................................................
|
|
||||||
.............................#..............................................................................................................
|
|
||||||
....................................................................................#.......................................................
|
|
||||||
.........................#.............#............................................................#......#......#.........#......#........
|
|
||||||
...................#...........................................................................#...........................................#
|
|
||||||
.......#...............................................#.....#........#..........#..........................................................
|
|
||||||
..............#....................#........................................................................................................
|
|
||||||
........................................................................................................#.................#...........#.....
|
|
||||||
..#...............................................................#.........#.......#.......................................................
|
|
||||||
.........#......................#..........................#.....................................#............#.............................
|
|
||||||
...................#.................................#.................................................................#....................
|
|
||||||
....................................#.......................................................................................................
|
|
||||||
...........................#......................................................................................................#.........
|
|
||||||
............................................#.................#............#...................#.......#...................#................
|
|
||||||
............#.....................................#.........................................................................................
|
|
||||||
...........................................................................................................#......#.........................
|
|
||||||
.....................................#..............................................#......#................................................
|
|
||||||
.........................................................................#..............................................#...................
|
|
||||||
#....................#........#...................................................................#.....................................#...
|
|
||||||
.....#........................................#.........#........................#..........................................................
|
|
@ -1 +0,0 @@
|
|||||||
3.2
|
|
@ -1,4 +0,0 @@
|
|||||||
source "https://rubygems.org"
|
|
||||||
|
|
||||||
gem "minitest"
|
|
||||||
gem "rake"
|
|
@ -1,15 +0,0 @@
|
|||||||
GEM
|
|
||||||
remote: https://rubygems.org/
|
|
||||||
specs:
|
|
||||||
minitest (5.20.0)
|
|
||||||
rake (13.1.0)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
arm64-darwin-22
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
minitest
|
|
||||||
rake
|
|
||||||
|
|
||||||
BUNDLED WITH
|
|
||||||
2.4.1
|
|
@ -1,24 +0,0 @@
|
|||||||
lines = ARGF.readlines(chomp: true)
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p lines
|
|
||||||
.map { _1.chars.select {|c| c =~ /\d/ }}
|
|
||||||
.map { _1.values_at(0, -1) }
|
|
||||||
.sum { _1.join.to_i }
|
|
||||||
|
|
||||||
# part two
|
|
||||||
spellings = %w[
|
|
||||||
one two three four five six seven eight nine
|
|
||||||
].each.with_index.to_h { [_1, _2 + 1] }
|
|
||||||
digits = (spellings.keys + spellings.values).join(?|)
|
|
||||||
first_re = /(#{digits})(?~#{digits})/
|
|
||||||
last_re = /.*(#{digits})/
|
|
||||||
|
|
||||||
p lines
|
|
||||||
.sum { |line|
|
|
||||||
[first_re, last_re]
|
|
||||||
.map { _1.match(line)[1] }
|
|
||||||
.map { spellings.fetch(_1, &:to_i) }
|
|
||||||
.join
|
|
||||||
.to_i
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
input = ARGF.read
|
|
||||||
|
|
||||||
def parse_cubes(input)
|
|
||||||
input
|
|
||||||
.scan(/(\d+) (\w+)/)
|
|
||||||
.to_h(&:reverse)
|
|
||||||
.transform_values(&:to_i)
|
|
||||||
end
|
|
||||||
|
|
||||||
bag = parse_cubes("12 red cubes, 13 green cubes, and 14 blue cubes")
|
|
||||||
|
|
||||||
Game = Data.define(:id, :reveals) do
|
|
||||||
def possible?(bag)
|
|
||||||
reveals.all? {|reveal|
|
|
||||||
bag.all? {|color, n| n >= reveal.fetch(color, 0) }
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
games = input
|
|
||||||
.scan(/^Game (\d+): ((?~\n))/)
|
|
||||||
.map {|id, reveals|
|
|
||||||
Game.new(
|
|
||||||
id.to_i,
|
|
||||||
reveals.split(?;).map { parse_cubes(_1) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p games.select { _1.possible?(bag) }.sum(&:id)
|
|
||||||
|
|
||||||
# part two
|
|
||||||
p games
|
|
||||||
.map {|game|
|
|
||||||
game.reveals.inject {|bag, reveal|
|
|
||||||
bag.merge(reveal) { [_2, _3].max }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.sum {|bag| bag.values.inject(:*) }
|
|
@ -1,55 +0,0 @@
|
|||||||
require "strscan"
|
|
||||||
|
|
||||||
Part = Data.define(:number) do
|
|
||||||
def eql?(other)
|
|
||||||
self.object_id == other.object_id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse(input)
|
|
||||||
ss = StringScanner.new(input)
|
|
||||||
y = x = 0
|
|
||||||
schematic = {}
|
|
||||||
until ss.eos?
|
|
||||||
case
|
|
||||||
when ss.scan(/\./)
|
|
||||||
x += 1
|
|
||||||
when num = ss.scan(/\d+/)
|
|
||||||
coords = (0...num.length).map {|dx| [y, x+dx] }
|
|
||||||
part = Part.new(num.to_i)
|
|
||||||
schematic.merge!(coords.to_h { [_1, part] })
|
|
||||||
x += num.length
|
|
||||||
when ss.scan(/\n/)
|
|
||||||
y += 1
|
|
||||||
x = 0
|
|
||||||
when sym = ss.scan(/./)
|
|
||||||
schematic[[y,x]] = sym
|
|
||||||
x += 1
|
|
||||||
else
|
|
||||||
fail
|
|
||||||
end
|
|
||||||
end
|
|
||||||
schematic
|
|
||||||
end
|
|
||||||
|
|
||||||
schematic = parse(ARGF.read)
|
|
||||||
syms, nums = schematic.partition { String === _2 }.map(&:to_h)
|
|
||||||
neighboring_parts = ->((y,x)) {
|
|
||||||
dy = (-1..1).to_a
|
|
||||||
dx = (-1..1).to_a
|
|
||||||
dy.product(dx)
|
|
||||||
.map {|dy,dx| [y+dy,x+dx] }
|
|
||||||
.filter_map { nums.fetch(_1, nil) }
|
|
||||||
}
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p syms.keys.flat_map { neighboring_parts.(_1) }.uniq.sum(&:number)
|
|
||||||
|
|
||||||
# part two
|
|
||||||
p syms
|
|
||||||
.select { _2 == ?* }
|
|
||||||
.filter_map {|coord, _|
|
|
||||||
parts = neighboring_parts.(coord).uniq
|
|
||||||
parts.length == 2 ? parts : nil
|
|
||||||
}
|
|
||||||
.sum { _1.map(&:number).inject(:*) }
|
|
@ -1,22 +0,0 @@
|
|||||||
cards = ARGF.read.scan(/Card\s+(\d+):+((?~\|))\|(.*)/)
|
|
||||||
.to_h {|id, *v|
|
|
||||||
[id.to_i, v.map { _1.scan(/\d+/).map(&:to_i) }]
|
|
||||||
}
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p cards.values
|
|
||||||
.map {|winning,card|
|
|
||||||
winners = (card & winning)
|
|
||||||
winners.empty? ? 0 : 2 ** (winners.length - 1)
|
|
||||||
}
|
|
||||||
.sum
|
|
||||||
|
|
||||||
# part two
|
|
||||||
wins = Hash.new {|h,k|
|
|
||||||
winning, card = cards.fetch(k)
|
|
||||||
winners = winning & card
|
|
||||||
new_cards = (1..winners.length).map { k + _1 }
|
|
||||||
|
|
||||||
h[k] = 1 + (winners.empty? ? 0 : new_cards.sum { h[_1] })
|
|
||||||
}
|
|
||||||
p cards.keys.sum { wins[_1] }
|
|
@ -1,108 +0,0 @@
|
|||||||
Conversion = Data.define(:source, :dest) do
|
|
||||||
def [](k)
|
|
||||||
return nil unless source.cover?(k)
|
|
||||||
|
|
||||||
dest.begin + k - source.begin
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Mapping = Data.define(:conversions) do
|
|
||||||
def [](source)
|
|
||||||
conversions.filter_map { _1[source] }.first || source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
chunks = ARGF.read.split("\n\n")
|
|
||||||
seeds = chunks.shift.scan(/\d+/).map(&:to_i)
|
|
||||||
mappings = chunks.map {|chunk|
|
|
||||||
Mapping.new(
|
|
||||||
chunk
|
|
||||||
.strip.split("\n")[1..-1]
|
|
||||||
.map { _1.scan(/\d+/).map(&:to_i) }
|
|
||||||
.map { Conversion.new((_2..._2+_3), (_1..._1+_3)) }
|
|
||||||
# .sort_by { _1.source.begin }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p seeds
|
|
||||||
.map {|seed|
|
|
||||||
mappings.inject(seed) {|cur, mapping| mapping[cur] }
|
|
||||||
}
|
|
||||||
.min
|
|
||||||
|
|
||||||
# part two
|
|
||||||
|
|
||||||
# clamps range a to range b
|
|
||||||
def clamp(a, b)
|
|
||||||
case
|
|
||||||
when a.cover?(b.begin) && a.cover?(b.end)
|
|
||||||
b
|
|
||||||
when b.cover?(a.begin) && b.cover?(a.end)
|
|
||||||
a
|
|
||||||
when a.cover?(b.begin)
|
|
||||||
(b.begin...a.end)
|
|
||||||
when b.cover?(a.begin)
|
|
||||||
(a.begin...b.end)
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
seeds = seeds
|
|
||||||
.each_slice(2)
|
|
||||||
.map {|start, length| (start...start+length) }
|
|
||||||
.sort_by(&:begin)
|
|
||||||
dests = mappings.inject(seeds) {|cur, mapping|
|
|
||||||
sources = cur
|
|
||||||
.flat_map {|range|
|
|
||||||
sources = mapping.conversions.map(&:source).sort_by(&:begin)
|
|
||||||
sources.concat(sources.each_cons(2).map { (_1.end..._2.begin) })
|
|
||||||
sources << (0...(sources.map(&:begin).min))
|
|
||||||
sources << (sources.map(&:end).max..)
|
|
||||||
sources.filter_map {|source|
|
|
||||||
clamp(source, range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.reject { _1.size == 0 }
|
|
||||||
sources.map { (mapping[_1.begin]..mapping[_1.end-1]) }
|
|
||||||
}
|
|
||||||
p dests.map(&:begin).min
|
|
||||||
|
|
||||||
### prior explorations for part two
|
|
||||||
|
|
||||||
# p seeds
|
|
||||||
# .each_slice(2)
|
|
||||||
# .map {|start, length|
|
|
||||||
# (start...start+length).map {|seed|
|
|
||||||
# mappings.inject(seed) {|cur, mapping| mapping[cur] }
|
|
||||||
# }
|
|
||||||
# .min
|
|
||||||
# }
|
|
||||||
# .min
|
|
||||||
|
|
||||||
reversed = mappings
|
|
||||||
.map {|mapping|
|
|
||||||
Mapping.new(
|
|
||||||
mapping.conversions.map {|c|
|
|
||||||
Conversion.new((c.dest.begin...c.dest.begin+c.source.size), c.source)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.reverse
|
|
||||||
# p (0..).find {|i|
|
|
||||||
# source = reversed.inject(i) {|cur, mapping| mapping[cur] }
|
|
||||||
# seeds.any? { _1.cover?(source) }
|
|
||||||
# }
|
|
||||||
|
|
||||||
lowest = seeds
|
|
||||||
.flat_map(&:minmax)
|
|
||||||
.filter_map {|seed|
|
|
||||||
mappings.inject(seed) {|cur, mapping| mapping[cur] }
|
|
||||||
}
|
|
||||||
.min
|
|
||||||
p (0..lowest).bsearch {|loc|
|
|
||||||
source = reversed.inject(loc) {|cur, mapping| mapping[cur] }
|
|
||||||
seeds.any? { _1.cover?(source) }
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
times, records = ARGF.readlines(chomp: true).map { _1.scan(/\d+/).map(&:to_i) }
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p times.zip(records)
|
|
||||||
.map {|time, record|
|
|
||||||
distances = (1...time).map {|hold| (time - hold) * hold }
|
|
||||||
distances.count { _1 > record }
|
|
||||||
}
|
|
||||||
.inject(:*)
|
|
||||||
|
|
||||||
# part two
|
|
||||||
time = times.join.to_i
|
|
||||||
record = records.join.to_i
|
|
||||||
p (1...time).count {|hold| (time - hold) * hold > record}
|
|
@ -1,55 +0,0 @@
|
|||||||
HAND_STRENGTH = [
|
|
||||||
[5], # five of a kind
|
|
||||||
[1, 4], # four of a kind
|
|
||||||
[2, 3], # full house
|
|
||||||
[1, 1, 3], # three of a kind
|
|
||||||
[1, 2, 2], # two pair
|
|
||||||
[1, 1, 1, 2], # one pair
|
|
||||||
[1, 1, 1, 1, 1], # high card
|
|
||||||
].reverse.each.with_index.to_h { [_1, _2] }
|
|
||||||
|
|
||||||
class PartOne
|
|
||||||
CARD_RANK = ((?2..?9).to_a + %w[ T J Q K A ]).each.with_index.to_h
|
|
||||||
|
|
||||||
def strength(cards)
|
|
||||||
tally = cards.tally
|
|
||||||
strengths = [
|
|
||||||
self.hand_type(tally),
|
|
||||||
*cards.map { CARD_RANK.fetch(_1) },
|
|
||||||
]
|
|
||||||
strengths.map { (?a.ord + _1).chr }.join
|
|
||||||
end
|
|
||||||
|
|
||||||
def hand_type(tally)
|
|
||||||
HAND_STRENGTH.fetch(tally.values.sort)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class PartTwo < PartOne
|
|
||||||
CARD_RANK = ([?J] + (?2..?9).to_a + %w[ T Q K A ]).each.with_index.to_h
|
|
||||||
|
|
||||||
def hand_type(tally)
|
|
||||||
jokers = tally.delete(?J) || 0
|
|
||||||
counts = tally.values.sort
|
|
||||||
if counts.empty?
|
|
||||||
counts = [5]
|
|
||||||
else
|
|
||||||
counts[-1] += jokers
|
|
||||||
end
|
|
||||||
HAND_STRENGTH.fetch(counts)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
hands = ARGF.read.scan(/(\w+)\s+(\d+)/).to_h { [_1.chars, _2.to_i ] }
|
|
||||||
|
|
||||||
part_one = PartOne.new
|
|
||||||
p hands
|
|
||||||
.sort_by {|(hand,_)| part_one.strength(hand) }
|
|
||||||
.map.with_index {|(_,bid),i| bid * (i+1) }
|
|
||||||
.sum
|
|
||||||
|
|
||||||
part_two = PartTwo.new
|
|
||||||
p hands
|
|
||||||
.sort_by {|(hand,_)| part_two.strength(hand) }
|
|
||||||
.map.with_index {|(_,bid),i| bid * (i+1) }
|
|
||||||
.sum
|
|
@ -1,24 +0,0 @@
|
|||||||
instructions, network = ARGF.read.split("\n\n")
|
|
||||||
|
|
||||||
network = network
|
|
||||||
.scan(/(\w+) = \((\w+), (\w+)\)/)
|
|
||||||
.to_h { [_1, { L: _2, R: _3 }] }
|
|
||||||
|
|
||||||
steps = ->(start, finish) {
|
|
||||||
node = start
|
|
||||||
instructions.chars.map(&:to_sym)
|
|
||||||
.cycle.with_index.lazy
|
|
||||||
.filter_map {|dir, i|
|
|
||||||
node = network.fetch(node).fetch(dir)
|
|
||||||
(node =~ finish) ? i+1 : nil
|
|
||||||
}
|
|
||||||
.first
|
|
||||||
}
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p steps.("AAA", /ZZZ/)
|
|
||||||
|
|
||||||
# part two
|
|
||||||
nodes = network.keys.select { _1.end_with?(?A) }
|
|
||||||
node_steps = nodes.map { steps.(_1, /Z$/) }
|
|
||||||
p node_steps.inject(1, :lcm)
|
|
@ -1,17 +0,0 @@
|
|||||||
histories = ARGF.readlines.map { _1.scan(/-?\d+/).map(&:to_i) }
|
|
||||||
|
|
||||||
history_diffs = histories.map {|history|
|
|
||||||
diffs = [history]
|
|
||||||
until diffs.last.all?(&:zero?)
|
|
||||||
diffs << diffs.last.each_cons(2).map { _2 - _1 }
|
|
||||||
end
|
|
||||||
diffs
|
|
||||||
}
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p history_diffs.sum { _1.sum(&:last) }
|
|
||||||
|
|
||||||
# part two
|
|
||||||
p history_diffs.sum {|diffs|
|
|
||||||
diffs.map(&:first).reverse.inject { _2 - _1 }
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
require "forwardable"
|
|
||||||
|
|
||||||
DIR_DELTAS = {
|
|
||||||
N: [-1, 0],
|
|
||||||
W: [ 0, -1],
|
|
||||||
E: [ 0, 1],
|
|
||||||
S: [ 1, 0],
|
|
||||||
}
|
|
||||||
TILE_NEIGHBOR_DELTAS = {
|
|
||||||
?| => "NS",
|
|
||||||
?- => "EW",
|
|
||||||
?L => "NE",
|
|
||||||
?J => "NW",
|
|
||||||
?7 => "SW",
|
|
||||||
?F => "SE",
|
|
||||||
?S => "NEWS",
|
|
||||||
}.transform_values {|dirs| dirs.chars.map { DIR_DELTAS.fetch(_1.to_sym) }}
|
|
||||||
|
|
||||||
Tiles = Data.define(:tiles) do
|
|
||||||
extend Forwardable
|
|
||||||
def_delegator :tiles, :key
|
|
||||||
def_delegator :tiles, :fetch
|
|
||||||
def_delegator :tiles, :size
|
|
||||||
|
|
||||||
def neighbors(coord)
|
|
||||||
TILE_NEIGHBOR_DELTAS.fetch(self.fetch(coord))
|
|
||||||
.map {|delta| coord.zip(delta).map { _1 + _2 }}
|
|
||||||
.select { tiles.has_key?(_1) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
coords = tiles.keys
|
|
||||||
y_range, x_range = *extents
|
|
||||||
y_range.map {|y|
|
|
||||||
x_range.map {|x| tiles.fetch([y,x], ?.) }.join
|
|
||||||
}.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def extents
|
|
||||||
y_range = Range.new(*tiles.keys.map(&:first).minmax)
|
|
||||||
x_range = Range.new(*tiles.keys.map(&:last).minmax)
|
|
||||||
[y_range, x_range]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
tiles = ARGF.readlines(chomp: true).each.with_index.inject({}) {|tiles, (row, y)|
|
|
||||||
tiles.merge(
|
|
||||||
row.chars.each.with_index
|
|
||||||
.reject {|tile,_| tile == ?. }
|
|
||||||
.to_h {|tile,x| [[y,x], tile] }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
tiles = Tiles.new(tiles)
|
|
||||||
|
|
||||||
start = tiles.key(?S)
|
|
||||||
seed = tiles.neighbors(start)
|
|
||||||
.find {|candidate|
|
|
||||||
tiles.neighbors(candidate).any? { tiles.fetch(_1) == ?S }
|
|
||||||
}
|
|
||||||
|
|
||||||
loop_ = [seed]
|
|
||||||
until loop_.last == start
|
|
||||||
cur = loop_.last
|
|
||||||
loop_ << tiles.neighbors(cur)
|
|
||||||
.reject { _1 == loop_[-2] }
|
|
||||||
.first
|
|
||||||
end
|
|
||||||
|
|
||||||
# fix the start tile
|
|
||||||
start_dirs = [seed, loop_[-2]].map {|coord| start.zip(coord).map { _2 - _1 }}
|
|
||||||
tile = TILE_NEIGHBOR_DELTAS.find { _2.sort == start_dirs.sort }[0]
|
|
||||||
tiles.tiles[start] = tile
|
|
||||||
|
|
||||||
loop_ = Tiles.new(loop_.to_h { [_1, tiles.fetch(_1)] })
|
|
||||||
# puts loop_
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p loop_.size / 2
|
|
||||||
|
|
||||||
# part two
|
|
||||||
y_range, x_range = *loop_.extents
|
|
||||||
p y_range.sum {|y|
|
|
||||||
x_range.chunk_while {|x_a, x_b|
|
|
||||||
a = loop_.fetch([y, x_a], nil)
|
|
||||||
b = loop_.fetch([y, x_b], nil)
|
|
||||||
|
|
||||||
# it's a chunk if it's multiple empty tiles or a pipe that goes east
|
|
||||||
(a.nil? && b.nil?) || (a && TILE_NEIGHBOR_DELTAS.fetch(a).include?([0,1]))
|
|
||||||
}.select {|chunk|
|
|
||||||
# keep empty tiles
|
|
||||||
end_tiles = chunk.values_at(0, -1).map {|x| loop_.fetch([y,x], nil) }
|
|
||||||
next true if end_tiles.all?(&:nil?)
|
|
||||||
|
|
||||||
# only keep pipes that cross the horizontal axis
|
|
||||||
deltas = end_tiles.flat_map {|tile| TILE_NEIGHBOR_DELTAS.fetch(tile) }
|
|
||||||
[[-1,0], [1,0]].all? {|dy| deltas.include?(dy) }
|
|
||||||
}.sum {|chunk|
|
|
||||||
tiles = chunk.map {|x| loop_.fetch([y,x], nil) }
|
|
||||||
(tiles[0]...tiles[0]) ? tiles.count(nil) : 0 # lol
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
image = ARGF.readlines(chomp: true).map(&:chars)
|
|
||||||
empty_rows = image.filter_map.with_index {|row,y| row.all? { _1 == ?. } ? y : nil }
|
|
||||||
empty_cols = image.transpose.filter_map.with_index {|col,x| col.all? { _1 == ?. } ? x : nil }
|
|
||||||
|
|
||||||
galaxies = []
|
|
||||||
y = x = 0
|
|
||||||
image.each.with_index do |row, yy|
|
|
||||||
x = 0
|
|
||||||
row.each.with_index do |elem, xx|
|
|
||||||
galaxies << [y,x] if elem == ?#
|
|
||||||
x += 1
|
|
||||||
x += 999_999 if empty_cols.include?(xx)
|
|
||||||
end
|
|
||||||
|
|
||||||
y += 1
|
|
||||||
y += 999_999 if empty_rows.include?(yy)
|
|
||||||
end
|
|
||||||
|
|
||||||
p galaxies.combination(2).sum {|a, b|
|
|
||||||
a.zip(b).sum { (_1 - _2).abs }
|
|
||||||
}
|
|
||||||
|
|
||||||
# original part one
|
|
||||||
|
|
||||||
# image = ARGF.read
|
|
||||||
# image.gsub!(/^(\.+)$/m, "\\1\n\\1")
|
|
||||||
# image = image.split("\n").map(&:chars).transpose.map(&:join).join("\n")
|
|
||||||
# image.gsub!(/^(\.+)$/m, "\\1\n\\1")
|
|
||||||
# image = image.split("\n").map(&:chars)
|
|
||||||
|
|
||||||
# galaxies = image.flat_map.with_index {|row, y|
|
|
||||||
# row.filter_map.with_index {|elem, x| elem == ?# ? [y,x] : nil }
|
|
||||||
# }
|
|
||||||
|
|
||||||
# p galaxies.combination(2).sum {|a, b|
|
|
||||||
# a.zip(b).sum { (_1 - _2).abs }
|
|
||||||
# }
|
|
@ -1,70 +0,0 @@
|
|||||||
input = ARGF.readlines(chomp: true).map {|row|
|
|
||||||
springs, groups = row.split(" ")
|
|
||||||
[springs, groups.scan(/\d+/).map(&:to_i)]
|
|
||||||
}
|
|
||||||
|
|
||||||
p input
|
|
||||||
# .map { [ _1.chars, _2 ] }
|
|
||||||
.map { [Array.new(5, _1).join(??).chars, _2 * 5] }
|
|
||||||
.map {|springs, groups|
|
|
||||||
arrangement_counts = Hash.new {|h,k|
|
|
||||||
count, springs, groups = k
|
|
||||||
first, *rest = springs
|
|
||||||
h[k] = case [count, first, groups]
|
|
||||||
in count, _, []
|
|
||||||
if count.nonzero?
|
|
||||||
0
|
|
||||||
elsif springs.include?(?#)
|
|
||||||
0
|
|
||||||
else
|
|
||||||
1
|
|
||||||
end
|
|
||||||
in count, _, groups if count > groups.fetch(0)
|
|
||||||
0 # early exit if the damaged group ever gets too large
|
|
||||||
in count, nil, groups # no more springs
|
|
||||||
if groups.size > 1
|
|
||||||
0
|
|
||||||
elsif count == groups.fetch(0)
|
|
||||||
1
|
|
||||||
else
|
|
||||||
0
|
|
||||||
end
|
|
||||||
in count, ?#, groups # continue a damaged group
|
|
||||||
h[[count + 1, rest, groups]]
|
|
||||||
in 0, ?., groups
|
|
||||||
h[[0, rest, groups]]
|
|
||||||
in count, ?., groups # finish a damaged group
|
|
||||||
if count == groups.fetch(0)
|
|
||||||
h[[0, rest, groups[1..]]]
|
|
||||||
else
|
|
||||||
0
|
|
||||||
end
|
|
||||||
in count, ??, g if count == g.fetch(0) # unknown spring, matched current group
|
|
||||||
h[[0, rest, g[1..]]]
|
|
||||||
in count, ??, g unless count.zero? # unknown spring, ongoing group
|
|
||||||
h[[count + 1, rest, g]]
|
|
||||||
in count, ??, g # unknown spring
|
|
||||||
[
|
|
||||||
h[[count, rest, g]], # undamaged
|
|
||||||
h[[count + 1, rest, g]], # damaged
|
|
||||||
].sum
|
|
||||||
else
|
|
||||||
fail "#{{first:, springs: springs.join, groups:}}"
|
|
||||||
end
|
|
||||||
}
|
|
||||||
arrangement_counts[[0, springs, groups]]
|
|
||||||
}.sum
|
|
||||||
|
|
||||||
# original part one
|
|
||||||
# p input.map {|springs, groups|
|
|
||||||
# unknowns = springs.count(??)
|
|
||||||
# (0...2**unknowns).map {|arrangement|
|
|
||||||
# arrangement = arrangement.to_s(2).rjust(unknowns, ?0).chars.map { _1 == ?0 ? ?. : ?# }
|
|
||||||
# candidate = springs.gsub(??) { arrangement.shift }
|
|
||||||
# candidate.chars
|
|
||||||
# .slice_when { _1 != _2 }
|
|
||||||
# .reject { _1[0] == ?. }
|
|
||||||
# .map(&:size) == groups
|
|
||||||
# }.count(&:itself)
|
|
||||||
# }.sum
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
|||||||
def reflection_points(pattern)
|
|
||||||
(0.5...pattern.length-0.5).step(1).filter_map {|fold|
|
|
||||||
a = pattern[0..fold.floor]
|
|
||||||
b = pattern[fold.ceil..]
|
|
||||||
if a.reverse.zip(b).reject { _1.any?(&:nil?) }.all? { _1 == _2 }
|
|
||||||
fold
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
}.map(&:ceil)
|
|
||||||
end
|
|
||||||
|
|
||||||
Pattern = Data.define(:pattern) do
|
|
||||||
def reflection_axes
|
|
||||||
ary = to_a
|
|
||||||
reflection_points(ary).map { [:y, _1] } + reflection_points(ary.transpose).map { [:x, _1] }
|
|
||||||
end
|
|
||||||
|
|
||||||
def smudges
|
|
||||||
return enum_for(__method__) unless block_given?
|
|
||||||
|
|
||||||
max_y, max_x = extents
|
|
||||||
(0..max_y).each do |y|
|
|
||||||
(0..max_x).each do |x|
|
|
||||||
smudged = case pattern[[y,x]]
|
|
||||||
when ?# then ?.
|
|
||||||
when ?. then ?#
|
|
||||||
else fail
|
|
||||||
end
|
|
||||||
yield Pattern.new(pattern.merge({[y,x] => smudged}))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_a
|
|
||||||
max_y, max_x = extents
|
|
||||||
(0..max_y).map {|y|
|
|
||||||
(0..max_x).map {|x|
|
|
||||||
pattern.fetch([y,x])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
to_a.map(&:join).join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def extents
|
|
||||||
max_y = pattern.keys.map(&:first).max
|
|
||||||
max_x = pattern.keys.map(&:last).max
|
|
||||||
[max_y, max_x]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
patterns = ARGF.read.strip.split("\n\n")
|
|
||||||
.map {|pattern|
|
|
||||||
pattern.split("\n").map(&:chars)
|
|
||||||
.each.with_index.inject({}) {|h, (row, y)|
|
|
||||||
h.merge(row.each.with_index.to_h {|elem,x| [[y,x], elem]})
|
|
||||||
}
|
|
||||||
}.map { Pattern.new(_1) }
|
|
||||||
|
|
||||||
# part one
|
|
||||||
x, y = patterns.map { _1.reflection_axes.fetch(0) }
|
|
||||||
.partition {|axis,_| axis == :x }
|
|
||||||
.map { _1.map(&:last) } # keep index (discard axis)
|
|
||||||
p x.sum + y.sum { _1 * 100 }
|
|
||||||
|
|
||||||
# part two
|
|
||||||
|
|
||||||
x, y = patterns.map {|pattern|
|
|
||||||
original_reflection_axis = pattern.reflection_axes.fetch(0)
|
|
||||||
pattern.smudges.lazy
|
|
||||||
.flat_map { _1.reflection_axes}
|
|
||||||
.reject { _1 == original_reflection_axis }
|
|
||||||
.first
|
|
||||||
}.partition {|axis,_| axis == :x }
|
|
||||||
.map { _1.map(&:last) } # keep index (discard axis)
|
|
||||||
p x.sum + y.sum { _1 * 100 }
|
|
@ -1,54 +0,0 @@
|
|||||||
input = ARGF.readlines(chomp: true).map(&:chars)
|
|
||||||
|
|
||||||
# always tilts left
|
|
||||||
def tilt(platform)
|
|
||||||
platform
|
|
||||||
.map {|row| row.chunk_while { [_1, _2].tally.fetch(?#, 0).even? }}
|
|
||||||
.map {|row| row.flat_map { _1.sort.reverse }}
|
|
||||||
end
|
|
||||||
|
|
||||||
def load(platform)
|
|
||||||
platform.reverse
|
|
||||||
.each.with_index
|
|
||||||
.sum {|row, i| row.count(?O) * (i+1) }
|
|
||||||
end
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p load(tilt(input.transpose).transpose)
|
|
||||||
|
|
||||||
def spin_cycle(platform)
|
|
||||||
return enum_for(__method__, platform) unless block_given?
|
|
||||||
|
|
||||||
loop do
|
|
||||||
# north
|
|
||||||
platform = tilt(platform.transpose).transpose
|
|
||||||
|
|
||||||
# west
|
|
||||||
platform = tilt(platform)
|
|
||||||
|
|
||||||
# south
|
|
||||||
platform = tilt(platform.reverse.transpose).transpose.reverse
|
|
||||||
|
|
||||||
# east
|
|
||||||
platform = tilt(platform.map(&:reverse)).map(&:reverse)
|
|
||||||
|
|
||||||
yield platform
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# part two
|
|
||||||
spin = spin_cycle(input)
|
|
||||||
seen = {}
|
|
||||||
(1_000_000_000).times do |i|
|
|
||||||
platform = spin.next
|
|
||||||
|
|
||||||
if seen.has_key?(platform.hash)
|
|
||||||
start, _ = seen.fetch(platform.hash)
|
|
||||||
i = (1_000_000_000 - start) % (i+1 - start) + start
|
|
||||||
p seen.find {|_,(j,_)| j == i }.fetch(1).fetch(1)
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
|
|
||||||
seen[platform.hash] = [i+1, load(platform)]
|
|
||||||
end
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
|||||||
input = ARGF.read
|
|
||||||
|
|
||||||
def hash(label)
|
|
||||||
label.chars.inject(0) {|n,c|
|
|
||||||
(n + c.ord) * 17 % 256
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
# part one
|
|
||||||
p input.split(?,).sum { hash(_1) }
|
|
||||||
|
|
||||||
# part two
|
|
||||||
boxes = Hash.new {|h,k| h[k] = {} }
|
|
||||||
input.scan(/(\w+)([-=])(\d+)?/).each do |label, op, focal_length|
|
|
||||||
box = boxes[hash(label)]
|
|
||||||
case op
|
|
||||||
when ?-
|
|
||||||
box.delete(label)
|
|
||||||
when ?=
|
|
||||||
box[label] = focal_length.to_i
|
|
||||||
else
|
|
||||||
fail
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
p boxes.flat_map {|box_i, box|
|
|
||||||
box.map.with_index {|(label, focal_length), lens_i|
|
|
||||||
[1 + box_i, 1 + lens_i, focal_length].inject(:*)
|
|
||||||
}
|
|
||||||
}.sum
|
|
@ -1,51 +0,0 @@
|
|||||||
input = ARGF.readlines(chomp: true)
|
|
||||||
.flat_map.with_index {|row, y|
|
|
||||||
row.chars.map.with_index {|elem, x| [[y,x], elem] }
|
|
||||||
}.to_h
|
|
||||||
|
|
||||||
count_energized = ->(start, dir) {
|
|
||||||
current = [[start, dir]]
|
|
||||||
seen = Set.new
|
|
||||||
|
|
||||||
until current.empty?
|
|
||||||
coord, delta = current.shift
|
|
||||||
seen << [coord, delta]
|
|
||||||
|
|
||||||
next_delta = case [input[coord], delta]
|
|
||||||
in [nil, _]
|
|
||||||
[] # the beam has escaped the contraption
|
|
||||||
in [?., _] | [?|, [_,0]] | [?-, [0,_]] # keep going
|
|
||||||
[delta]
|
|
||||||
in [?|, [0,_]] # split up and down
|
|
||||||
[[-1,0], [1,0]]
|
|
||||||
in [?-, [_,0]] # split left and right
|
|
||||||
[[0,-1], [0,1]]
|
|
||||||
in [?/, _]
|
|
||||||
[delta.map { -_1 }.reverse]
|
|
||||||
in [?\\, _]
|
|
||||||
[delta.reverse]
|
|
||||||
else
|
|
||||||
fail
|
|
||||||
end
|
|
||||||
|
|
||||||
current.concat(
|
|
||||||
next_delta
|
|
||||||
.map {|d| [coord.zip(d).map { _1 + _2 }, d] }
|
|
||||||
.reject { seen.include?(_1) }
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
seen.map(&:first).select { input.has_key?(_1) }.uniq.size
|
|
||||||
}
|
|
||||||
|
|
||||||
max_y = input.keys.map(&:first).max
|
|
||||||
max_x = input.keys.map(&:last).max
|
|
||||||
|
|
||||||
candidates = [
|
|
||||||
(0..max_x).map { [[0,_1], [1,0]] }, # down
|
|
||||||
(0..max_x).map { [[max_y,_1], [-1,0]] }, # up
|
|
||||||
(0..max_y).map { [[_1,0], [0,1]] }, # right
|
|
||||||
(0..max_y).map { [[_1,max_x], [0,-1]] }, # left
|
|
||||||
].inject(:+)
|
|
||||||
|
|
||||||
p candidates.map { count_energized[*_1] }.max
|
|
@ -1,65 +0,0 @@
|
|||||||
def succ(coord, delta)
|
|
||||||
coord.zip(delta).map { _1 + _2 }
|
|
||||||
end
|
|
||||||
|
|
||||||
map = ARGF.readlines(chomp: true)
|
|
||||||
.flat_map.with_index {|row, y|
|
|
||||||
row.chars.map.with_index {|elem, x|
|
|
||||||
[[y,x], elem.to_i]
|
|
||||||
}
|
|
||||||
}.to_h
|
|
||||||
|
|
||||||
max_y = map.keys.map(&:first).max
|
|
||||||
max_x = map.keys.map(&:last).max
|
|
||||||
dest = [max_y,max_x]
|
|
||||||
|
|
||||||
Node = Data.define(:pos, :dir, :continued)
|
|
||||||
|
|
||||||
frontier = []
|
|
||||||
visited = {}
|
|
||||||
|
|
||||||
# seed initial directions
|
|
||||||
[
|
|
||||||
[1,0], # down
|
|
||||||
[0,1], # right
|
|
||||||
].each do |dir|
|
|
||||||
node = Node.new(dir, dir, 1)
|
|
||||||
frontier << node
|
|
||||||
visited[node] = map.fetch(dir)
|
|
||||||
end
|
|
||||||
|
|
||||||
loop do
|
|
||||||
frontier.sort_by! { visited.fetch(_1) }
|
|
||||||
current = frontier.shift
|
|
||||||
|
|
||||||
nexts = []
|
|
||||||
|
|
||||||
# turn left and right
|
|
||||||
if current.continued > 3
|
|
||||||
nexts.concat([current.dir.reverse, current.dir.reverse.map { -_1 }].map {|turn|
|
|
||||||
Node.new(current.pos.zip(turn).map { _1 + _2 }, turn, 1)
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
# keep going?
|
|
||||||
if current.continued < 10
|
|
||||||
nexts << Node.new(
|
|
||||||
current.pos.zip(current.dir).map { _1 + _2 },
|
|
||||||
current.dir,
|
|
||||||
current.continued + 1,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
if found = nexts.find { _1.pos == dest && (4..10).cover?(_1.continued) }
|
|
||||||
p visited.fetch(current) + map.fetch(dest)
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
|
|
||||||
nexts
|
|
||||||
.select { map.has_key?(_1.pos) }
|
|
||||||
.reject { visited.has_key?(_1) }
|
|
||||||
.each do |node|
|
|
||||||
frontier << node
|
|
||||||
visited[node] = visited.fetch(current) + map.fetch(node.pos)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,93 +0,0 @@
|
|||||||
require "matrix"
|
|
||||||
|
|
||||||
# part one
|
|
||||||
plan = ARGF.read.scan(/([UDLR])\s+(\d+)\s+\(#(\w+)\)/)
|
|
||||||
.map { [_1.to_sym, _2.to_i, _3] }
|
|
||||||
|
|
||||||
# part two
|
|
||||||
plan = plan.map { _3.chars }.map {|hex|
|
|
||||||
dist = hex[0..4].join.to_i(16)
|
|
||||||
dir = "RDLU".chars.fetch(hex.last.to_i).to_sym
|
|
||||||
[dir, dist]
|
|
||||||
}
|
|
||||||
|
|
||||||
deltas = { U: [-1,0], D: [1,0], L: [0,-1], R: [0,1] }
|
|
||||||
|
|
||||||
points = plan.inject([[0,0]]) {|points, (dir, dist, _)|
|
|
||||||
delta = deltas.fetch(dir).map { _1*dist }
|
|
||||||
next_point = points.last.zip(delta).map { _1 + _2 }
|
|
||||||
points << next_point
|
|
||||||
}
|
|
||||||
|
|
||||||
p [
|
|
||||||
(0.5 * points.each_cons(2).sum { Matrix.columns(_1).determinant }.abs).to_i,
|
|
||||||
plan.select {|dir,_,_| %i[ D L ].include?(dir) }.sum { _2 },
|
|
||||||
1,
|
|
||||||
].sum
|
|
||||||
|
|
||||||
# trench = plan.inject([[0,0]]) {|trench, (dir, dist, _)|
|
|
||||||
# delta = deltas.fetch(dir)
|
|
||||||
# dist.times do
|
|
||||||
# trench << trench.last.zip(delta).map { _1 + _2 }
|
|
||||||
# end
|
|
||||||
# trench
|
|
||||||
# }.uniq
|
|
||||||
|
|
||||||
# y_range = Range.new(*trench.map(&:first).minmax)
|
|
||||||
# x_range = Range.new(*trench.map(&:last).minmax)
|
|
||||||
|
|
||||||
# y_range.each do |y|
|
|
||||||
# x_range.each do |x|
|
|
||||||
# print trench.include?([y,x]) ? ?# : ?.
|
|
||||||
# end
|
|
||||||
# puts
|
|
||||||
# end
|
|
||||||
|
|
||||||
# part one
|
|
||||||
# lagoon = trench.to_set
|
|
||||||
|
|
||||||
# seed = [1, x_range.find {|x| lagoon.include?([0,x]) } + 1]
|
|
||||||
# frontier = [seed]
|
|
||||||
# until frontier.empty?
|
|
||||||
# current = frontier.shift
|
|
||||||
# lagoon << current
|
|
||||||
|
|
||||||
# frontier.concat(
|
|
||||||
# [[-1,0],[1,0],[0,-1],[0,1]].map {|delta|
|
|
||||||
# current.zip(delta).map { _1 + _2 }
|
|
||||||
# }.reject { lagoon.include?(_1) || frontier.include?(_1) }
|
|
||||||
# )
|
|
||||||
# end
|
|
||||||
|
|
||||||
# p lagoon.size
|
|
||||||
|
|
||||||
# row_counts = {}
|
|
||||||
|
|
||||||
# count = trench.size
|
|
||||||
# y_range.each do |y|
|
|
||||||
# inside = nil
|
|
||||||
|
|
||||||
# segments = trench.select {|y_,_| y_ == y }.map(&:last).sort.slice_when { _1+1 != _2 }
|
|
||||||
# if row_count = row_counts[segments]
|
|
||||||
# count += row_count
|
|
||||||
# next
|
|
||||||
# end
|
|
||||||
|
|
||||||
# row_count = 0
|
|
||||||
# segments.each do |segment|
|
|
||||||
# if [-1,1].all? {|dy| [[y+dy,segment[0]],[y+dy,segment[-1]]].any? { trench.include?(_1) }}
|
|
||||||
# if inside
|
|
||||||
# row_count += segment[0] - inside
|
|
||||||
# inside = nil
|
|
||||||
# else
|
|
||||||
# inside = segment[-1] + 1
|
|
||||||
# end
|
|
||||||
# elsif inside
|
|
||||||
# row_count += segment[0] - inside
|
|
||||||
# inside = segment[-1] + 1
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# row_counts[segments] = row_count
|
|
||||||
# count += row_count
|
|
||||||
# end
|
|
||||||
# p count
|
|
@ -1,20 +0,0 @@
|
|||||||
workflows, parts = ARGF.read.split("\n\n")
|
|
||||||
|
|
||||||
Part = Data.define(:x, :m, :a, :s)
|
|
||||||
|
|
||||||
parts = parts.lines(chomp: true).map { Part.new(**eval(_1.gsub(?=, ?:))) }
|
|
||||||
|
|
||||||
workflows = workflows.scan(/(\w+)\{((?~}))\}/).to_h {|name, rules|
|
|
||||||
rules = rules.split(?,).map {|rule|
|
|
||||||
rule.include?(?:) ? rule.split(?:) : ["true", rule]
|
|
||||||
}
|
|
||||||
[name, rules]
|
|
||||||
}
|
|
||||||
|
|
||||||
pp parts.select {|part|
|
|
||||||
workflow = "in"
|
|
||||||
until %w[A R].include?(workflow) do
|
|
||||||
workflow = workflows.fetch(workflow).find {|cond,_| part.instance_eval(cond) }.last
|
|
||||||
end
|
|
||||||
workflow == ?A
|
|
||||||
}.sum { _1.instance_eval { x + m + a + s }}
|
|
@ -1,7 +0,0 @@
|
|||||||
Input ← &fras "../day_01.txt"
|
|
||||||
Lines ← ⊜□≠, @\n Input
|
|
||||||
|
|
||||||
Digits ← +@1⇡9
|
|
||||||
CalibrationValue ← /+ parse ⊏0_¯1 ▽≡/+ ∵(⌕:Digits).
|
|
||||||
|
|
||||||
/+ ⊐∵CalibrationValue Lines
|
|
@ -1,4 +0,0 @@
|
|||||||
&fras "../day_04.txt"
|
|
||||||
|
|
||||||
# 36 numbers per card is 1 card id, 10 winning numbers, and 25 card numbers
|
|
||||||
/+≡(⌊ⁿ:2-1/+∊⊃↙↘10↘1) ↯¯1_36 ∵(parse⊔) regex "\\d+"
|
|
@ -1,9 +0,0 @@
|
|||||||
Input ← regex"\\d+" &fras "../day_06.txt"
|
|
||||||
|
|
||||||
# part one
|
|
||||||
Races ← ⍉↯2_¯1 ⊐∵⋕ Input
|
|
||||||
/×≡(/+<×⊃-∘⇡.⍘⊟) Races
|
|
||||||
|
|
||||||
# part two
|
|
||||||
Races ← ∵⋕⊐≡/⊂ ↯2_¯1 Input
|
|
||||||
/+<×⊃-∘⇡.⍘⊟ Races
|
|
@ -1,12 +0,0 @@
|
|||||||
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"
|
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||||
|
}
|
Loading…
Reference in new issue