diff --git a/2015/README.md b/2015/README.md index 5b08d31..011a630 100644 --- a/2015/README.md +++ b/2015/README.md @@ -16,7 +16,7 @@ | ✓ | 12 | Ruby | ✓ | 13 | Ruby | ✓ | 14 | Ruby -| | 15 | +| ✓ | 15 | Ruby | | 16 | | | 17 | | | 18 | diff --git a/2015/day-15/.ruby-version b/2015/day-15/.ruby-version new file mode 100644 index 0000000..4a36342 --- /dev/null +++ b/2015/day-15/.ruby-version @@ -0,0 +1 @@ +3.0.0 diff --git a/2015/day-15/inputs/puzzle.txt b/2015/day-15/inputs/puzzle.txt new file mode 100644 index 0000000..6f33d01 --- /dev/null +++ b/2015/day-15/inputs/puzzle.txt @@ -0,0 +1,4 @@ +Sprinkles: capacity 2, durability 0, flavor -2, texture 0, calories 3 +Butterscotch: capacity 0, durability 5, flavor -3, texture 0, calories 3 +Chocolate: capacity 0, durability 0, flavor 5, texture -1, calories 8 +Candy: capacity 0, durability -1, flavor 0, texture 5, calories 8 diff --git a/2015/day-15/inputs/test.txt b/2015/day-15/inputs/test.txt new file mode 100644 index 0000000..1a7ff25 --- /dev/null +++ b/2015/day-15/inputs/test.txt @@ -0,0 +1,2 @@ +Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8 +Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3 diff --git a/2015/day-15/main.rb b/2015/day-15/main.rb new file mode 100755 index 0000000..1b42a7d --- /dev/null +++ b/2015/day-15/main.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "pathname" + +Ingredient = Struct.new(:name, :capacity, :durability, :flavor, :texture, :calories, keyword_init: true) + +def parse_file(file) + file.each_line.map do |line| + line.split(": ") => [name, tail] + tail.split(", ").map(&:split).map { |(k, v)| [k.to_sym, v.to_i] }.to_h => properties + Ingredient.new(name: name, **properties) + end +end + +# Not the most efficient solution, but it does its job +def calculate_scores(ingredients) + size = ingredients.size + + (1..(100 - size + 1)).to_a.repeated_permutation(size).select { |x| x.sum == 100 }.map do |perm| + total_score = %i[capacity durability flavor texture].reduce(1) do |total_score, property| + score = ingredients.each_with_index.sum { |ing, idx| perm[idx] * ing[property] } + total_score * [score, 0].max + end + + calories = ingredients.each_with_index.sum { |ing, idx| perm[idx] * ing.calories } + + [total_score, calories] + end +end + +def main(file_paths) + file_paths.each do |file_path| + puts "File: #{file_path}" + ingredients = parse_file(file_path) + + scores = calculate_scores(ingredients) + + solution1 = scores.max_by { |(score, _)| score }.first + puts " solution 1: #{solution1}" + + solution2 = scores.select { |(_, cal)| cal == 500 }.max_by { |(score, _)| score }.first + puts " solution 2: #{solution2}" + end +end + +main(ARGV.map { |x| Pathname(x) })