diff options
-rw-r--r-- | 2015/day15.exs | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/2015/day15.exs b/2015/day15.exs new file mode 100644 index 0000000..8f93a1b --- /dev/null +++ b/2015/day15.exs @@ -0,0 +1,95 @@ +ingredients = + File.stream!("inputs/day15.txt") + |> Enum.filter(fn line -> String.trim(line) != "" end) + |> Enum.map(fn line -> + Regex.run( + ~r/\w+: capacity ([+-]?\d+), durability ([+-]?\d+), flavor ([+-]?\d+), texture ([+-]?\d+), calories ([+-]?\d+)/, + line + ) + |> Stream.drop(1) + |> Stream.map(&Integer.parse/1) + |> Enum.map(fn {i, _} -> i end) + end) + +ingredientsWithoutCalories = + Enum.map(ingredients, fn line -> + {_calories, withoutCalories} = List.pop_at(line, -1) + withoutCalories + end) + +ingredientsWithCalories = + Enum.map(ingredients, fn line -> + List.pop_at(line, -1) + end) + +defmodule RecipeFinder do + def findTastiestRecipe([lastIngredient], remainingSpoons, currentMixture) do + Enum.zip(lastIngredient, currentMixture) + |> Enum.map(fn {next, current} -> next * remainingSpoons + current end) + |> Enum.map(&max(&1, 0)) + |> Enum.product() + end + + def findTastiestRecipe([nextIngredient | remainingIngredients], remainingSpoons, currentMixture) do + Enum.map(0..remainingSpoons, fn nextSpoons -> + findTastiestRecipe( + remainingIngredients, + remainingSpoons - nextSpoons, + Enum.zip(nextIngredient, currentMixture) + |> Enum.map(fn {next, current} -> next * nextSpoons + current end) + ) + end) + |> Enum.max() + end + + def findTastiestRecipeWithExactCalories( + [{lastIngredientCalories, _}], + remainingSpoons, + remainingCalories, + _ + ) + when lastIngredientCalories * remainingSpoons != remainingCalories do + nil + end + + def findTastiestRecipeWithExactCalories( + [{_, lastIngredient}], + remainingSpoons, + _, + currentMixture + ) do + Enum.zip(lastIngredient, currentMixture) + |> Enum.map(fn {next, current} -> next * remainingSpoons + current end) + |> Enum.map(&max(&1, 0)) + |> Enum.product() + end + + def findTastiestRecipeWithExactCalories( + [{nextIngredientCalories, nextIngredient} | remainingIngredients], + remainingSpoons, + remainingCalories, + currentMixture + ) do + maxSpoons = min(remainingSpoons, div(remainingCalories, nextIngredientCalories)) + + Enum.map(0..maxSpoons, fn nextSpoons -> + findTastiestRecipeWithExactCalories( + remainingIngredients, + remainingSpoons - nextSpoons, + remainingCalories - nextIngredientCalories * nextSpoons, + Enum.zip(nextIngredient, currentMixture) + |> Enum.map(fn {next, current} -> next * nextSpoons + current end) + ) + end) + |> Enum.filter(&(!is_nil(&1))) + |> Enum.max(&>=/2, fn -> nil end) + end +end + +tastiest = RecipeFinder.findTastiestRecipe(ingredientsWithoutCalories, 100, [0, 0, 0, 0]) +IO.puts("Tastiest: #{tastiest}") + +healthiest = + RecipeFinder.findTastiestRecipeWithExactCalories(ingredientsWithCalories, 100, 500, [0, 0, 0, 0]) + +IO.puts("Healthiest: #{healthiest}") |