This commit is contained in:
Shadowfacts 2018-12-06 20:14:24 -05:00
parent 7d5f3501c0
commit ee489439e1
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
6 changed files with 90 additions and 64 deletions

View File

@ -1,5 +1,4 @@
defmodule Day4 do defmodule Day4 do
defmodule Timestamp do defmodule Timestamp do
defstruct [:year, :month, :day, :hour, :minute] defstruct [:year, :month, :day, :hour, :minute]
@ -9,7 +8,7 @@ defmodule Day4 do
month: m |> String.to_integer(), month: m |> String.to_integer(),
day: d |> String.to_integer(), day: d |> String.to_integer(),
hour: h |> String.to_integer(), hour: h |> String.to_integer(),
minute: min |> String.to_integer minute: min |> String.to_integer()
} }
end end
@ -17,10 +16,11 @@ defmodule Day4 do
first.minute..second.minute first.minute..second.minute
end end
end end
def parse_event(line) do def parse_event(line) do
res = Regex.run(~r/\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.+)/, line) res = Regex.run(~r/\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.+)/, line)
[_line, y, m, d, h, min, event | _tail] = res [_line, y, m, d, h, min, event | _tail] = res
{ {
Timestamp.create(y, m, d, h, min), Timestamp.create(y, m, d, h, min),
event event
@ -53,10 +53,12 @@ defmodule Day4 do
_id -> {:cont, Enum.reverse(acc), [event]} _id -> {:cont, Enum.reverse(acc), [event]}
end end
end end
after_fun = fn after_fun = fn
[] -> {:cont, []} [] -> {:cont, []}
acc -> {:cont, Enum.reverse(acc), acc} acc -> {:cont, Enum.reverse(acc), acc}
end end
events events
|> Enum.chunk_while([], chunk_fun, after_fun) |> Enum.chunk_while([], chunk_fun, after_fun)
|> Enum.reject(fn |> Enum.reject(fn
@ -65,11 +67,14 @@ defmodule Day4 do
end) end)
|> Enum.reduce(%{}, fn [begin_shift | events], acc -> |> Enum.reduce(%{}, fn [begin_shift | events], acc ->
guard_id = parse_guard(begin_shift) guard_id = parse_guard(begin_shift)
ranges = events
|> Enum.chunk_every(2) ranges =
|> Enum.map(fn [{sleep, _}, {wake, _} | []] -> events
Timestamp.range(sleep, wake) |> Enum.chunk_every(2)
end) |> Enum.map(fn [{sleep, _}, {wake, _} | []] ->
Timestamp.range(sleep, wake)
end)
Map.update(acc, guard_id, ranges, &(&1 ++ ranges)) Map.update(acc, guard_id, ranges, &(&1 ++ ranges))
end) end)
|> Enum.reject(fn |> Enum.reject(fn
@ -81,38 +86,48 @@ defmodule Day4 do
def get_max_sleep_time(guards) do def get_max_sleep_time(guards) do
guards guards
|> Enum.map(fn {id, times} -> |> Enum.map(fn {id, times} ->
total = times total =
|> Enum.map(fn a..b -> b - a end) times
|> Enum.sum() |> Enum.map(fn a..b -> b - a end)
{minute, _count} = times |> Enum.sum()
|> Enum.flat_map(&Enum.to_list/1)
|> Enum.reduce(%{}, fn minute, acc -> {minute, _count} =
Map.update(acc, minute, 1, &(&1 + 1)) times
end) |> Enum.flat_map(&Enum.to_list/1)
|> Enum.max_by(fn {_minute, count} -> count end) |> Enum.reduce(%{}, fn minute, acc ->
Map.update(acc, minute, 1, &(&1 + 1))
end)
|> Enum.max_by(fn {_minute, count} -> count end)
{id, total, minute} {id, total, minute}
end) end)
|> Enum.max_by(fn {_id, total, _minute} -> total end) |> Enum.max_by(fn {_id, total, _minute} -> total end)
end end
def range_containing(ranges) do def range_containing(ranges) do
first = Enum.reduce(ranges, Enum.at(ranges, 0).first, fn first.._, acc -> first =
min(first, acc) Enum.reduce(ranges, Enum.at(ranges, 0).first, fn first.._, acc ->
end) min(first, acc)
last = Enum.reduce(ranges, Enum.at(ranges, 0).last, fn _..last, acc -> end)
max(last, acc)
end) last =
Enum.reduce(ranges, Enum.at(ranges, 0).last, fn _..last, acc ->
max(last, acc)
end)
first..last first..last
end end
def get_most_frequent_sleep_time(guards) do def get_most_frequent_sleep_time(guards) do
guards guards
|> Enum.map(fn {id, times} -> |> Enum.map(fn {id, times} ->
{minute, count} = range_containing(times) {minute, count} =
|> Enum.map(fn minute -> range_containing(times)
{minute, Enum.count(times, fn range -> minute in range end)} |> Enum.map(fn minute ->
end) {minute, Enum.count(times, fn range -> minute in range end)}
|> Enum.max_by(fn {_minute, count} -> count end) end)
|> Enum.max_by(fn {_minute, count} -> count end)
{id, minute, count} {id, minute, count}
end) end)
|> Enum.max_by(fn {_id, _minute, count} -> count end) |> Enum.max_by(fn {_id, _minute, count} -> count end)
@ -124,21 +139,24 @@ defmodule Day4 do
end end
def part1() do def part1() do
{id, _total, minute} = parse_input() {id, _total, minute} =
|> parse_events() parse_input()
|> sort_events() |> parse_events()
|> get_sleep_times() |> sort_events()
|> get_max_sleep_time() |> get_sleep_times()
|> get_max_sleep_time()
String.to_integer(id) * minute String.to_integer(id) * minute
end end
def part2() do def part2() do
{id, minute, _count} = parse_input() {id, minute, _count} =
|> parse_events() parse_input()
|> sort_events() |> parse_events()
|> get_sleep_times() |> sort_events()
|> get_most_frequent_sleep_time() |> get_sleep_times()
|> get_most_frequent_sleep_time()
String.to_integer(id) * minute String.to_integer(id) * minute
end end
end
end

View File

@ -1,5 +1,4 @@
defmodule Day5 do defmodule Day5 do
@doc """ @doc """
Compares two codepoints for opposite case. Compares two codepoints for opposite case.
@ -18,6 +17,7 @@ defmodule Day5 do
else else
[c | s] [c | s]
end end
c, [] -> c, [] ->
[c] [c]
end) end)
@ -76,6 +76,7 @@ defmodule Day5 do
s = <<c::utf8>> s = <<c::utf8>>
str = String.replace(input, s, "") str = String.replace(input, s, "")
str = String.replace(str, String.upcase(s), "") str = String.replace(str, String.upcase(s), "")
input input
|> String.replace(s, "") |> String.replace(s, "")
|> String.replace(String.upcase(s), "") |> String.replace(String.upcase(s), "")
@ -87,7 +88,7 @@ defmodule Day5 do
end end
def parse_input() do def parse_input() do
File.read!("lib/day5/input.txt") File.read!("lib/day5/input.txt")
end end
def part1() do def part1() do
@ -101,5 +102,4 @@ defmodule Day5 do
parse_input() parse_input()
|> min_length() |> min_length()
end end
end
end

View File

@ -1,5 +1,4 @@
defmodule Day6 do defmodule Day6 do
@doc """ @doc """
Parses a node from a string. Parses a node from a string.
@ -11,6 +10,7 @@ defmodule Day6 do
""" """
def parse_node(s) do def parse_node(s) do
[x, y] = String.split(s, ", ") [x, y] = String.split(s, ", ")
{ {
x |> String.to_integer(), x |> String.to_integer(),
y |> String.to_integer() y |> String.to_integer()
@ -39,7 +39,7 @@ defmodule Day6 do
nil nil
""" """
def nearest_node(point, all) do def nearest_node(point, all) do
nearest = nearest =
all all
|> Enum.map(fn other -> {other, distance(point, other)} end) |> Enum.map(fn other -> {other, distance(point, other)} end)
@ -58,9 +58,11 @@ defmodule Day6 do
0..grid_size 0..grid_size
|> Enum.reduce(acc, fn x, {areas, infinite_area_nodes} -> |> Enum.reduce(acc, fn x, {areas, infinite_area_nodes} ->
pt = {x, y} pt = {x, y}
case nearest_node(pt, nodes) do case nearest_node(pt, nodes) do
nil -> nil ->
{areas, infinite_area_nodes} {areas, infinite_area_nodes}
nearest -> nearest ->
if x == 0 or y == 0 or x == grid_size or y == grid_size do if x == 0 or y == 0 or x == grid_size or y == grid_size do
{ {
@ -102,9 +104,11 @@ defmodule Day6 do
0..grid_size 0..grid_size
|> Enum.reduce(acc, fn x, acc -> |> Enum.reduce(acc, fn x, acc ->
pt = {x, y} pt = {x, y}
cond do cond do
total_distances(pt, nodes) < max_dist -> total_distances(pt, nodes) < max_dist ->
[pt | acc] [pt | acc]
true -> true ->
acc acc
end end
@ -128,5 +132,4 @@ defmodule Day6 do
|> region_near_most() |> region_near_most()
|> Enum.count() |> Enum.count()
end end
end
end

View File

@ -4,11 +4,15 @@ defmodule Day4Test do
alias Day4.Timestamp alias Day4.Timestamp
test "parse event" do test "parse event" do
assert Day4.parse_event("[1518-11-01 00:00] Guard #10 begins shift") == {%Timestamp{year: 1518, month: 11, day: 01, hour: 0, minute: 0}, "Guard #10 begins shift"} assert Day4.parse_event("[1518-11-01 00:00] Guard #10 begins shift") ==
{%Timestamp{year: 1518, month: 11, day: 01, hour: 0, minute: 0},
"Guard #10 begins shift"}
end end
test "parse guard" do test "parse guard" do
event = {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 00}, "Guard #10 begins shift"} event =
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 00}, "Guard #10 begins shift"}
assert Day4.parse_guard(event) == "10" assert Day4.parse_guard(event) == "10"
end end
@ -17,17 +21,19 @@ defmodule Day4Test do
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 05}, "falls asleep"}, {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 05}, "falls asleep"},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 55}, "wakes up"}, {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 55}, "wakes up"},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 25}, "wakes up"}, {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 25}, "wakes up"},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 00}, "Guard #10 begins shift"}, {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 00},
"Guard #10 begins shift"},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 30}, "falls asleep"} {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 30}, "falls asleep"}
] ]
assert Day4.sort_events(events) == [ assert Day4.sort_events(events) == [
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 00}, "Guard #10 begins shift"}, {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 00},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 05}, "falls asleep"}, "Guard #10 begins shift"},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 25}, "wakes up"}, {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 05}, "falls asleep"},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 30}, "falls asleep"}, {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 25}, "wakes up"},
{%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 55}, "wakes up"} {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 30}, "falls asleep"},
] {%Timestamp{year: 1518, month: 11, day: 01, hour: 00, minute: 55}, "wakes up"}
]
end end
test "get sleep times" do test "get sleep times" do
@ -52,9 +58,9 @@ defmodule Day4Test do
] ]
assert Day4.get_sleep_times(events) == [ assert Day4.get_sleep_times(events) == [
{"10", [5..25, 30..55, 24..29]}, {"10", [5..25, 30..55, 24..29]},
{"99", [40..50, 36..46, 45..55]} {"99", [40..50, 36..46, 45..55]}
] ]
end end
test "get max sleep time" do test "get max sleep time" do
@ -79,5 +85,4 @@ defmodule Day4Test do
assert Day4.get_most_frequent_sleep_time(guards) == {"99", 45, 3} assert Day4.get_most_frequent_sleep_time(guards) == {"99", 45, 3}
end end
end
end

View File

@ -1,4 +1,4 @@
defmodule Day5Test do defmodule Day5Test do
use ExUnit.Case use ExUnit.Case
doctest Day5 doctest Day5
end end

View File

@ -1,4 +1,4 @@
defmodule Day6Test do defmodule Day6Test do
use ExUnit.Case use ExUnit.Case
doctest Day6 doctest Day6
end end