summaryrefslogtreecommitdiffstats
path: root/src/day07.exs
blob: 1adeb5497e46a68dca3c31f18dc02f100d3c812f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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}")