This commit is contained in:
Shadowfacts 2018-12-03 16:58:13 -05:00
parent 16f5505974
commit ad6c796cd2
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
5 changed files with 105 additions and 83 deletions

View File

@ -1,7 +1,7 @@
defmodule Day1 do defmodule Day1 do
def calculate_frequency(shifts) do def calculate_frequency(shifts) do
shifts shifts
|> Enum.reduce(0, &+/2) |> Enum.reduce(0, &+/2)
end end
def first_repetition(shifts, index \\ 0, sum \\ 0, seen \\ [0]) do def first_repetition(shifts, index \\ 0, sum \\ 0, seen \\ [0]) do
@ -11,6 +11,7 @@ defmodule Day1 do
cond do cond do
Enum.member?(seen, sum) -> Enum.member?(seen, sum) ->
sum sum
true -> true ->
first_repetition(shifts, next_index, sum, [sum | seen]) first_repetition(shifts, next_index, sum, [sum | seen])
end end
@ -18,44 +19,46 @@ defmodule Day1 do
def first_repetition_stream(shifts) do def first_repetition_stream(shifts) do
shifts shifts
|> Stream.cycle() |> Stream.cycle()
|> Enum.reduce_while({0, [0]}, fn shift, {sum, seen} -> |> Enum.reduce_while({0, [0]}, fn shift, {sum, seen} ->
sum = sum + shift sum = sum + shift
cond do
Enum.member?(seen, sum) -> {:halt, sum} cond do
true -> {:cont, {sum, [sum | seen]}} Enum.member?(seen, sum) -> {:halt, sum}
end true -> {:cont, {sum, [sum | seen]}}
end) end
end)
end end
def first_repetition_mapset(shifts) do def first_repetition_mapset(shifts) do
shifts shifts
|> Stream.cycle() |> Stream.cycle()
|> Enum.reduce_while({0, MapSet.new([0])}, fn shift, {sum, seen} -> |> Enum.reduce_while({0, MapSet.new([0])}, fn shift, {sum, seen} ->
sum = sum + shift sum = sum + shift
cond do
sum in seen -> {:halt, sum} cond do
true -> {:cont, {sum, MapSet.put(seen, sum)}} sum in seen -> {:halt, sum}
end true -> {:cont, {sum, MapSet.put(seen, sum)}}
end) end
end)
end end
def parse_input() do def parse_input() do
File.read!("lib/day1/input.txt") File.read!("lib/day1/input.txt")
|> String.split("\n") |> String.split("\n")
|> Enum.map(fn s -> |> Enum.map(fn s ->
{num, _} = Integer.parse(s) {num, _} = Integer.parse(s)
num num
end) end)
end end
def part1() do def part1() do
parse_input() parse_input()
|> calculate_frequency() |> calculate_frequency()
end end
def part2() do def part2() do
parse_input() parse_input()
|> first_repetition_mapset() |> first_repetition_mapset()
end end
end end

View File

