|
| 1 | +defmodule HypothermalVenture do |
| 2 | + @type line :: %{ |
| 3 | + from: {integer, integer}, |
| 4 | + to: {integer, integer} |
| 5 | + } |
| 6 | + |
| 7 | + def load_file() do |
| 8 | + File.read!("../input.txt") |
| 9 | + |> String.split("\n", trim: true) |
| 10 | + end |
| 11 | + |
| 12 | + def parse_line({from, to}) do |
| 13 | + %{ |
| 14 | + from: |
| 15 | + String.split(from, ",") |
| 16 | + |> Enum.map(&Integer.parse/1) |
| 17 | + |> Enum.map(&elem(&1, 0)) |
| 18 | + |> List.to_tuple(), |
| 19 | + to: |
| 20 | + String.split(to, ",") |
| 21 | + |> Enum.map(&Integer.parse/1) |
| 22 | + |> Enum.map(&elem(&1, 0)) |
| 23 | + |> List.to_tuple() |
| 24 | + } |
| 25 | + end |
| 26 | + |
| 27 | + @spec parse_lines(input :: [String.t()]) :: [line] |
| 28 | + def parse_lines(input) do |
| 29 | + Enum.map(input, fn ln -> |
| 30 | + String.replace(ln, " ", "") |
| 31 | + |> String.split("->", trim: true) |
| 32 | + |> List.to_tuple() |
| 33 | + |> parse_line() |
| 34 | + end) |
| 35 | + end |
| 36 | + |
| 37 | + def init_array(), do: Matrix.from_list(List.duplicate(List.duplicate(0, 1000), 1000)) |
| 38 | + |
| 39 | + def draw_line(matrix, %{from: {x1, y1}, to: {x2, y2}} = line) |
| 40 | + when x2 - x1 == 0 and y2 - y1 == 0 do |
| 41 | + put_in(matrix[y1][x1], matrix[y1][x1] + 1) |
| 42 | + end |
| 43 | + |
| 44 | + def draw_line(matrix, %{from: {x1, y1}, to: {x2, y2}}) do |
| 45 | + delta_x = x2 - x1 |
| 46 | + delta_y = y2 - y1 |
| 47 | + |
| 48 | + updated_matrix = put_in(matrix[y1][x1], matrix[y1][x1] + 1) |
| 49 | + |
| 50 | + new_x = |
| 51 | + case delta_x do |
| 52 | + x when x > 0 -> x1 + 1 |
| 53 | + x when x < 0 -> x1 - 1 |
| 54 | + x when x == 0 -> x1 |
| 55 | + end |
| 56 | + |
| 57 | + new_y = |
| 58 | + case delta_y do |
| 59 | + y when y > 0 -> y1 + 1 |
| 60 | + y when y < 0 -> y1 - 1 |
| 61 | + y when y == 0 -> y1 |
| 62 | + end |
| 63 | + |
| 64 | + draw_line(updated_matrix, %{from: {new_x, new_y}, to: {x2, y2}}) |
| 65 | + end |
| 66 | + |
| 67 | + def draw_lines(matrix, []), do: matrix |
| 68 | + def draw_lines(matrix, [line | tail]), do: draw_lines(draw_line(matrix, line), tail) |
| 69 | + |
| 70 | + def solve(lines) do |
| 71 | + matrix = init_array() |
| 72 | + |
| 73 | + draw_lines(matrix, lines) |
| 74 | + |> Matrix.to_list() |
| 75 | + |> List.flatten() |
| 76 | + |> Enum.filter(fn x -> x >= 2 end) |
| 77 | + |> Enum.count() |
| 78 | + end |
| 79 | + |
| 80 | + @spec first() :: Integer |
| 81 | + def first() do |
| 82 | + lines = |
| 83 | + load_file() |
| 84 | + |> parse_lines() |
| 85 | + |> Enum.filter(fn %{from: {x1, y1}, to: {x2, y2}} -> x1 == x2 or y1 == y2 end) |
| 86 | + |
| 87 | + solve(lines) |
| 88 | + end |
| 89 | + |
| 90 | + @spec second() :: Integer |
| 91 | + def second() do |
| 92 | + lines = |
| 93 | + load_file() |
| 94 | + |> parse_lines() |
| 95 | + |
| 96 | + solve(lines) |
| 97 | + end |
| 98 | +end |
| 99 | + |
| 100 | +defmodule Matrix do |
| 101 | + @moduledoc """ |
| 102 | + Helpers for working with multidimensional lists, also called matrices. |
| 103 | + """ |
| 104 | + |
| 105 | + @doc """ |
| 106 | + Converts a multidimensional list into a zero-indexed map. |
| 107 | +
|
| 108 | + ## Example |
| 109 | +
|
| 110 | + iex> list = [["x", "o", "x"]] |
| 111 | + ...> Matrix.from_list(list) |
| 112 | + %{0 => %{0 => "x", 1 => "o", 2 => "x"}} |
| 113 | + """ |
| 114 | + def from_list(list) when is_list(list) do |
| 115 | + do_from_list(list) |
| 116 | + end |
| 117 | + |
| 118 | + defp do_from_list(list, map \\ %{}, index \\ 0) |
| 119 | + defp do_from_list([], map, _index), do: map |
| 120 | + |
| 121 | + defp do_from_list([h | t], map, index) do |
| 122 | + map = Map.put(map, index, do_from_list(h)) |
| 123 | + do_from_list(t, map, index + 1) |
| 124 | + end |
| 125 | + |
| 126 | + defp do_from_list(other, _, _), do: other |
| 127 | + |
| 128 | + @doc """ |
| 129 | + Converts a zero-indexed map into a multidimensional list. |
| 130 | +
|
| 131 | + ## Example |
| 132 | +
|
| 133 | + iex> matrix = %{0 => %{0 => "x", 1 => "o", 2 => "x"}} |
| 134 | + ...> Matrix.to_list(matrix) |
| 135 | + [["x", "o", "x"]] |
| 136 | + """ |
| 137 | + def to_list(matrix) when is_map(matrix) do |
| 138 | + do_to_list(matrix) |
| 139 | + end |
| 140 | + |
| 141 | + defp do_to_list(matrix) when is_map(matrix) do |
| 142 | + for {_index, value} <- matrix, |
| 143 | + into: [], |
| 144 | + do: do_to_list(value) |
| 145 | + end |
| 146 | + |
| 147 | + defp do_to_list(other), do: other |
| 148 | +end |
0 commit comments