218 lines
4.5 KiB
Elixir
218 lines
4.5 KiB
Elixir
|
|
defmodule Aoc19.Solution.Day08 do
|
||
|
|
@name "Day 8: Space Image Format"
|
||
|
|
@behaviour Solution
|
||
|
|
@image_width 25
|
||
|
|
@image_height 6
|
||
|
|
@black " "
|
||
|
|
@white "X"
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
def get_name, do: @name
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
def parse!(str), do: str
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Solution for the first part of "Day 8: Space Image Format".
|
||
|
|
"""
|
||
|
|
def solve_first_part(data), do: data |> _solve_first_part(@image_width, @image_height)
|
||
|
|
|
||
|
|
@impl Solution
|
||
|
|
@doc """
|
||
|
|
Solution for the second part of "Day 8: Space Image Format".
|
||
|
|
"""
|
||
|
|
def solve_second_part(data) do
|
||
|
|
data |> _solve_second_part(@image_width, @image_height) |> reveal(@image_width)
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Actual solution for part 1, but with the ability to test.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08._solve_first_part("123456789012", 3, 2)
|
||
|
|
1
|
||
|
|
|
||
|
|
"""
|
||
|
|
def _solve_first_part(data, image_width, image_height) do
|
||
|
|
data
|
||
|
|
|> layers(image_width, image_height)
|
||
|
|
|> fewest_zeros
|
||
|
|
|> multiply()
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Actual solution for part 2, but with the ability to test.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08._solve_second_part("0222112222120000", 2, 2)
|
||
|
|
[" ", "X", "X", " "]
|
||
|
|
|
||
|
|
"""
|
||
|
|
def _solve_second_part(data, image_width, image_height) do
|
||
|
|
data
|
||
|
|
|> layers(image_width, image_height)
|
||
|
|
|> pixels()
|
||
|
|
|> colors
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
get layers from image data.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.layers("123456789012", 3, 2)
|
||
|
|
["123456", "789012"]
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.layers("0222112222120000", 2, 2)
|
||
|
|
["0222", "1122", "2212", "0000"]
|
||
|
|
|
||
|
|
"""
|
||
|
|
def layers(data, x, y) do
|
||
|
|
data
|
||
|
|
|> String.codepoints()
|
||
|
|
|> Enum.chunk_every(x * y)
|
||
|
|
|> Enum.map(&Enum.join/1)
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Get layers with the fewest zeros.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.fewest_zeros(["123456", "789012"])
|
||
|
|
"123456"
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.fewest_zeros(["103406", "789012"])
|
||
|
|
"789012"
|
||
|
|
|
||
|
|
"""
|
||
|
|
def fewest_zeros(layers) do
|
||
|
|
layers
|
||
|
|
|> Enum.map(fn layer -> {layer, layer} end)
|
||
|
|
|> Enum.map(fn {layer, data} ->
|
||
|
|
{layer, data |> String.replace("0", "") |> String.length()}
|
||
|
|
end)
|
||
|
|
|> Enum.sort(fn a, b -> elem(a, 1) > elem(b, 1) end)
|
||
|
|
|> Enum.at(0)
|
||
|
|
|> elem(0)
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
return the number of 1 digits multiplied by the number of 2 digits of a layer.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.multiply("121226")
|
||
|
|
6
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.multiply("293416")
|
||
|
|
1
|
||
|
|
|
||
|
|
"""
|
||
|
|
def multiply(layer) do
|
||
|
|
{x, y} =
|
||
|
|
layer
|
||
|
|
|> String.codepoints()
|
||
|
|
|> Enum.map(&String.to_integer/1)
|
||
|
|
|> Enum.reduce({0, 0}, fn
|
||
|
|
1, {x, y} -> {x + 1, y}
|
||
|
|
2, {x, y} -> {x, y + 1}
|
||
|
|
_, acc -> acc
|
||
|
|
end)
|
||
|
|
|
||
|
|
x * y
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
Regroup a set of layers to pixels.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.pixels(["0222", "1122", "2212", "0000"])
|
||
|
|
[[0, 1, 2, 0], [2, 1, 2, 0], [2, 2, 1, 0], [2, 2, 2, 0]]
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.pixels(["123456", "789012"])
|
||
|
|
[[1, 7], [2, 8], [3, 9], [4, 0], [5, 1], [6, 2]]
|
||
|
|
|
||
|
|
"""
|
||
|
|
def pixels(_layers, {count, _depth}, pixels, pos) when pos > count,
|
||
|
|
do: pixels |> Enum.reverse()
|
||
|
|
|
||
|
|
def pixels(layers, {count, depth}, pixels, pos) do
|
||
|
|
pixel =
|
||
|
|
0..depth
|
||
|
|
|> Enum.map(fn layer ->
|
||
|
|
layers
|
||
|
|
|> Enum.at(layer)
|
||
|
|
|> Enum.at(pos)
|
||
|
|
|> String.to_integer()
|
||
|
|
end)
|
||
|
|
|
||
|
|
pixels(layers, {count, depth}, [pixel | pixels], pos + 1)
|
||
|
|
end
|
||
|
|
|
||
|
|
def pixels(layers) do
|
||
|
|
count = layers |> Enum.at(0) |> String.length()
|
||
|
|
depth = layers |> length
|
||
|
|
|
||
|
|
pixels(
|
||
|
|
layers |> Enum.map(&String.codepoints/1),
|
||
|
|
{count - 1, depth - 1},
|
||
|
|
[],
|
||
|
|
0
|
||
|
|
)
|
||
|
|
end
|
||
|
|
|
||
|
|
def colors(pixels) do
|
||
|
|
pixels
|
||
|
|
|> Enum.map(&color/1)
|
||
|
|
end
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
determine color of pixel based on layer.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.color([0, 1, 2, 0])
|
||
|
|
" "
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.color([2, 1, 2, 0])
|
||
|
|
"X"
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.color([2, 2, 1, 0])
|
||
|
|
"X"
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.color([2, 2, 2, 0])
|
||
|
|
" "
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.color([2, 2, 2, 2, 1, 2, 2, 0])
|
||
|
|
"X"
|
||
|
|
|
||
|
|
"""
|
||
|
|
def color([2 | queue]), do: color(queue)
|
||
|
|
def color([1 | _]), do: @white
|
||
|
|
def color([0 | _]), do: @black
|
||
|
|
|
||
|
|
@doc """
|
||
|
|
determine color of pixel based on layer.
|
||
|
|
|
||
|
|
## Examples
|
||
|
|
|
||
|
|
iex> Aoc19.Solution.Day08.reveal(["X", " ", " ", "X"], 2)
|
||
|
|
"\\nX \\n X"
|
||
|
|
|
||
|
|
"""
|
||
|
|
def reveal(pixels, breakpoint) do
|
||
|
|
output =
|
||
|
|
pixels
|
||
|
|
|> Enum.chunk_every(breakpoint)
|
||
|
|
|> Enum.map(&Enum.join/1)
|
||
|
|
|> Enum.join("\n")
|
||
|
|
|
||
|
|
"\n" <> output
|
||
|
|
end
|
||
|
|
end
|