어려운 문제가 이어지던 도중에 잠깐 쉬어가는 날이었다. 주어진 좌표에 각각 1x1x1의 정육면체 모양의 용암이 있을 때 전체 표면적(문제 1)과, 용암으로 감싸인 빈 공간(에어 포켓)을 뺀 순수 외부 표면적(문제 2)을 구하는 문제였다.
전체 표면적은 그저 6(단위 정육면체의 표면적)에서 겹치는 면 수만큼 빼면 되니 그리 어렵지 않았고, 에어 포켓을 거꾸로 단위 정육면체의 집합으로 생각하고 표면적을 구하면 순수 외부 표면적도 쉽게 구할 수 있었다. 문제를 풀기에 바빠서 입출력과 로직을 분리할 생각은 안 하고 그냥 q2
함수에서 임시 파일을 만들어 q1
함수를 호출한 것이 옥의 티처럼 보이지만, 지금 수정하기에도 조금 그러니 그대로 올려 둔다.
defmodule Omicron.Day18 do
@dir "data/day18/"
def q1(file_name \\ "q.txt") do
File.read!(@dir <> file_name)
|> String.split("\n")
|> Enum.map(fn v ->
String.split(v, ",")
|> Enum.map(&String.to_integer/1)
|> List.to_tuple()
end)
|> Enum.reduce({MapSet.new(), 0}, fn {a, b, c} = cube, {cubes, sides} ->
new_cubes = MapSet.put(cubes, cube)
overlaps =
[
MapSet.member?(cubes, {a - 1, b, c}),
MapSet.member?(cubes, {a + 1, b, c}),
MapSet.member?(cubes, {a, b - 1, c}),
MapSet.member?(cubes, {a, b + 1, c}),
MapSet.member?(cubes, {a, b, c - 1}),
MapSet.member?(cubes, {a, b, c + 1})
]
|> Enum.filter(&(&1 == true))
|> length()
{new_cubes, sides + 6 - 2 * overlaps}
end)
end
def q2(file_name \\ "q.txt") do
cubes =
File.read!(@dir <> file_name)
|> String.split("\n")
|> Enum.map(fn v ->
String.split(v, ",")
|> Enum.map(&String.to_integer/1)
|> List.to_tuple()
end)
max_x = cubes |> Enum.map(&elem(&1, 0)) |> Enum.max() |> IO.inspect(label: "max_x")
min_x = cubes |> Enum.map(&elem(&1, 0)) |> Enum.min() |> IO.inspect(label: "min_x")
max_y = cubes |> Enum.map(&elem(&1, 1)) |> Enum.max() |> IO.inspect(label: "max_y")
min_y = cubes |> Enum.map(&elem(&1, 1)) |> Enum.min() |> IO.inspect(label: "min_y")
max_z = cubes |> Enum.map(&elem(&1, 2)) |> Enum.max() |> IO.inspect(label: "max_z")
min_z = cubes |> Enum.map(&elem(&1, 2)) |> Enum.min() |> IO.inspect(label: "min_z")
air_pockets =
min_x..max_x
|> Enum.flat_map(fn x ->
min_y..max_y
|> Enum.flat_map(fn y ->
min_z..max_z
|> Enum.filter(fn z -> air_pocket?(cubes, {x, y, z}) end)
|> Enum.map(fn z -> {x, y, z} end)
end)
end)
air_pocket_input =
air_pockets
|> Enum.map(fn {x, y, z} -> "#{x},#{y},#{z}" end)
|> Enum.join("\n")
tmp_file_name = "tmp.txt"
File.write!(@dir <> tmp_file_name, air_pocket_input)
{_, total_sides} = q1(file_name)
{_, inner_sides} = q1(tmp_file_name)
total_sides - inner_sides
end
defp air_pocket?(cubes, {x, y, z}) do
if {x, y, z} in cubes do
false
else
if Enum.any?(cubes, fn {cx, cy, cz} -> cx > x and cy == y and cz == z end) and
Enum.any?(cubes, fn {cx, cy, cz} -> cx < x and cy == y and cz == z end) and
Enum.any?(cubes, fn {cx, cy, cz} -> cx == x and cy > y and cz == z end) and
Enum.any?(cubes, fn {cx, cy, cz} -> cx == x and cy < y and cz == z end) and
Enum.any?(cubes, fn {cx, cy, cz} -> cx == x and cy == y and cz > z end) and
Enum.any?(cubes, fn {cx, cy, cz} -> cx == x and cy == y and cz < z end) do
true
else
false
end
end
end
end
'호두나무 공방 > Advent of Code' 카테고리의 다른 글
Advent of Code 2022 Day 20 in Elixir - Grove Positioning System 풀이 (0) | 2023.01.23 |
---|---|
Advent of Code 2022 Day 19 in Elixir - Not Enough Minerals 풀이 (0) | 2023.01.23 |
Advent of Code 2022 Day 17 in Elixir - Pyroclastic Flow 풀이 (0) | 2023.01.23 |
Advent of Code 2022 Day 16 in Elixir - Proboscidea Volcanium 풀이 (0) | 2023.01.22 |
Advent of Code 2022 Day 15 in Elixir - Beacon Exclusion Zone 풀이 (0) | 2023.01.08 |