Skip to content

Instantly share code, notes, and snippets.

@scottswezey
Last active December 3, 2021 00:37
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 scottswezey/fa6327d610c59e401148c9df890f18b7 to your computer and use it in GitHub Desktop.
Save scottswezey/fa6327d610c59e401148c9df890f18b7 to your computer and use it in GitHub Desktop.
Advent of Code 2021 - Day 2
defmodule Day2 do
@input File.read!("day2-input.txt")
defmodule PosTracker do
@callback new() :: Map.t
@callback new(integer(), integer()) :: Map.t
@callback new(integer(), integer(), integer()) :: Map.t
@callback forward(Map.t, integer()) :: Map.t
@callback up(Map.t, integer()) :: Map.t
@callback down(Map.t, integer()) :: Map.t
@optional_callbacks new: 2, new: 3
end
defmodule PosTrackerV1 do
@behaviour PosTracker
defstruct horizontal: nil, depth: nil
def new, do: %__MODULE__{horizontal: 0, depth: 0}
def new(h, d), do: %__MODULE__{horizontal: h, depth: d}
def forward(%__MODULE__{horizontal: h, depth: d}, n), do: new(h + n, d)
def up(%__MODULE__{horizontal: h, depth: d}, n), do: new(h, d - n)
def down(%__MODULE__{horizontal: h, depth: d}, n), do: new(h, d + n)
end
defmodule PosTrackerV2 do
@behaviour PosTracker
defstruct horizontal: nil, depth: nil, aim: nil
def new, do: %__MODULE__{horizontal: 0, depth: 0, aim: 0}
def new(h, d, a), do: %__MODULE__{horizontal: h, depth: d, aim: a}
def forward(%__MODULE__{horizontal: h, depth: d, aim: a}, n), do: new(h + n, d + (n * a), a)
def up(%__MODULE__{horizontal: h, depth: d, aim: a}, n), do: new(h, d, a - n)
def down(%__MODULE__{horizontal: h, depth: d, aim: a}, n), do: new(h, d, a + n)
end
def part1(input \\ @input), do: execute(input, PosTrackerV1)
def part2(input \\ @input), do: execute(input, PosTrackerV2)
defp execute(input, pos_tracker) do
input
|> parse_input()
|> follow_course(pos_tracker)
|> multiply_result()
end
def parse_input(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(&line_to_command/1)
end
defp line_to_command(line) do
[command, value] = String.split(line, " ", trim: true)
{String.to_atom(command), String.to_integer(value)}
end
defp follow_course(commands, pos_tracker) do
reducer = fn {command, dist}, pos ->
apply(pos_tracker, command, [pos, dist])
end
Enum.reduce(commands, pos_tracker.new(), reducer)
end
defp multiply_result(%{horizontal: h, depth: d}), do: h * d
end
defmodule Day2Test do
use ExUnit.Case, async: true
@test_input """
forward 5
down 5
forward 8
up 3
down 8
forward 2
"""
test "parse input" do
test_input = Day2.parse_input(@test_input)
assert hd(test_input) == {:forward, 5}
end
test "part 1" do
assert Day2.part1(@test_input) == 150
end
test "part 2" do
assert Day2.part2(@test_input) == 900
end
end
ExUnit.run()
Day2.part2()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment