defmodule Utils do def parse_integer_list(string, split, trim \\ true) do string |> String.split(split, trim: trim) |> Enum.map(& String.to_integer(&1)) end end defmodule Equation do @derive Inspect defstruct [:result, :terms] def from_string(string) do string |> Utils.parse_integer_list([":", " "]) |> then(& %Equation{result: hd(&1), terms: tl(&1)}) end def has_lr_solution(equation, ops) do has_lr_solution(hd(equation.terms), tl(equation.terms), equation.result, ops) end defp has_lr_solution(acc, terms, result, ops) do cond do acc > result -> false terms == [] and acc == result -> true terms == [] -> false true -> ops |> Enum.any?(& has_lr_solution(apply_op(acc, hd(terms), &1), tl(terms), result, ops)) end end defp apply_op(l, r, op) do case op do :add -> l + r :mul -> l * r :concat -> String.to_integer("#{l}#{r}") end end end defmodule Day07 do def part1(data) do data |> String.split("\n", trim: true) |> Enum.map(& Equation.from_string(&1)) |> Enum.filter(& Equation.has_lr_solution(&1, [:mul, :add])) |> Enum.map(& &1.result) |> Enum.sum() end def part2(data) do data |> String.split("\n", trim: true) |> Enum.map(& Equation.from_string(&1)) |> Enum.filter(& Equation.has_lr_solution(&1, [:mul, :concat, :add])) |> Enum.map(& &1.result) |> Enum.sum() end end data = IO.read(:stdio, :eof) {time1 , ans1} = :timer.tc(fn -> Day07.part1(data) end) IO.puts("Time : #{time1 / 1000000}") IO.puts("Answer: #{ans1}") {time2 , ans2} = :timer.tc(fn -> Day07.part2(data) end) IO.puts("Time : #{time2 / 1000000}") IO.puts("Answer: #{ans2}")