Skip to content

Instantly share code, notes, and snippets.

@iszlai
Forked from petrikero/day6.ex
Created December 28, 2015 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iszlai/31f01f5c3b5803014712 to your computer and use it in GitHub Desktop.
Save iszlai/31f01f5c3b5803014712 to your computer and use it in GitHub Desktop.
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