Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions 2022/day13/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
28 changes: 28 additions & 0 deletions 2022/day13/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
day13-*.tar

# Temporary files, for example, from tests.
/tmp/

day13
11 changes: 11 additions & 0 deletions 2022/day13/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Day 13

[Challenge link](https://adventofcode.com/2022/day/13).

How to run:

Put your data into 'data.txt' (in the same directory as this readme file).

```sh
mix escript.build && ./day13
```
52 changes: 52 additions & 0 deletions 2022/day13/lib/comparator/comparator.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
defmodule Comparator do
@spec compare(any(), any()) :: boolean
def compare(l, r) do
case check_order(l, r) do
:ok -> true
:inconclusive -> true
:wrong -> false
end
end

@spec check_order(any(), any()) :: :ok | :wrong | :inconclusive
defp check_order(l, r) do
case {l, r} do
{a, b} when is_integer(a) and is_integer(b) -> compare_ints(a, b)
{a, b} when is_list(a) and is_list(b) -> compare_lists(a, b)
{a, b} when is_integer(a) and is_list(b) -> check_order([a], b)
{a, b} when is_list(a) and is_integer(b) -> check_order(a, [b])
end
end

@spec compare_ints(integer(), integer()) :: :ok | :wrong | :inconclusive
defp compare_ints(a, b) do
cond do
a < b -> :ok
a > b -> :wrong
a == b -> :inconclusive
end
end

@spec compare_lists([], []) :: :ok | :wrong | :inconclusive
defp compare_lists(a, b) do
cond do
a == [] and b == [] -> :inconclusive
a == [] -> :ok
b == [] -> :wrong
true -> compare_lists_by_element(a, b)
end
end

@spec compare_lists_by_element([], []) :: :ok | :wrong | :inconclusive
defp compare_lists_by_element(a, b) do
first_a = Enum.at(a, 0)
first_b = Enum.at(b, 0)
order = check_order(first_a, first_b)

if order != :inconclusive do
order
else
compare_lists(Enum.drop(a, 1), Enum.drop(b, 1))
end
end
end
14 changes: 14 additions & 0 deletions 2022/day13/lib/main.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule Day13.CLI do
def main(_args) do
File.stream!("data.txt") |> Parser.data() |> solve()
:ok
end

defp solve(contents) do
IO.write("task #1 solution: ")
Task1.solution(contents) |> IO.puts()

IO.write("task #2 solution: ")
Task2.solution(contents) |> IO.puts()
end
end
23 changes: 23 additions & 0 deletions 2022/day13/lib/parser.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Parser do
@spec lines(File.Stream) :: Stream.t()
def lines(fstream) do
fstream
|> Stream.map(&String.trim/1)
end

@spec data(Stream.t()) :: Stream.t()
def data(lines) do
lines |> Enum.chunk_every(3) |> Enum.map(fn l -> parse_pair(l) end)
end

@spec parse_pair([String.t()]) :: {[], []}
defp parse_pair(s) do
[first, second] = s |> Enum.take(2)
{parse_packet(first), parse_packet(second)}
end

@spec parse_packet(String.t()) :: []
defp parse_packet(s) do
Code.eval_string(s) |> elem(0)
end
end
10 changes: 10 additions & 0 deletions 2022/day13/lib/task1/task1.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule Task1 do
@spec solution([{[], []}]) :: integer()
def solution(pairs) do
Enum.map(pairs, fn {l, r} -> Comparator.compare(l, r) end)
|> Enum.with_index()
|> Enum.filter(fn {x, _} -> x end)
|> Enum.map(fn {_, i} -> i + 1 end)
|> Enum.sum()
end
end
17 changes: 17 additions & 0 deletions 2022/day13/lib/task2/task2.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Task2 do
@spec solution([{[], []}]) :: integer()
def solution(pairs) do
Enum.reduce(pairs, [], fn {l, r}, acc -> [l] ++ [r] ++ acc end)
|> with_new_pairs()
|> Enum.sort(&Comparator.compare/2)
|> Enum.with_index()
|> Enum.filter(fn {x, _} -> x == [[2]] or x == [[6]] end)
|> Enum.map(fn {_, i} -> i + 1 end)
|> Enum.reduce(1, fn x, acc -> x * acc end)
end

@spec with_new_pairs([]) :: []
defp with_new_pairs(list) do
[[[2]]] ++ [[[6]]] ++ list
end
end
33 changes: 33 additions & 0 deletions 2022/day13/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
defmodule Day13.MixProject do
use Mix.Project

def project do
[
app: :day13,
version: "0.1.0",
elixir: "~> 1.14",
start_permanent: Mix.env() == :prod,
deps: deps(),
escript: escript()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

defp escript do
[main_module: Day13.CLI]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end
1 change: 1 addition & 0 deletions 2022/day13/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()