+
defmodule AdventOfCode.Day01 do
- def part1(_args) do
+ require Logger
+ use Flow
+
+ def part1(input \\ nil) do
+ input = if is_nil(input), do: AdventOfCode.Input.get!(1), else: input
+ {lefts, rights} = parse_input(input)
+ s_lefts = Enum.sort(lefts)
+ s_rights = Enum.sort(rights)
+
+ Enum.zip(s_lefts, s_rights)
+ |> Enum.map(fn {l, r} -> abs(l - r) end)
+ |> Enum.sum()
+ end
+
+ def part2(input \\ nil) do
+ input = if is_nil(input), do: AdventOfCode.Input.get!(1), else: input
+ {lefts, rights} = parse_input(input)
+
+ right_counts = rights
+ |> Flow.from_enumerable()
+ |> Flow.partition(key: fn x -> rem(x, 100) end)
+ |> Flow.reduce(fn -> %{} end, fn item, acc ->
+ Map.update(acc, item, 1, &(&1 + 1))
+ end)
+ |> Enum.reduce(%{}, fn {n, c}, acc -> Map.merge(%{n => c}, acc) end)
+
+ # right_counts = Enum.frequencies(rights)
+
+ similarity =
+ lefts
+ |> Enum.map(fn x -> x * Map.get(right_counts, x, 0) end)
+ |> Enum.sum()
+
+ similarity
+ end
+
+ defp parse_input(input) do
+ input
+ |> String.split("\n")
+ |> Task.async_stream(&parse_line/1, ordered: false)
+ |> Enum.map(fn r -> elem(r, 1) end)
+ |> Enum.unzip()
+
+ # |> String.split("\n")
+ # |> Enum.map(&String.split/1)
+ # # |> Enum.map(fn xs -> xs |> Enum.map(&String.to_integer/1) end)
+ # |> Enum.map(fn xs -> Enum.map(xs, &String.to_integer/1) end)
+ # |> Enum.map(fn xs -> {Enum.at(xs, 0), Enum.at(xs, 1)} end)
+ # |> Enum.unzip()
end
- def part2(_args) do
+ defp parse_line(inline) do
+ lp = inline
+ |> String.split()
+ |> Enum.map(&String.to_integer/1)
+ {Enum.at(lp, 0), Enum.at(lp, 1)}
end
end
cache, it will be retrieved from the server if `allow_network?: true` is
configured and your cookie is setup.
"""
- def get!(day, year \\ nil)
- def get!(day, nil), do: get!(day, default_year())
- def get!(day, year) do
- cond do
- in_cache?(day, year) ->
- from_cache!(day, year)
-
- allow_network?() ->
- download!(day, year)
-
- true ->
- raise "Cache miss for day #{day} of year #{year} and `:allow_network?` is not `true`"
- end
- end
-
- @doc """
- If, somehow, your input is invalid or mangled and you want to delete it from
- your cache so you can re-fetch it, this will save your bacon.
- Please don't use this to retrieve the input from the server repeatedly!
- """
- def delete!(day, year \\ nil)
- def delete!(day, nil), do: delete!(day, default_year())
- def delete!(day, year), do: File.rm!(cache_path(day, year))
-
- defp cache_path(day, year), do: Path.join(cache_dir(), "/#{year}/#{day}.aocinput")
- defp in_cache?(day, year), do: File.exists?(cache_path(day, year))
-
- defp store_in_cache!(day, year, input) do
- path = cache_path(day, year)
- :ok = path |> Path.dirname() |> File.mkdir_p()
- :ok = File.write(path, input)
- end
-
- defp from_cache!(day, year), do: File.read!(cache_path(day, year))
-
- defp download!(day, year) do
- {:ok, {{~c"HTTP/1.1", 200, ~c"OK"}, _, input}} =
- :httpc.request(
- :get,
- {~c"https://adventofcode.com/#{year}/day/#{day}/input", headers()},
- [],
- []
- )
-
- store_in_cache!(day, year, input)
-
- to_string(input)
+ def get!(day, suffix \\ "") do
+ day_string = Integer.to_string(day) |> String.pad_leading(2, "0")
+ filename = "../data/advent#{day_string}#{suffix}.txt"
+ File.read!(filename)
end
- defp cache_dir do
- config()
- |> Keyword.get(
- :cache_dir,
- Path.join([System.get_env("XDG_CACHE_HOME", "~/.cache"), "/advent_of_code_inputs"])
- )
- |> Path.expand()
- end
-
- defp default_year do
- case :calendar.local_time() do
- {{y, 12, _}, _} -> y
- {{y, _, _}, _} -> y - 1
- end
- end
-
- defp config, do: Application.get_env(:advent_of_code, __MODULE__)
- defp allow_network?, do: Keyword.get(config(), :allow_network?, false)
-
- defp headers,
- do: [
- {~c"user-agent",
- ~c"github.com/mhanberg/advent-of-code-elixir-starter by aoc@mitchellhanberg.com"},
- {~c"cookie", String.to_charlist("session=" <> Keyword.get(config(), :session_cookie))}
- ]
+ # @doc """
+ # If, somehow, your input is invalid or mangled and you want to delete it from
+ # your cache so you can re-fetch it, this will save your bacon.
+ # Please don't use this to retrieve the input from the server repeatedly!
+ # """
+ # def delete!(day, year \\ nil)
+ # def delete!(day, nil), do: delete!(day, default_year())
+ # def delete!(day, year), do: File.rm!(cache_path(day, year))
+
+ # defp cache_path(day, year), do: Path.join(cache_dir(), "/#{year}/#{day}.aocinput")
+ # defp in_cache?(day, year), do: File.exists?(cache_path(day, year))
+
+ # defp store_in_cache!(day, year, input) do
+ # path = cache_path(day, year)
+ # :ok = path |> Path.dirname() |> File.mkdir_p()
+ # :ok = File.write(path, input)
+ # end
+
+ # defp from_cache!(day, year), do: File.read!(cache_path(day, year))
+
+ # defp download!(day, year) do
+ # {:ok, {{~c"HTTP/1.1", 200, ~c"OK"}, _, input}} =
+ # :httpc.request(
+ # :get,
+ # {~c"https://adventofcode.com/#{year}/day/#{day}/input", headers()},
+ # [],
+ # []
+ # )
+
+ # store_in_cache!(day, year, input)
+
+ # to_string(input)
+ # end
+
+ # defp cache_dir do
+ # config()
+ # |> Keyword.get(
+ # :cache_dir,
+ # Path.join([System.get_env("XDG_CACHE_HOME", "~/.cache"), "/advent_of_code_inputs"])
+ # )
+ # |> Path.expand()
+ # end
+
+ # defp default_year do
+ # case :calendar.local_time() do
+ # {{y, 12, _}, _} -> y
+ # {{y, _, _}, _} -> y - 1
+ # end
+ # end
+
+ # defp config, do: Application.get_env(:advent_of_code, __MODULE__)
+ # defp allow_network?, do: Keyword.get(config(), :allow_network?, false)
+
+ # defp headers,
+ # do: [
+ # {~c"user-agent",
+ # ~c"github.com/mhanberg/advent-of-code-elixir-starter by aoc@mitchellhanberg.com"},
+ # {~c"cookie", String.to_charlist("session=" <> Keyword.get(config(), :session_cookie))}
+ # ]
end
%{
"benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
+ "flow": {:hex, :flow, "1.2.4", "1dd58918287eb286656008777cb32714b5123d3855956f29aa141ebae456922d", [:mix], [{:gen_stage, "~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}], "hexpm", "874adde96368e71870f3510b91e35bc31652291858c86c0e75359cbdd35eb211"},
+ "gen_stage": {:hex, :gen_stage, "1.2.1", "19d8b5e9a5996d813b8245338a28246307fd8b9c99d1237de199d21efc4c76a1", [:mix], [], "hexpm", "83e8be657fa05b992ffa6ac1e3af6d57aa50aace8f691fcf696ff02f8335b001"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
}