Day 2: Dive!
Section
defmodule Setup do
## parsing the input, converting it to a list of lines
def get_input(prompt) do
case IO.gets(prompt) do
:eof -> ""
line -> line <> get_input(prompt)
end
end
def parse_input(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(&parse_line/1)
end
defp parse_line("forward " <> units), do: {:forward, String.to_integer(units)}
defp parse_line("down " <> units), do: {:down, String.to_integer(units)}
defp parse_line("up " <> units), do: {:up, String.to_integer(units)}
end
input =
Setup.get_input("Input")
|> Setup.parse_input()
defmodule Submarine do
def position(instructions, pos \\ {0, 0}) do
{x, y} = Enum.reduce(instructions, pos, &move/2)
x * y
end
defp move({:forward, unit}, {x, y}), do: {x + unit, y}
defp move({:down, unit}, {x, y}), do: {x, y + unit}
defp move({:up, unit}, {x, y}), do: {x, y - unit}
end
Submarine.position(input)
Part 2
defmodule Submarine2 do
def position(instructions, pos \\ {0, 0, 0}) do
{_, x, y} = Enum.reduce(instructions, pos, &move/2)
x * y
end
def move({:forward, unit}, {a, x, y}), do: {a, x + unit, y + a * unit}
def move({:down, unit}, {a, x, y}), do: {a + unit, x, y}
def move({:up, unit}, {a, x, y}), do: {a - unit, x, y}
end
Submarine2.position(input)
Test
ExUnit.start()
defmodule Test do
use ExUnit.Case
setup do
{:ok,
input:
Setup.parse_input("""
forward 5
down 5
forward 8
up 3
down 8
forward 2
""")}
end
test "setup", %{input: input} do
assert input ==
[
forward: 5,
down: 5,
forward: 8,
up: 3,
down: 8,
forward: 2
]
end
test "position", %{input: input} do
assert Submarine.position(input) == 150
end
test "position2", %{input: input} do
assert Submarine2.position(input) == 900
end
end
ExUnit.run()
Animate descent
Mix.install([:vega_lite, :kino])
alias VegaLite, as: Vl
widget =
Vl.new(width: 400, height: 400)
|> Vl.mark(:line)
|> Vl.encode_field(:x, "position", type: :quantitative)
|> Vl.encode_field(:y, "depth", type: :quantitative)
|> Kino.VegaLite.new()
|> tap(&Kino.render/1)
Enum.reduce(input, {0, 0, 0}, fn instr, pos ->
{_, x, y} = pos = Submarine2.move(instr, pos)
point = %{"position" => x, "depth" => -y}
Kino.VegaLite.push(widget, point, window: 2000)
Process.sleep(25)
pos
end)