@ -1,10 +1,10 @@
defmodule Day2 do defmodule Day2 do
def count_characters(id) do def count_characters(id) do
id id
|> String.graphemes() |> String.graphemes()
|> Enum.reduce(%{}, fn c, acc -> |> Enum.reduce(%{}, fn c, acc ->
Map.update(acc, c, 1, &(&1 + 1)) Map.update(acc, c, 1, &(&1 + 1))
end) end)
end end
def checksum(list) do def checksum(list) do
@ -17,23 +17,25 @@ defmodule Day2 do
defp any_char_count(n) do defp any_char_count(n) do
fn map -> fn map ->
map map
|> Enum.to_list() |> Enum.to_list()
|> Enum.any?(fn {_c, count} -> count == n end) |> Enum.any?(fn {_c, count} -> count == n end)
end end
end end
def diff(a, b) do def diff(a, b) do
a = String.graphemes(a) a = String.graphemes(a)
b = String.graphemes(b) b = String.graphemes(b)
Enum.zip(a, b) Enum.zip(a, b)
|> Enum.reduce({0, ""}, fn {a, b}, {diff_count, common} -> |> Enum.reduce({0, ""}, fn {a, b}, {diff_count, common} ->
cond do cond do
a == b -> a == b ->
{diff_count, common <> a} {diff_count, common <> a}
true ->
{diff_count + 1, common} true ->
end {diff_count + 1, common}
end) end
end)
end end
def match(id, list) do def match(id, list) do
@ -47,12 +49,12 @@ defmodule Day2 do
def correct_boxes(list) do def correct_boxes(list) do
list list
|> Enum.reduce_while(nil, fn id, _acc -> |> Enum.reduce_while(nil, fn id, _acc ->
case match(id, list) do case match(id, list) do
nil -> {:cont, nil} nil -> {:cont, nil}
common -> {:halt, common} common -> {:halt, common}
end end
end) end)
end end
def except(list, except) do def except(list, except) do
@ -61,16 +63,16 @@ defmodule Day2 do
defp parse_input() do defp parse_input() do
File.read!("lib/day2/input.txt") File.read!("lib/day2/input.txt")
|> String.split("\n") |> String.split("\n")
end end
def part1() do def part1() do
parse_input() parse_input()
|> checksum() |> checksum()
end end
def part2() do def part2() do
parse_input() parse_input()
|> correct_boxes() |> correct_boxes()
end end
end end

View File

