Finished day 5, part 2!
This commit is contained in:
1 parent
1d19b0548a
commit
4392344bc4
7 files changed
+211
-22
No files matched your search
+1
-1
@@ -39,7 +39,7 @@ def get_calibration_code(line)
|
||||
end
|
||||
|
||||
def get_sum_of_calibration_code(document)
|
||||
calibration_codes = document.split("\n").hash do |line|
|
||||
calibration_codes = document.split("\n").map do |line|
|
||||
get_calibration_code line
|
||||
end
|
||||
calibration_codes.reduce 0, :+
|
||||
|
||||
+2
-2
@@ -43,13 +43,13 @@ class Game
|
||||
def self.deserialize(line)
|
||||
id = /\s*Game\s+(\d+):/.match(line)[1].to_i
|
||||
draws_as_text = line[line.index(":") + 1..]
|
||||
draws = draws_as_text.split(";").hash(&Draw.method(:deserialize))
|
||||
draws = draws_as_text.split(";").map(&Draw.method(:deserialize))
|
||||
self.new id, draws
|
||||
end
|
||||
|
||||
def fewer_number_of_cubes
|
||||
[:blue, :red, :green].map do |color|
|
||||
@draws.hash {|draw| draw.send color }
|
||||
@draws.map {|draw| draw.send color }
|
||||
.max || 0
|
||||
end
|
||||
end
|
||||
|
||||
+8
-8
@@ -98,7 +98,7 @@ class EngineLine
|
||||
|
||||
def extract_engine_numbers
|
||||
digit_indexes = extract_digit_indexes @line
|
||||
group_digit_indexes(digit_indexes).hash &method(:create_engine_number)
|
||||
group_digit_indexes(digit_indexes).map &method(:create_engine_number)
|
||||
end
|
||||
|
||||
def extract_gears
|
||||
@@ -119,13 +119,13 @@ class Engine
|
||||
end
|
||||
|
||||
def self.deserialize(ser)
|
||||
els = ser.strip.split("\n").each_with_index.hash { |line, idx| EngineLine.new idx, line}
|
||||
els = ser.strip.split("\n").each_with_index.map { |line, idx| EngineLine.new idx, line}
|
||||
return self.new els
|
||||
end
|
||||
|
||||
def extract_engine_numbers
|
||||
@engine_lines
|
||||
.hash {|line| line.extract_engine_numbers}
|
||||
.map {|line| line.extract_engine_numbers}
|
||||
.flatten
|
||||
end
|
||||
|
||||
@@ -159,7 +159,7 @@ class Engine
|
||||
|
||||
def is_adjacent(engine_number, gear)
|
||||
gear.get_neighbourhood
|
||||
.hash {|point| engine_number.is_located_on(point[:line_index], point[:column_index])}
|
||||
.map {|point| engine_number.is_located_on(point[:line_index], point[:column_index])}
|
||||
.any?
|
||||
end
|
||||
|
||||
@@ -170,15 +170,15 @@ class Engine
|
||||
|
||||
def extract_gears
|
||||
@engine_lines
|
||||
.hash {|line| line.extract_gears}
|
||||
.map {|line| line.extract_gears}
|
||||
.flatten
|
||||
end
|
||||
|
||||
def get_gear_ratios
|
||||
extract_gears
|
||||
.hash {|gear| get_adjacent_number_parts(gear)}
|
||||
.map {|gear| get_adjacent_number_parts(gear)}
|
||||
.filter {|adjacent_numbers| adjacent_numbers.length == 2}
|
||||
.hash {|adjacent_numbers| adjacent_numbers.hash {|a| a.value}.reduce(1, :*)}
|
||||
.map {|adjacent_numbers| adjacent_numbers.map {|a| a.value}.reduce(1, :*)}
|
||||
end
|
||||
attr_accessor :engine_lines
|
||||
end
|
||||
@@ -190,6 +190,6 @@ input_content = File.open(input_file_name).read
|
||||
|
||||
engine = Engine.deserialize input_content
|
||||
|
||||
puts engine.extract_engine_numbers_that_touches_symbols.hash {|e| e.value}.sum
|
||||
puts engine.extract_engine_numbers_that_touches_symbols.map {|e| e.value}.sum
|
||||
puts engine.get_gear_ratios.sum
|
||||
|
||||
@@ -36,6 +36,7 @@ class Day3Test < Test::Unit::TestCase
|
||||
assert_equal [1, 2] + [3, 4], [1,2,3,4]
|
||||
|
||||
|
||||
# assert_equal ((1..5) + (6..10)).to_a, [1,2,3,4,5,6,7,8,9,10]
|
||||
|
||||
end
|
||||
end
|
||||
@@ -67,7 +68,7 @@ class EngineLineTest < Test::Unit::TestCase
|
||||
def test_extract_engine_numbers
|
||||
engine = Engine.deserialize @@easy_engine
|
||||
expt = [467, 114, 35, 633, 617, 58, 592, 755, 664, 598]
|
||||
assert_equal expt, engine.extract_engine_numbers.hash {|e| e.value}
|
||||
assert_equal expt, engine.extract_engine_numbers.map {|e| e.value}
|
||||
end
|
||||
|
||||
def test_touches_symbol
|
||||
@@ -79,7 +80,7 @@ class EngineLineTest < Test::Unit::TestCase
|
||||
def test_extract_engine_numbers_that_touches_symbols
|
||||
engine = Engine.deserialize @@easy_engine
|
||||
expt = [467, 35, 633, 617, 592, 755, 664, 598]
|
||||
assert_equal expt, engine.extract_engine_numbers_that_touches_symbols.hash {|e| e.value}
|
||||
assert_equal expt, engine.extract_engine_numbers_that_touches_symbols.map {|e| e.value}
|
||||
end
|
||||
|
||||
def test_empty
|
||||
@@ -96,14 +97,14 @@ class EngineLineTest < Test::Unit::TestCase
|
||||
.........."
|
||||
engine = Engine.deserialize input
|
||||
expt = []
|
||||
assert_equal expt, engine.extract_engine_numbers_that_touches_symbols.hash {|e| e.value}
|
||||
assert_equal expt, engine.extract_engine_numbers_that_touches_symbols.map {|e| e.value}
|
||||
end
|
||||
|
||||
|
||||
def test_day_3_part_1_easy
|
||||
engine = Engine.deserialize @@easy_engine
|
||||
expt = 4361
|
||||
assert_equal expt, engine.extract_engine_numbers_that_touches_symbols.hash {|e| e.value}.sum
|
||||
assert_equal expt, engine.extract_engine_numbers_that_touches_symbols.map {|e| e.value}.sum
|
||||
end
|
||||
|
||||
def test_extract_gears
|
||||
|
||||
+5
-5
@@ -19,8 +19,8 @@ class Card
|
||||
def self.deserialize(line)
|
||||
id_match = /Card\s+(\d+)/.match(line)
|
||||
id = id_match[1].to_i
|
||||
winning_numbers = line[(line.index(":") + 1)..(line.index("|") - 1)].split(/\s+/).filter {|x| !x.empty?}.hash {|x| x.to_i}
|
||||
selected_numbers = line[(line.index("|") + 1)..line.length].split(/\s+/).filter {|x| !x.empty?}.hash {|x| x.to_i}
|
||||
winning_numbers = line[(line.index(":") + 1)..(line.index("|") - 1)].split(/\s+/).filter {|x| !x.empty?}.map {|x| x.to_i}
|
||||
selected_numbers = line[(line.index("|") + 1)..line.length].split(/\s+/).filter {|x| !x.empty?}.map {|x| x.to_i}
|
||||
Card.new id, selected_numbers, winning_numbers
|
||||
end
|
||||
|
||||
@@ -40,12 +40,12 @@ class Cards
|
||||
cards = ser
|
||||
.split("\n")
|
||||
.filter {|line| !line.empty?}
|
||||
.hash {|line| Card.deserialize line}
|
||||
.map {|line| Card.deserialize line}
|
||||
self.new cards
|
||||
end
|
||||
|
||||
def scores
|
||||
@cards.hash {|card| card.score}
|
||||
@cards.map {|card| card.score}
|
||||
end
|
||||
|
||||
def scratchcards_generated_by_card(card)
|
||||
@@ -57,7 +57,7 @@ class Cards
|
||||
if score > 0
|
||||
sub_cards = @cards.filter {|sub_card| sub_card.id > card.id and sub_card.id <= card.id + score }
|
||||
ret += sub_cards
|
||||
.hash {|sub_card| scratchcards_generated_by_card(sub_card)}
|
||||
.map {|sub_card| scratchcards_generated_by_card(sub_card)}
|
||||
.flatten
|
||||
end
|
||||
@scratchcards_generated_by_card_cache[card.id] = ret
|
||||
|
||||
+110
-1
@@ -8,13 +8,25 @@ class WeirMapRange
|
||||
end
|
||||
|
||||
def includes_source?(source)
|
||||
@source <= source and source <= (@source + @range_length)
|
||||
@source <= source and source < (@source + @range_length)
|
||||
end
|
||||
|
||||
def includes_destination?(destination)
|
||||
@destination <= destination and destination < (@destination + @range_length)
|
||||
end
|
||||
|
||||
def source_for_destination(destination)
|
||||
destination + @source - @destination
|
||||
end
|
||||
|
||||
def destination_for_source(source)
|
||||
@destination + (source - @source)
|
||||
end
|
||||
|
||||
def critical_points
|
||||
[@source - 1, @source, @source + @range_length, @source + @range_length + 1]
|
||||
end
|
||||
|
||||
def self.deserialize(ser)
|
||||
parts = ser.strip.split(/\s+/).map {|p| p.to_i}
|
||||
self.new parts[0], parts[1], parts[2]
|
||||
@@ -30,6 +42,15 @@ class WeirdMap
|
||||
@weird_map_ranges = weird_map_ranges
|
||||
end
|
||||
|
||||
def preimage_of(destination)
|
||||
@weird_map_ranges.each do |wmr|
|
||||
if wmr.includes_destination? destination
|
||||
return wmr.source_for_destination destination
|
||||
end
|
||||
end
|
||||
destination
|
||||
end
|
||||
|
||||
def [](source)
|
||||
@weird_map_ranges.each do |wmr|
|
||||
if wmr.includes_source? source
|
||||
@@ -45,6 +66,12 @@ class WeirdMap
|
||||
.map {|line| WeirMapRange.deserialize line}
|
||||
self.new wmr
|
||||
end
|
||||
|
||||
def critical_points
|
||||
@weird_map_ranges.map {|r| r.critical_points} .flatten
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -66,6 +93,14 @@ class TodoMap
|
||||
@hash[source]
|
||||
end
|
||||
|
||||
def critical_points
|
||||
@hash.critical_points
|
||||
end
|
||||
|
||||
def preimage_of(value)
|
||||
@hash.preimage_of value
|
||||
end
|
||||
|
||||
attr_accessor :from
|
||||
attr_accessor :to
|
||||
attr_accessor :hash
|
||||
@@ -98,12 +133,86 @@ class PlanningMaps
|
||||
attr_accessor :seeds
|
||||
end
|
||||
|
||||
class PlanningMapsWithSeedRanges
|
||||
def initialize(seed_ranges, toto_maps)
|
||||
@seed_ranges = seed_ranges
|
||||
@toto_maps = toto_maps
|
||||
end
|
||||
|
||||
def [](source)
|
||||
ret = source
|
||||
@toto_maps.each {|tm| ret = tm[ret]}
|
||||
ret
|
||||
end
|
||||
|
||||
def self.deserialize_seed_ranges(ser_arr)
|
||||
ser_arr.each_slice(2).map {|start, length| (start...(start + length))}
|
||||
end
|
||||
|
||||
def self.deserialize(ser)
|
||||
blocks = ser.strip.split(/^$/)
|
||||
seeds = blocks[0].split(" ")[(1..)].map {|s| s.to_i}
|
||||
toto_maps = blocks[(1..)].map {|b| TodoMap.deserialize b}
|
||||
self.new(self.deserialize_seed_ranges(seeds), toto_maps)
|
||||
end
|
||||
|
||||
def _preimage_of(value, weird_maps)
|
||||
ret = value
|
||||
weird_maps.each do |weird_map|
|
||||
ret = weird_map.preimage_of ret
|
||||
end
|
||||
ret
|
||||
end
|
||||
|
||||
def _critical_points_of(idx)
|
||||
@toto_maps[idx].critical_points.map {|p| _preimage_of(p, @toto_maps[0...idx])}
|
||||
end
|
||||
|
||||
def critical_points
|
||||
(0...@toto_maps.length).map {|idx| _critical_points_of idx}.flatten.uniq.sort
|
||||
end
|
||||
|
||||
def critical_points_in_range(seed_range)
|
||||
underlying_critical_points = critical_points
|
||||
(underlying_critical_points + [seed_range.min, seed_range.max]).filter {|p| seed_range.include? p}
|
||||
end
|
||||
|
||||
def min_of_seed_range(seed_range)
|
||||
cpts = critical_points_in_range(seed_range)
|
||||
cpts.map {|s| self[s]}.min
|
||||
end
|
||||
|
||||
def all_seeds
|
||||
@seed_ranges.map {|r| r.to_a}.flatten
|
||||
end
|
||||
|
||||
def min_destinations
|
||||
@seed_ranges.map {|seed_range| min_of_seed_range seed_range}.min
|
||||
end
|
||||
|
||||
def min_destinations_brute_force
|
||||
all_seeds.map {|s| self[s]}.min
|
||||
end
|
||||
|
||||
def seed_of(destination)
|
||||
all_seeds.each do |s|
|
||||
if self[s] == destination
|
||||
return s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :seed_ranges
|
||||
end
|
||||
|
||||
|
||||
if __FILE__ == $0
|
||||
input_file_name = File.join(File.dirname(__FILE__), "day_5_input.txt")
|
||||
input_content = File.open(input_file_name).read
|
||||
pms = PlanningMaps.deserialize input_content
|
||||
pmswsr = PlanningMapsWithSeedRanges.deserialize input_content
|
||||
|
||||
puts "Solution to part 1: #{pms.min_destinations}"
|
||||
puts "Solution to part 2: #{pmswsr.min_destinations}"
|
||||
|
||||
end
|
||||
+80
-1
@@ -12,6 +12,29 @@ class TestWeirMapRange < Test::Unit::TestCase
|
||||
assert_equal 52, wmr.source
|
||||
assert_equal 2, wmr.range_length
|
||||
end
|
||||
|
||||
def test_happy_path
|
||||
wmr = WeirMapRange.deserialize "37 52 2"
|
||||
assert_false wmr.includes_destination? 36
|
||||
assert_true wmr.includes_destination? 37
|
||||
assert_true wmr.includes_destination? 38
|
||||
assert_false wmr.includes_destination? 39
|
||||
|
||||
|
||||
assert_false wmr.includes_source? 51
|
||||
assert_true wmr.includes_source? 52
|
||||
assert_true wmr.includes_source? 53
|
||||
assert_false wmr.includes_source? 54
|
||||
|
||||
[51, 52, 53, 54].each do |source|
|
||||
assert_equal(source, wmr.source_for_destination(wmr.destination_for_source(source)))
|
||||
end
|
||||
|
||||
[36,37,38,39].each do |destination|
|
||||
assert_equal(destination, wmr.destination_for_source(wmr.source_for_destination(destination)))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -91,6 +114,62 @@ humidity-to-location map:
|
||||
|
||||
def test_day_4_part_1
|
||||
pms = PlanningMaps.deserialize @@easy_input
|
||||
assert_equal 2, pms.min_destinations
|
||||
assert_equal 35, pms.min_destinations
|
||||
end
|
||||
end
|
||||
|
||||
class TestPlanningMapsWithSeedRanges < Test::Unit::TestCase
|
||||
|
||||
@@easy_input = "seeds: 79 14 55 13
|
||||
|
||||
seed-to-soil map:
|
||||
50 98 2
|
||||
52 50 48
|
||||
|
||||
soil-to-fertilizer map:
|
||||
0 15 37
|
||||
37 52 2
|
||||
39 0 15
|
||||
|
||||
fertilizer-to-water map:
|
||||
49 53 8
|
||||
0 11 42
|
||||
42 0 7
|
||||
57 7 4
|
||||
|
||||
water-to-light map:
|
||||
88 18 7
|
||||
18 25 70
|
||||
|
||||
light-to-temperature map:
|
||||
45 77 23
|
||||
81 45 19
|
||||
68 64 13
|
||||
|
||||
temperature-to-humidity map:
|
||||
0 69 1
|
||||
1 0 69
|
||||
|
||||
humidity-to-location map:
|
||||
60 56 37
|
||||
56 93 4"
|
||||
|
||||
def test_deserialization
|
||||
pms = PlanningMapsWithSeedRanges.deserialize @@easy_input
|
||||
expt = (79..92).to_a + (55..67).to_a
|
||||
assert_equal(expt, pms.seed_ranges.map {|r| r.to_a} .flatten)
|
||||
end
|
||||
|
||||
def test_brute_force
|
||||
pms = PlanningMapsWithSeedRanges.deserialize @@easy_input
|
||||
assert_equal 46, pms.min_destinations_brute_force
|
||||
assert_equal( 82, pms.seed_of(46))
|
||||
end
|
||||
|
||||
def test_day_5_part_2
|
||||
pms = PlanningMapsWithSeedRanges.deserialize @@easy_input
|
||||
assert_equal 46, pms.min_destinations
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
Reference in new issue
Block a user