160 lines
4.1 KiB
Elixir
160 lines
4.1 KiB
Elixir
|
|
defmodule Aoc19.Solution.Day03 do
|
||
|
|
@name "Day 3: Crossed Wires"
|
||
|
|
@behaviour Solution
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
def get_name, do: @name
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Parse raw input into a list of paths.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.parse!("U3,R7\\nD11,L13")
|
||
|
|
[["U3", "R7"], ["D11", "L13"]]
|
||
|
|
|
||
|
|
"""
|
||
|
|
def parse!(raw) do
|
||
|
|
raw
|
||
|
|
|> String.split()
|
||
|
|
|> Enum.map(fn s -> String.split(s, ",") end)
|
||
|
|
end
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Solution for the first part of "Day 3: Crossed Wires".
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.solve_first_part("R8,U5,L5,D3\\nU7,R6,D4,L4" |> Aoc19.Solution.Day03.parse!)
|
||
|
|
6
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.solve_first_part("R75,D30,R83,U83,L12,D49,R71,U7,L72\\nU62,R66,U55,R34,D71,R55,D58,R83" |> Aoc19.Solution.Day03.parse!)
|
||
|
|
159
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.solve_first_part("R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51\\nU98,R91,D20,R16,D67,R40,U7,R15,U6,R7" |> Aoc19.Solution.Day03.parse!)
|
||
|
|
135
|
||
|
|
|
||
|
|
"""
|
||
|
|
def solve_first_part(input) do
|
||
|
|
[a, b] =
|
||
|
|
input
|
||
|
|
|> Enum.map(&get_wire/1)
|
||
|
|
|> Enum.map(&MapSet.new/1)
|
||
|
|
|
||
|
|
MapSet.intersection(a, b)
|
||
|
|
|> Enum.map(&manhattan_distance/1)
|
||
|
|
|> Enum.min()
|
||
|
|
end
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Solution for the second part of "Day 3: Crossed Wires".
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.solve_second_part("R8,U5,L5,D3\\nU7,R6,D4,L4" |> Aoc19.Solution.Day03.parse!)
|
||
|
|
30
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.solve_second_part("R75,D30,R83,U83,L12,D49,R71,U7,L72\\nU62,R66,U55,R34,D71,R55,D58,R83" |> Aoc19.Solution.Day03.parse!)
|
||
|
|
610
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.solve_second_part("R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51\\nU98,R91,D20,R16,D67,R40,U7,R15,U6,R7" |> Aoc19.Solution.Day03.parse!)
|
||
|
|
410
|
||
|
|
|
||
|
|
"""
|
||
|
|
def solve_second_part(input) do
|
||
|
|
wires =
|
||
|
|
input
|
||
|
|
|> Enum.map(&get_wire/1)
|
||
|
|
|
||
|
|
ab = wires |> Enum.map(&Enum.count/1) |> Enum.sum()
|
||
|
|
[a, b] = wires
|
||
|
|
|
||
|
|
MapSet.intersection(MapSet.new(a), MapSet.new(b))
|
||
|
|
|> Enum.map(fn pos ->
|
||
|
|
{Enum.find_index(a, fn x -> x == pos end), Enum.find_index(b, fn x -> x == pos end)}
|
||
|
|
end)
|
||
|
|
|> Enum.map(fn {x, y} ->
|
||
|
|
ab - x - y
|
||
|
|
end)
|
||
|
|
|> Enum.min()
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Return a changeset (a tuple of x and y additions) for a defined direction.
|
||
|
|
"""
|
||
|
|
def direction("U"), do: {1, 0}
|
||
|
|
def direction("R"), do: {0, 1}
|
||
|
|
def direction("D"), do: {-1, 0}
|
||
|
|
def direction("L"), do: {0, -1}
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Get a wire's complete spread (in steps) from a list of directions.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.get_wire(["U7", "R6", "D4", "L4"])
|
||
|
|
[{3, 2}, {3, 3}, {3, 4}, {3, 5}, {3, 6}, {4, 6}, {5, 6}, {6, 6}, {7, 6}, {7, 5}, {7, 4}, {7, 3}, {7, 2}, {7, 1}, {7, 0}, {6, 0}, {5, 0}, {4, 0}, {3, 0}, {2, 0}, {1, 0}]
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.get_wire(["R8", "U5", "L5", "D3"])
|
||
|
|
[{2, 3}, {3, 3}, {4, 3}, {5, 3}, {5, 4}, {5, 5}, {5, 6}, {5, 7}, {5, 8}, {4, 8}, {3, 8}, {2, 8}, {1, 8}, {0, 8}, {0, 7}, {0, 6}, {0, 5}, {0, 4}, {0, 3}, {0, 2}, {0, 1}]
|
||
|
|
|
||
|
|
"""
|
||
|
|
def get_wire(paths) do
|
||
|
|
paths
|
||
|
|
|> Enum.map(&steps/1)
|
||
|
|
|> List.flatten()
|
||
|
|
|> Enum.reduce(
|
||
|
|
{{0, 0}, []},
|
||
|
|
fn {x1, y1}, {{x2, y2}, seen} ->
|
||
|
|
{{x1 + x2, y1 + y2}, [{x1 + x2, y1 + y2} | seen]}
|
||
|
|
end
|
||
|
|
)
|
||
|
|
|> elem(1)
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Get the Manhattan distance from position {0, 0}.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.manhattan_distance({-300, 100})
|
||
|
|
400
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.manhattan_distance({-20, -20})
|
||
|
|
40
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.manhattan_distance({111, 111})
|
||
|
|
222
|
||
|
|
|
||
|
|
"""
|
||
|
|
def manhattan_distance({x, y}), do: abs(x) + abs(y)
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Get step changesets for a path.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.steps("U4")
|
||
|
|
[{1, 0}, {1, 0}, {1, 0}, {1, 0}]
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.steps("R2")
|
||
|
|
[{0, 1}, {0, 1}]
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.steps("D3")
|
||
|
|
[{-1, 0}, {-1, 0}, {-1, 0}]
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day03.steps("L1")
|
||
|
|
[{0, -1}]
|
||
|
|
|
||
|
|
"""
|
||
|
|
def steps(path) do
|
||
|
|
{d, steps} = String.split_at(path, 1)
|
||
|
|
modifier = direction(d)
|
||
|
|
stop_at = String.to_integer(steps)
|
||
|
|
1..stop_at |> Enum.map(fn _ -> modifier end)
|
||
|
|
end
|
||
|
|
end
|