@ -1,11 +1,12 @@
defmodule Day3 do defmodule Day3 do
defmodule Rect do defmodule Rect do
defstruct [:id, :left, :top, :width, :height] defstruct [:id, :left, :top, :width, :height]
def points(nil), do: [] def points(nil), do: []
def points(rect) do def points(rect) do
xs = rect.left..(rect.left + rect.width - 1) xs = rect.left..(rect.left + rect.width - 1)
Enum.flat_map(xs, fn x -> Enum.flat_map(xs, fn x ->
ys = rect.top..(rect.top + rect.height - 1) ys = rect.top..(rect.top + rect.height - 1)
Enum.map(ys, fn y -> {x, y} end) Enum.map(ys, fn y -> {x, y} end)
@ -14,26 +15,34 @@ defmodule Day3 do
def overlap(a, b) do def overlap(a, b) do
overlap_left = max(a.left, b.left) overlap_left = max(a.left, b.left)
overlap_width = max(0, min(a.left + a.width, b.left + b.width) - overlap_left) overlap_width = max(0, min(a.left + a.width, b.left + b.width) - overlap_left)
overlap_top = max(a.top, b.top) overlap_top = max(a.top, b.top)
overlap_height = max(0, min(a.top + a.height, b.top + b.height) - overlap_top) overlap_height = max(0, min(a.top + a.height, b.top + b.height) - overlap_top)
case overlap_width * overlap_height do case overlap_width * overlap_height do
0 -> 0 ->
nil nil
_ -> _ ->
%Rect{left: overlap_left, top: overlap_top, width: overlap_width, height: overlap_height} %Rect{
left: overlap_left,
top: overlap_top,
width: overlap_width,
height: overlap_height
}
end end
end end
end end
def parse_rect(str) do def parse_rect(str) do
parts = Regex.run(~r/#(\d+) @ (\d+),(\d+): (\d+)x(\d+)/, str) parts = Regex.run(~r/#(\d+) @ (\d+),(\d+): (\d+)x(\d+)/, str)
%Rect{ %Rect{
id: parts |> Enum.at(1) |> String.to_integer, id: parts |> Enum.at(1) |> String.to_integer(),
left: parts |> Enum.at(2) |> String.to_integer, left: parts |> Enum.at(2) |> String.to_integer(),
top: parts |> Enum.at(3) |> String.to_integer, top: parts |> Enum.at(3) |> String.to_integer(),
width: parts |> Enum.at(4) |> String.to_integer, width: parts |> Enum.at(4) |> String.to_integer(),
height: parts |> Enum.at(5) |> String.to_integer, height: parts |> Enum.at(5) |> String.to_integer()
} }
end end
@ -43,44 +52,43 @@ defmodule Day3 do
def overlap_area(rects) do def overlap_area(rects) do
rects rects
|> Enum.flat_map(fn rect -> |> Enum.flat_map(fn rect ->
rects rects
|> except(rect) |> except(rect)
|> Enum.map(fn other -> |> Enum.map(fn other ->
Rect.overlap(rect, other) Rect.overlap(rect, other)
end)
|> Enum.flat_map(&Rect.points/1)
end) end)
|> Enum.uniq |> Enum.flat_map(&Rect.points/1)
|> Enum.count end)
|> Enum.uniq()
|> Enum.count()
end end
def exclude_overlapping(rects) do def exclude_overlapping(rects) do
rects rects
|> Enum.reject(fn rect -> |> Enum.reject(fn rect ->
rects rects
|> except(rect) |> except(rect)
|> Enum.any?(fn other -> |> Enum.any?(fn other ->
Rect.overlap(rect, other) != nil Rect.overlap(rect, other) != nil
end)
end) end)
end)
end end
def parse_input() do def parse_input() do
File.read!("lib/day3/input.txt") File.read!("lib/day3/input.txt")
|> String.split("\n", trim: true) |> String.split("\n", trim: true)
end end
def part1() do def part1() do
parse_input() parse_input()
|> Enum.map(&parse_rect/1) |> Enum.map(&parse_rect/1)
|> overlap_area() |> overlap_area()
end end
def part2() do def part2() do
parse_input() parse_input()
|> Enum.map(&parse_rect/1) |> Enum.map(&parse_rect/1)
|> exclude_overlapping() |> exclude_overlapping()
end end
end
end

View File

@ -3,7 +3,15 @@ defmodule Day2Test do
doctest Day2 doctest Day2
test "count characters" do test "count characters" do
assert Day2.count_characters("abcdef") == %{"a" => 1, "b" => 1, "c" => 1, "d" => 1, "e" => 1, "f" => 1} assert Day2.count_characters("abcdef") == %{
"a" => 1,
"b" => 1,
"c" => 1,
"d" => 1,
"e" => 1,
"f" => 1
}
assert Day2.count_characters("bababc") == %{"a" => 2, "b" => 3, "c" => 1} assert Day2.count_characters("bababc") == %{"a" => 2, "b" => 3, "c" => 1}
assert Day2.count_characters("abbcde") == %{"a" => 1, "b" => 2, "c" => 1, "d" => 1, "e" => 1} assert Day2.count_characters("abbcde") == %{"a" => 1, "b" => 2, "c" => 1, "d" => 1, "e" => 1}
end end
@ -26,4 +34,4 @@ defmodule Day2Test do
list = ["abcde", "fghij", "klmno", "pqrst", "fguij", "axcye", "wvxyz"] list = ["abcde", "fghij", "klmno", "pqrst", "fguij", "axcye", "wvxyz"]
assert Day2.correct_boxes(list) == "fgij" assert Day2.correct_boxes(list) == "fgij"
end end
end end

View File

@ -25,6 +25,7 @@ defmodule Day3Test do
%Rect{id: 2, left: 3, top: 1, width: 4, height: 4}, %Rect{id: 2, left: 3, top: 1, width: 4, height: 4},
%Rect{id: 3, left: 5, top: 5, width: 2, height: 2} %Rect{id: 3, left: 5, top: 5, width: 2, height: 2}
] ]
assert Day3.overlap_area(rects) == 4 assert Day3.overlap_area(rects) == 4
end end
@ -34,9 +35,9 @@ defmodule Day3Test do
%Rect{id: 2, left: 3, top: 1, width: 4, height: 4}, %Rect{id: 2, left: 3, top: 1, width: 4, height: 4},
%Rect{id: 3, left: 5, top: 5, width: 2, height: 2} %Rect{id: 3, left: 5, top: 5, width: 2, height: 2}
] ]
res = Day3.exclude_overlapping(rects) res = Day3.exclude_overlapping(rects)
assert Enum.count(res) == 1 assert Enum.count(res) == 1
assert Enum.at(res, 0).id == 3 assert Enum.at(res, 0).id == 3
end end
end
end