Compare commits
No commits in common. "3d5c13cf6af52da0e30481a4bfadc689151de69f" and "15128fbddf3917761bac488649d633af88841d90" have entirely different histories.
3d5c13cf6a
...
15128fbddf
45
day4.cr
45
day4.cr
@ -1,6 +1,20 @@
|
|||||||
require "./passports.cr"
|
|
||||||
INPUT = File.read("day4.txt")
|
INPUT = File.read("day4.txt")
|
||||||
|
|
||||||
|
def parse_passport(string)
|
||||||
|
new_hash = {} of String => String
|
||||||
|
string.split(" ").each do |field|
|
||||||
|
k,v = field.split(":")
|
||||||
|
new_hash[k] = v
|
||||||
|
end
|
||||||
|
new_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_passports(lines)
|
||||||
|
lines.split(/\n\n/).map do |s|
|
||||||
|
parse_passport(s.chomp.gsub(/\n/, " "))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def part1
|
def part1
|
||||||
input = INPUT.clone
|
input = INPUT.clone
|
||||||
passports = parse_passports(input)
|
passports = parse_passports(input)
|
||||||
@ -12,16 +26,35 @@ def part1
|
|||||||
puts total
|
puts total
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_range(range)
|
||||||
|
->(s : String) { s.to_i32?.try { |i| range.includes? i } }
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_regex(regex)
|
||||||
|
->(s : String) { s.matches?(regex) }
|
||||||
|
end
|
||||||
|
|
||||||
def part2
|
def part2
|
||||||
input = INPUT.clone
|
input = INPUT.clone
|
||||||
passports = parse_passports(input)
|
passports = parse_passports(input)
|
||||||
valid_passports = [] of Passport
|
validators = {
|
||||||
passports.each do |p|
|
"byr" => validate_range(1920..2002),
|
||||||
if vp = Passport.from_hash?(p)
|
"iyr" => validate_range(2010..2020),
|
||||||
valid_passports << vp
|
"eyr" => validate_range(2020..2030),
|
||||||
|
"hgt" => ->(s : String) {
|
||||||
|
return false unless s.match(/^(\d+)(cm|in)$/)
|
||||||
|
validate_range($~[2] == "cm" ? (150..193) : (59..76)).call($~[1])
|
||||||
|
},
|
||||||
|
"hcl" => validate_regex(/^#[0-9a-f]{6}$/),
|
||||||
|
"ecl" => ->(s : String) { "amb blu brn gry grn hzl oth".split(" ").includes? s },
|
||||||
|
"pid" => ->(s : String) { s =~ /^[0-9]{9}$/ },
|
||||||
|
}
|
||||||
|
total = passports.count do |passport|
|
||||||
|
validators.all? do |k, v|
|
||||||
|
passport[k]?.try { |s| v.call(s) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
puts valid_passports.size
|
puts total
|
||||||
end
|
end
|
||||||
|
|
||||||
part1
|
part1
|
||||||
|
55
day5.cr
55
day5.cr
@ -1,55 +0,0 @@
|
|||||||
INPUT = File.read("day5.txt").lines.map(&.chomp)
|
|
||||||
|
|
||||||
def partition(choices, list)
|
|
||||||
b = 0
|
|
||||||
e = list.size
|
|
||||||
choices.chars.each do |c|
|
|
||||||
b = (b+e)//2 if c == 'B' || c == 'R'
|
|
||||||
e = (b+e)//2 if c == 'F' || c == 'L'
|
|
||||||
end
|
|
||||||
|
|
||||||
return {b,e}
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_id(str)
|
|
||||||
col = str[0..6]
|
|
||||||
row = str[7..]
|
|
||||||
{partition(col, (0..127).to_a)[0], partition(row, (0..7).to_a)[0]}
|
|
||||||
end
|
|
||||||
|
|
||||||
def id(t)
|
|
||||||
r, c = t
|
|
||||||
r * 8 + c
|
|
||||||
end
|
|
||||||
|
|
||||||
def part1
|
|
||||||
input = INPUT.clone
|
|
||||||
max = input.max_of do |line|
|
|
||||||
r, c = get_id(line)
|
|
||||||
r * 8 + c
|
|
||||||
end
|
|
||||||
puts max
|
|
||||||
end
|
|
||||||
|
|
||||||
def part2
|
|
||||||
input = INPUT.clone
|
|
||||||
seen = Set(Int32).new
|
|
||||||
max = input.each do |line|
|
|
||||||
seen << id(get_id(line))
|
|
||||||
end
|
|
||||||
candidates = [] of Int32
|
|
||||||
128.times do |r|
|
|
||||||
next if r == 0 || r == 127
|
|
||||||
8.times do |c|
|
|
||||||
next if seen.includes? id({r, c})
|
|
||||||
candidates << id({r,c})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
candidates = candidates.select do |i|
|
|
||||||
seen.includes?(i-1) && seen.includes?(i+1)
|
|
||||||
end
|
|
||||||
puts candidates[0]
|
|
||||||
end
|
|
||||||
|
|
||||||
part1
|
|
||||||
part2
|
|
48
graph.cr
48
graph.cr
@ -1,48 +0,0 @@
|
|||||||
class Graph(A)
|
|
||||||
def initialize
|
|
||||||
@edges = {} of A => Set({A, Int32})
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_edge(f, t, c = 1)
|
|
||||||
@edges[f] ||= Set({A, Int32}).new
|
|
||||||
@edges[f] << {t, c}
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_biedge(f, t, c = 1)
|
|
||||||
add_edge(f, t, c)
|
|
||||||
add_edge(t, f, c)
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_path(f, t)
|
|
||||||
visited = Set(A).new
|
|
||||||
candidates = Set { f }
|
|
||||||
distances = {f => 0}
|
|
||||||
prev = {} of A => A
|
|
||||||
|
|
||||||
while !candidates.empty?
|
|
||||||
candidate = candidates.min_by { |c| distances[c] }
|
|
||||||
break if candidate == t
|
|
||||||
visited << candidate
|
|
||||||
candidates.delete candidate
|
|
||||||
dist = distances[candidate]
|
|
||||||
|
|
||||||
@edges.fetch(candidate, Set({A, Int32}).new).each do |e|
|
|
||||||
node, cost = e
|
|
||||||
new_dist = dist + cost
|
|
||||||
candidates << node unless visited.includes? node
|
|
||||||
next if (old_dist = distances[node]?) && old_dist < new_dist
|
|
||||||
distances[node] = new_dist
|
|
||||||
prev[node] = candidate
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
backtrack = t
|
|
||||||
path = [t] of A
|
|
||||||
while backtrack != f
|
|
||||||
return nil unless prev_bt = prev[backtrack]?
|
|
||||||
path << prev_bt
|
|
||||||
backtrack = prev_bt
|
|
||||||
end
|
|
||||||
{path.reverse!, distances[t]}
|
|
||||||
end
|
|
||||||
end
|
|
86
passports.cr
86
passports.cr
@ -1,86 +0,0 @@
|
|||||||
def parse_passport(string)
|
|
||||||
new_hash = {} of String => String
|
|
||||||
string.split(" ").each do |field|
|
|
||||||
k,v = field.split(":")
|
|
||||||
new_hash[k] = v
|
|
||||||
end
|
|
||||||
new_hash
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_passports(lines)
|
|
||||||
lines.split(/\n\n/).map do |s|
|
|
||||||
parse_passport(s.chomp.gsub(/\n/, " "))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Validator(T, R)
|
|
||||||
def initialize(@proc : Proc(T, R?))
|
|
||||||
end
|
|
||||||
|
|
||||||
def >>(other)
|
|
||||||
Validator.new(->(i : T) { @proc.call(i).try { |j| other.@proc.call(j) } })
|
|
||||||
end
|
|
||||||
|
|
||||||
def then(&block : R -> S?) forall S
|
|
||||||
Validator(T, S).new(->(i : T) { @proc.call(i).try { |j| block.call(j) } })
|
|
||||||
end
|
|
||||||
|
|
||||||
def run(input)
|
|
||||||
@proc.call(input)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Hash(K,V)
|
|
||||||
def validate(k, vl)
|
|
||||||
self[k]?.try { |v| vl.run(v) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def range(range) : Validator(Int32, Int32)
|
|
||||||
Validator.new ->(i : Int32) { (range.includes? i) ? i : nil }
|
|
||||||
end
|
|
||||||
|
|
||||||
def int : Validator(String, Int32)
|
|
||||||
Validator.new ->(s : String) { s.to_i32? }
|
|
||||||
end
|
|
||||||
|
|
||||||
def regex(regex) : Validator(String, Regex::MatchData)
|
|
||||||
Validator(String, Regex::MatchData).new ->(s : String) { s.match(regex) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def oneof(strs : Array(A)) : Validator(A, A) forall A
|
|
||||||
Validator(String, String).new ->(s : String) { (strs.includes? s) ? s : nil }
|
|
||||||
end
|
|
||||||
|
|
||||||
def length(len) : Validator(String, String)
|
|
||||||
Validator(String, String).new ->(s : String) { (s.size == len) ? s : nil }
|
|
||||||
end
|
|
||||||
|
|
||||||
def year(rng) : Validator(String, Int32)
|
|
||||||
length(4) >> int >> range(rng)
|
|
||||||
end
|
|
||||||
|
|
||||||
def unit_range(map) : Validator(String, {String, Int32})
|
|
||||||
regex(/(\d+)([a-zA-Z]+)/).then do |md|
|
|
||||||
map[md[2]]?.try { |r| (int >> range(r)).run(md[1]).try { |i| {md[2], i} } }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Passport
|
|
||||||
def initialize(
|
|
||||||
@byr : Int32, @iyr : Int32,
|
|
||||||
@eyr : Int32, @hgt : {String, Int32},
|
|
||||||
@hcl : String, @ecl : String, @pid : Int32)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.from_hash?(hash)
|
|
||||||
return nil unless byr = hash.validate("byr", year(1920..2002))
|
|
||||||
return nil unless iyr = hash.validate("iyr", year(2010..2020))
|
|
||||||
return nil unless eyr = hash.validate("eyr", year(2020..2030))
|
|
||||||
return nil unless hgt = hash.validate("hgt", unit_range({"cm" => (150..193), "in" => (59..76)}))
|
|
||||||
return nil unless hcl = hash.validate("hcl", regex(/^#([0-9a-f]{6})$/).then { |d| d[1] })
|
|
||||||
return nil unless ecl = hash.validate("ecl", oneof(["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]))
|
|
||||||
return nil unless pid = hash.validate("pid", length(9) >> int)
|
|
||||||
Passport.new(byr, iyr, eyr, hgt, hcl, ecl, pid)
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue
Block a user