|
| 1 | +defmodule Day13 do |
| 2 | + def read_input(file_path) do |
| 3 | + case File.read(file_path) do |
| 4 | + {:ok, content} -> |
| 5 | + content |
| 6 | + |> String.split("\n\n", trim: true) |
| 7 | + |> Enum.map(&String.split(&1, "\n", trim: true)) |
| 8 | + |> Enum.map(fn l -> Enum.map(l, &String.graphemes/1) end) |
| 9 | + |
| 10 | + {:error, reason} -> |
| 11 | + raise "Oh no! #{reason}" |
| 12 | + end |
| 13 | + end |
| 14 | + |
| 15 | + def partA(file_path) do |
| 16 | + file_path |
| 17 | + |> read_input() |
| 18 | + |> Enum.map(&find_mirror(&1, 0)) |
| 19 | + |> Enum.map(&mirror_point/1) |
| 20 | + |> Enum.sum() |
| 21 | + end |
| 22 | + |
| 23 | + def partB(file_path) do |
| 24 | + file_path |
| 25 | + |> read_input() |
| 26 | + |> Enum.map(&find_mirror(&1, 1)) |
| 27 | + |> Enum.map(&mirror_point/1) |
| 28 | + |> Enum.sum() |
| 29 | + end |
| 30 | + |
| 31 | + def pairs(mirror_loc, offset), do: {mirror_loc - 1 - offset, mirror_loc + offset} |
| 32 | + def get_row(arr, row_id), do: arr |> Enum.at(row_id) |
| 33 | + def get_col(arr, col_id), do: arr |> Enum.map(&Enum.at(&1, col_id)) |> List.flatten() |
| 34 | + |
| 35 | + def number_of_mismatches_at_offset(pattern, mirror_loc, offset, get_fun) do |
| 36 | + {p1, p2} = pairs(mirror_loc, offset) |
| 37 | + slice1 = get_fun.(pattern, p1) |
| 38 | + slice2 = get_fun.(pattern, p2) |
| 39 | + |
| 40 | + Enum.zip(slice1, slice2) |
| 41 | + |> Enum.filter(fn {a, b} -> a != b end) |
| 42 | + |> length() |
| 43 | + end |
| 44 | + |
| 45 | + def valid_mirror?(pattern, mirror_loc, type, target) do |
| 46 | + {get_fun, lim_fun} = |
| 47 | + case type do |
| 48 | + :row -> {&get_row/2, &get_col/2} |
| 49 | + :col -> {&get_col/2, &get_row/2} |
| 50 | + end |
| 51 | + |
| 52 | + 0..(min(mirror_loc, length(lim_fun.(pattern, 0)) - mirror_loc) - 1) |
| 53 | + |> Enum.map(&number_of_mismatches_at_offset(pattern, mirror_loc, &1, get_fun)) |
| 54 | + |> Enum.sum() |
| 55 | + |> Kernel.==(target) |
| 56 | + end |
| 57 | + |
| 58 | + def find_mirrorH(pattern, type, target) do |
| 59 | + lim_fun = |
| 60 | + case type do |
| 61 | + :row -> &get_col/2 |
| 62 | + :col -> &get_row/2 |
| 63 | + end |
| 64 | + |
| 65 | + Enum.reduce( |
| 66 | + 1..(length(lim_fun.(pattern, 0)) - 1), |
| 67 | + nil, |
| 68 | + fn mirror_loc, acc -> |
| 69 | + case acc do |
| 70 | + nil -> if valid_mirror?(pattern, mirror_loc, type, target), do: mirror_loc, else: nil |
| 71 | + _ -> acc |
| 72 | + end |
| 73 | + end |
| 74 | + ) |
| 75 | + end |
| 76 | + |
| 77 | + def find_mirror(pattern, target) do |
| 78 | + case find_mirrorH(pattern, :row, target) do |
| 79 | + nil -> {:col, find_mirrorH(pattern, :col, target)} |
| 80 | + x -> {:row, x} |
| 81 | + end |
| 82 | + end |
| 83 | + |
| 84 | + def mirror_point({:row, x}), do: 100 * x |
| 85 | + def mirror_point({:col, x}), do: x |
| 86 | +end |
| 87 | + |
| 88 | +IO.puts(Day13.partA("./input")) |
| 89 | +IO.puts(Day13.partB("./input")) |
0 commit comments