Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 2

advent_of_code/2021/day-02.livemd

Day 2

Setup

Mix.install(
  [
    {:kino, "~> 0.5.0"},
    {:nx, "~> 0.1.0"}
  ]
)
input = Kino.Input.textarea("Please add your input:")

Part 1

input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.reduce({_depth = 0, _position = 0}, fn
  "forward " <> number, {depth, position} ->
    {depth, String.to_integer(number) + position}

  "down " <> number, {depth, position} ->
    {String.to_integer(number) + depth, position}

  "up " <> number, {depth, position} ->
    {-String.to_integer(number) + depth, position}
end)
|> then(fn {depth, position} -> depth * position end)

Part 2

defmodule Submarine do
  def navigate("forward " <> number, {depth, position, aim}) do
    number = String.to_integer(number)
    {depth + aim * number, number + position, aim}
  end

  def navigate("down " <> number, {depth, position, aim}) do
    {depth, position, aim + String.to_integer(number)}
  end

  def navigate("up " <> number, {depth, position, aim}) do
    {depth, position, aim - String.to_integer(number)}
  end
end

input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.reduce({_depth = 0, _position = 0, _aim = 0}, &amp;Submarine.navigate/2)
|> then(fn {depth, position, _aim} -> depth * position end)

Part 1 - Nx

defmodule Subnx do
  import Nx.Defn

  defn navigate(tensor) do
    {size, _} = Nx.shape(tensor)

    {_, depth, position, _} =
      while {i = 0, depth = 0, position = 0, tensor}, i < size do
        instruction = tensor[i][0]
        value = tensor[i][1]

        cond do
          instruction == 0 -> {i + 1, depth, position + value, tensor}
          instruction == 1 -> {i + 1, depth + value, position, tensor}
          instruction == 2 -> {i + 1, depth - value, position, tensor}
          :otherwise -> {i + 1, depth, position, tensor}
        end
      end

    depth * position
  end
end

input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn
  "forward " <> number -> [0, String.to_integer(number)]
  "down " <> number -> [1, String.to_integer(number)]
  "up " <> number -> [2, String.to_integer(number)]
end)
|> Nx.tensor()
|> Subnx.navigate()

Part 1 - Nx from Sean

From: https://gist.github.com/seanmor5/1d34da2d09bd0be01e53796e08fdb3d3

input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
  [direction, amt] = String.split(line)
  amt_int = String.to_integer(amt)

  case direction do
    "forward" ->
      {amt_int, 0}

    "up" ->
      {0, -amt_int}

    "down" ->
      {0, amt_int}
  end
end)
|> Enum.unzip()
|> then(fn {xs, ys} ->
  Nx.multiply(Nx.sum(Nx.tensor(xs)), Nx.sum(Nx.tensor(ys)))
end)

Part 2 - Nx from Sean

input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
  [direction, amt] = String.split(line)
  amt_int = String.to_integer(amt)

  case direction do
    "forward" ->
      {amt_int, 0}

    "up" ->
      {0, -amt_int}

    "down" ->
      {0, amt_int}
  end
end)
|> Enum.unzip()
|> then(fn {forwards, aims} ->
  aims = Nx.tensor(aims)
  forwards = Nx.tensor(forwards)

  # Do a cumulative sum of aims to get aims at each forward point
  n = Nx.size(aims)
  padding_config = [{n - 1, 0}]
  window_shape = {n}
  temporal_aims = Nx.window_sum(aims, window_shape, padding: padding_config)

  depths = Nx.dot(temporal_aims, forwards)
  horizontal = Nx.sum(forwards)
  Nx.multiply(depths, horizontal)
end)