-
-
Save iszlai/31f01f5c3b5803014712 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Benchmark do | |
def measure(function) do | |
elapsed = function | |
|> :timer.tc | |
|> elem(0) | |
|> Kernel./(1_000_000) | |
IO.puts "Elapsed = #{elapsed}s" | |
end | |
end | |
defmodule Day6 do | |
## Row handler | |
defmodule Row do | |
use GenServer | |
def start_link() do | |
GenServer.start_link(__MODULE__, []) | |
end | |
def init([]) do | |
table = :ets.new(:light_table, [:set, :protected]) | |
Enum.each(0..999, fn x -> | |
true = :ets.insert(table, {x, 0}) | |
end) | |
{:ok, table} | |
end | |
def handle_cast({:update, op, {x0, x1}}, table) do | |
case op do | |
:turn_on -> Enum.each(x0..x1, fn x -> :ets.insert(table, {x, 1}) end) | |
:turn_off -> Enum.each(x0..x1, fn x -> :ets.insert(table, {x, 0}) end) | |
:toggle -> Enum.each(x0..x1, fn x -> | |
[{x, value}] = :ets.lookup(table, x) | |
:ets.insert(table, {x, 1 - value}) | |
end) | |
end | |
{:noreply, table} | |
end | |
def handle_cast(:sum, table) do | |
values = for x <- 0..999, do: :ets.lookup(table, x) | |
sum = values |> Enum.map(fn [{_k, v}] -> v end) |> Enum.sum | |
{:noreply, sum} | |
end | |
def handle_call(:get, _from, state) do | |
{:reply, state, state} | |
end | |
def terminate(_reason, _state) do | |
end | |
end | |
## Parsing | |
def parse_op("turn on"), do: :turn_on | |
def parse_op("turn off"), do: :turn_off | |
def parse_op("toggle"), do: :toggle | |
def parse_row(row) do | |
[_, op, x0, y0, x1, y1] = List.flatten(Regex.scan(~r/^([a-z]+|[a-z ]+) (\d+),(\d+) through (\d+),(\d+)$/, row)) | |
op = parse_op(op) | |
{x0, ""} = Integer.parse(x0) | |
{y0, ""} = Integer.parse(y0) | |
{x1, ""} = Integer.parse(x1) | |
{y1, ""} = Integer.parse(y1) | |
{op, {x0, y0}, {x1, y1}} | |
end | |
def parse_input(stream) do | |
stream | |
|> Enum.map(&parse_row/1) | |
end | |
## Program | |
def init() do | |
rows = for y <- 0..999 do | |
{:ok, pid} = Row.start_link() | |
{y, pid} | |
end | |
Enum.into(rows, %{}) | |
end | |
def execute_cmd({op, {x0, y0}, {x1, y1}}, state) do | |
#IO.puts "exec #{inspect op}(#{x1-x0+1} x #{y1-y0+1})" | |
Enum.each(y0..y1, fn y -> | |
row = Dict.get(state, y) | |
GenServer.cast(row, {:update, op, {x0, x1}}) | |
end) | |
state | |
end | |
def execute_cmds(cmds, state) do | |
Enum.reduce(cmds, state, fn(cmd, acc) -> execute_cmd(cmd, acc) end) | |
end | |
def count_on(state) do | |
pids = Dict.values(state) | |
pids | |
|> Enum.map(&GenServer.cast(&1, :sum)) | |
pids | |
|> Enum.map(&GenServer.call(&1, :get)) | |
|> Enum.sum | |
end | |
def run() do | |
cmds = parse_input(File.stream!("input.txt")) #|> Enum.take(10) | |
state = init() | |
state = execute_cmds(cmds, state) | |
count = count_on(state) | |
IO.puts "lights on = #{count}" | |
end | |
end | |
Benchmark.measure(&Day6.run/0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment