Powered by AppSignal & Oban Pro

AoC 2015 Day 6

2015/day6.livemd

AoC 2015 Day 6

Mix.install([:kino])

defmodule Utils do
  def split(line, sep \\ "") do
    String.split(line, sep, trim: true)
  end

  def split_all_lines(text, sep \\ "") do
    text
    |> String.split("\n", trim: true)
    |> Enum.map(&split(&1, sep))
  end

  def to_numbers(number) when is_binary(number) do
    String.to_integer(number)
  end

  def to_numbers(numbers) when is_list(numbers) do
    Enum.map(numbers, &to_numbers/1)
  end

  def to_matrix(text, sep \\ "") do
    text
    |> split_all_lines(sep)
    |> then(fn data ->
      for {row, r} <- Enum.with_index(data), {col, c} <- Enum.with_index(row) do
        {{r, c}, col}
      end
    end)
    |> Map.new()
  end
end

Setup

import Utils
input = Kino.Input.textarea("Input:")
text = Kino.Input.read(input)
data = split_all_lines(text, " ")

num = fn c -> split(c, ",") |> to_numbers() end

data =
  Enum.map(data, fn
    [_, "on", c1, _, c2] -> {:on, num.(c1), num.(c2)}
    [_, "off", c1, _, c2] -> {:off, num.(c1), num.(c2)}
    ["toggle", c1, _, c2] -> {:toggle, num.(c1), num.(c2)}
  end)

P1

defmodule P1 do
  def solve(input) do
    input
    |> Enum.reduce(:array.new(1000 * 1000, default: false), fn {op, [x1, y1], [x2, y2]}, arr ->
      for x <- x1..x2, y <- y1..y2, reduce: arr do
        arr ->
          case op do
            :on -> :array.set(x * 1000 + y, true, arr)
            :off -> :array.set(x * 1000 + y, false, arr)
            :toggle -> :array.set(x * 1000 + y, !:array.get(x * 1000 + y, arr), arr)
          end
      end
    end)
  end
end

:array.sparse_foldl(
  fn
    _, true, count -> count + 1
    _, false, count -> count
  end,
  0,
  P1.solve(data)
)

P2

defmodule P2 do
  def solve(input) do
    input
    |> Enum.reduce(:array.new(1000 * 1000, default: 0), fn {op, [x1, y1], [x2, y2]}, arr ->
      for x <- x1..x2, y <- y1..y2, reduce: arr do
        arr ->
          case op do
            :on -> update(x * 1000 + y, 1, arr)
            :off -> update(x * 1000 + y, -1, arr)
            :toggle -> update(x * 1000 + y, 2, arr)
          end
      end
    end)
  end

  def update(offset, change, arr) do
    v = :array.get(offset, arr) + change
    v = if v < 0, do: 0, else: v
    :array.set(offset, v, arr)
  end
end

:array.sparse_foldl(
  fn _, n, b -> b + n end,
  0,
  P2.solve(data)
)