1
0
Fork 0
advent-of-code/2015/lib/2015/6.ex
2022-09-21 09:19:53 -04:00

82 lines
2 KiB
Elixir

import AOC
aoc 2015, 6 do
import NimbleParsec
defparsec(
:coord,
integer(min: 1)
|> ignore(string(","))
|> integer(min: 1)
|> label("coordinate pair")
)
defparsec(
:command,
choice([
string("turn on"),
string("turn off"),
string("toggle")
])
|> ignore(string(" "))
|> parsec(:coord)
|> ignore(string(" through "))
|> parsec(:coord)
)
def parse_command(line) do
command(line)
|> then(fn {:ok, v, _, _, _, _} -> v end)
|> then(fn
["turn on", x1, y1, x2, y2] -> {:turn_on, {x1, y1}, {x2, y2}}
["turn off", x1, y1, x2, y2] -> {:turn_off, {x1, y1}, {x2, y2}}
["toggle", x1, y1, x2, y2] -> {:toggle, {x1, y1}, {x2, y2}}
end)
end
def command_stream(), do: input_stream() |> Stream.map(&parse_command/1)
def p1 do
lights = for x <- 0..999, y <- 0..999, into: %{}, do: {{x, y}, 0}
command_stream()
|> Enum.reduce(lights, fn
{:turn_on, from, to}, lights ->
set_range(lights, from, to, 1)
{:turn_off, from, to}, lights ->
set_range(lights, from, to, 0)
{:toggle, from, to}, lights ->
update_range(lights, from, to, fn
0 -> 1
1 -> 0
end)
end)
|> Map.values()
|> Enum.sum()
end
def p2 do
lights = for x <- 0..999, y <- 0..999, into: %{}, do: {{x, y}, 0}
command_stream()
|> Enum.reduce(lights, fn
{:turn_on, from, to}, lights -> update_range(lights, from, to, &(&1 + 1))
{:turn_off, from, to}, lights -> update_range(lights, from, to, &max(0, &1 - 1))
{:toggle, from, to}, lights -> update_range(lights, from, to, &(&1 + 2))
end)
|> Map.values()
|> Enum.sum()
end
def set_range(map, from, to, value), do: update_range(map, from, to, always(value))
def update_range(map, {x1, y1}, {x2, y2}, fun) do
for x <- x1..x2, y <- y1..y2, reduce: map do
map -> Map.update!(map, {x, y}, fun)
end
end
def always(v), do: fn _ -> v end
end