Day 14: Restroom Redoubt
Mix.install([:kino])
Section
input = Kino.Input.textarea("input")
input = Kino.Input.read(input)
Part 1 & 2
defmodule RestroomRedoubt do
def solve_part1(input) do
max_x = 100
max_y = 102
parse_input(input)
|> tick(0, {max_x, max_y}, 100, false)
|> sum_quadrants({max_x, max_y})
end
def solve_part2(input) do
max_x = 100
max_y = 102
parse_input(input)
|> tick(0, {max_x, max_y}, 10000, true)
end
defp draw_position_point({x, y}, robots_data) do
if Enum.any?(robots_data, fn [coord, _] -> {x, y} == coord end) do
"X"
else
"."
end
end
defp draw_map(robots_data, tick_num, {max_x, max_y}) do
map =
for y <- 0..max_y, x <- 0..max_x, into: "" do
case {x, y} do
{x, y} when x == max_x ->
draw_position_point({x, y}, robots_data) <> "\n"
{x, y} ->
draw_position_point({x, y}, robots_data)
end
end
if String.contains?(map, "XXXXXXX") do
IO.puts(tick_num)
IO.puts(map)
end
robots_data
end
defp parse_input(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(&parse_input_line(&1))
end
defp sum_quadrants(robots_data, {max_x, max_y}) do
Enum.group_by(robots_data, fn [{x, y}, _] ->
case {x, y} do
{x, y} when x in 0..(div(max_x, 2) - 1)//1 and y in 0..(div(max_y, 2) - 1)//1 ->
1
{x, y} when x in (div(max_x, 2) + 1)..max_x//1 and y in 0..(div(max_y, 2) - 1)//1 ->
2
{x, y} when x in 0..(div(max_x, 2) - 1)//1 and y in (div(max_y, 2) + 1)..max_y//1 ->
3
{x, y} when x in (div(max_x, 2) + 1)..max_x//1 and y in (div(max_y, 2) + 1)..max_y//1 ->
4
_ ->
nil
end
end)
|> Enum.reject(fn {k, _val} -> k == nil end)
|> Enum.map(fn {_i, list} -> length(list) end)
|> Enum.product()
end
defp parse_input_line(line) do
[position, velocity] = String.split(line, ["p=", " v="], trim: true)
[x, y] = String.split(position, ",") |> Enum.map(&String.to_integer(&1))
[vx, vy] = String.split(velocity, ",") |> Enum.map(&String.to_integer(&1))
[{x, y}, {vx, vy}]
end
defp tick(robots_data, tick_num, _map_size, max_tick, _draw) when tick_num == max_tick do
robots_data
end
defp tick(robots_data, tick_num, {max_x, max_y}, max_tick, draw) do
Enum.map(robots_data, fn
[{x, y}, {vx, vy}] ->
new_pos_x =
case x + vx do
new_x when new_x > max_x ->
new_x - max_x - 1
new_x when new_x < 0 ->
max_x + new_x + 1
new_x ->
new_x
end
new_pos_y =
case y + vy do
new_y when new_y > max_y ->
new_y - max_y - 1
new_y when new_y < 0 ->
max_y + new_y + 1
new_y ->
new_y
end
[{new_pos_x, new_pos_y}, {vx, vy}]
end)
|> then(fn data ->
if(draw, do: draw_map(data, tick_num, {max_x, max_y}))
data
end)
|> tick(tick_num + 1, {max_x, max_y}, max_tick, draw)
end
end
RestroomRedoubt.solve_part1(input)
RestroomRedoubt.solve_part2(input)