diff --git a/2015/README.md b/2015/README.md index 5cd7c25..5b08d31 100644 --- a/2015/README.md +++ b/2015/README.md @@ -15,7 +15,7 @@ | ✓ | 11 | Ruby | ✓ | 12 | Ruby | ✓ | 13 | Ruby -| | 14 | +| ✓ | 14 | Ruby | | 15 | | | 16 | | | 17 | diff --git a/2015/day-14/.ruby-version b/2015/day-14/.ruby-version new file mode 100644 index 0000000..4a36342 --- /dev/null +++ b/2015/day-14/.ruby-version @@ -0,0 +1 @@ +3.0.0 diff --git a/2015/day-14/inputs/puzzle.txt b/2015/day-14/inputs/puzzle.txt new file mode 100644 index 0000000..2d7c9cd --- /dev/null +++ b/2015/day-14/inputs/puzzle.txt @@ -0,0 +1,9 @@ +Rudolph can fly 22 km/s for 8 seconds, but then must rest for 165 seconds. +Cupid can fly 8 km/s for 17 seconds, but then must rest for 114 seconds. +Prancer can fly 18 km/s for 6 seconds, but then must rest for 103 seconds. +Donner can fly 25 km/s for 6 seconds, but then must rest for 145 seconds. +Dasher can fly 11 km/s for 12 seconds, but then must rest for 125 seconds. +Comet can fly 21 km/s for 6 seconds, but then must rest for 121 seconds. +Blitzen can fly 18 km/s for 3 seconds, but then must rest for 50 seconds. +Vixen can fly 20 km/s for 4 seconds, but then must rest for 75 seconds. +Dancer can fly 7 km/s for 20 seconds, but then must rest for 119 seconds. diff --git a/2015/day-14/inputs/test.txt b/2015/day-14/inputs/test.txt new file mode 100644 index 0000000..706ceae --- /dev/null +++ b/2015/day-14/inputs/test.txt @@ -0,0 +1,2 @@ +Comet can fly 14 km/s for 10 seconds, but then must rest for 127 seconds. +Dancer can fly 16 km/s for 11 seconds, but then must rest for 162 seconds. diff --git a/2015/day-14/main.rb b/2015/day-14/main.rb new file mode 100755 index 0000000..1cc6c45 --- /dev/null +++ b/2015/day-14/main.rb @@ -0,0 +1,56 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "pathname" + +Item = Struct.new(:name, :speed, :active_time, :recovery_time) + +def parse_file(file) + file.each_line.map do |line| + line.partition(" can fly ") => [name, _, tail] + tail.partition(" km/s for ") => [speed, _, tail] + tail.partition(" seconds, but then must rest for ") => [active_time, _, tail] + tail.split.first => recovery_time + Item.new(name, speed.to_i, active_time.to_i, recovery_time.to_i) + end +end + +def race(items, time) + active_times = items.map { |i| [i, 1..i.active_time] }.to_h + + (1..time).each_with_object(items.map {|i| [i, {score: 0, distance: 0}] }.to_h) do |sec, stats| + stats.each do |item, stat| + active = active_times[item] + + stat[:distance] += item.speed if active.include?(sec) + + next unless sec > active.last + + active_start = sec + item.recovery_time + active_end = active_start - 1 + item.active_time + active_times[item] = active_start..active_end + end + + leading = stats.values.max_by { |v| v[:distance] }[:distance] + stats.each do |n, s| + s[:score] += 1 if s[:distance] == leading + end + end +end + +def main(file_paths) + file_paths.each do |file_path| + puts "File: #{file_path}" + items = parse_file(file_path) + + results = race(items, 2503) + + results.values.max_by { |v| v[:distance] } => {distance:} + puts "solution 1: #{distance}" + + results.values.max_by { |v| v[:score] } => {score:} + puts "solution 2: #{score}" + end +end + +main(ARGV.map { |x| Pathname(x) })