Compare commits
23 Commits
c6c501af2a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa1d6f5ca0 | ||
|
|
a9519aebbf | ||
|
|
3fc1300387 | ||
|
|
c550c1850c | ||
|
|
e24b45de16 | ||
|
|
a7beb06a28 | ||
|
|
03b92dd930 | ||
|
|
131f501b91 | ||
|
|
e9367fd784 | ||
|
|
753635b38e | ||
|
|
5c04d2651e | ||
|
|
1655ead021 | ||
|
|
3361ad3a79 | ||
|
|
20501c0819 | ||
|
|
c500a9a280 | ||
|
|
863e1a5cb0 | ||
|
|
abbd8a263a | ||
|
|
683522ddc0 | ||
|
|
ce5e83baa4 | ||
|
|
ee17acccae | ||
|
|
2ae3b6cf7b | ||
|
|
c086fc1773 | ||
|
|
2784245b2d |
@@ -4,9 +4,11 @@ defmodule Aoc2023 do
|
||||
import Aoc2023.Common
|
||||
|
||||
def main(input) do
|
||||
parsed = parse(input)
|
||||
IO.puts("Part 1: #{part1(parsed)}")
|
||||
IO.puts("Part 2: #{part2(parsed)}")
|
||||
{t_parse, parsed} = :timer.tc fn -> parse(input) end
|
||||
{t_p1, _} = :timer.tc fn -> IO.puts("Part 1: #{part1(parsed)}") end
|
||||
|
||||
{t_p2, _} = :timer.tc fn -> IO.puts("Part 2: #{part2(parsed)}") end
|
||||
IO.puts("Took #{(t_parse + t_p1 + t_p2) / 1_000}ms (parse: #{t_parse / 1_000}ms, part1: #{t_p1 / 1_000}ms, part2: #{t_p2 / 1_000}ms)")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,4 +12,55 @@ defmodule Aoc2023.Common do
|
||||
fn (val) -> val |> unquote(expr) end
|
||||
end
|
||||
end
|
||||
|
||||
defmacro l &&& r do
|
||||
quote do
|
||||
fn val ->
|
||||
l = val |> unquote(l)
|
||||
r = val |> unquote(r)
|
||||
{l, r}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def runs(lst, f) do
|
||||
lst
|
||||
|> Enum.with_index()
|
||||
|> Enum.chunk_by(pipe(elem(0) |> f.()))
|
||||
|> Enum.filter(pipe(Enum.at(0) |> elem(0) |> f.()))
|
||||
|> Enum.map(Enum.at(0) |> elem(1) &&& length)
|
||||
end
|
||||
|
||||
def id(x), do: x
|
||||
def const(_, x), do: x
|
||||
|
||||
def lines(x), do: String.split(x, "\n")
|
||||
|
||||
def head([head | _]), do: head
|
||||
def head([]), do: nil
|
||||
def tail([_ | tail]), do: tail
|
||||
def tail([]), do: nil
|
||||
|
||||
def lcm(a, b), do: div(abs(a*b), Integer.gcd(a,b))
|
||||
def lcm(ls), do: ls |> Enum.reduce(&lcm/2)
|
||||
|
||||
def list_map_at(l, n, f) do
|
||||
List.replace_at(l, n, f.(Enum.at(l, n)))
|
||||
end
|
||||
|
||||
def transpose(l), do: l |> Enum.zip |> Enum.map(&Tuple.to_list/1)
|
||||
|
||||
def collapse(enum, v) do
|
||||
enum
|
||||
|> Stream.zip(enum |> Stream.drop(1) |> Stream.concat([nil]))
|
||||
|> Stream.filter(fn {a, b} -> a != v || b != v end)
|
||||
|> Stream.map(pipe(elem(0)))
|
||||
end
|
||||
|
||||
def repeat(_, 0), do: []
|
||||
def repeat(lst, n), do: Enum.concat(lst, repeat(lst, n - 1))
|
||||
|
||||
def add_vec({y, x}, {y_, x_}) do
|
||||
{y + y_, x + x_}
|
||||
end
|
||||
end
|
||||
|
||||
91
lib/day10.ex
Normal file
91
lib/day10.ex
Normal file
@@ -0,0 +1,91 @@
|
||||
defmodule Aoc2023.Day10 do
|
||||
use Aoc2023
|
||||
require Integer
|
||||
|
||||
@connections %{
|
||||
?| => [{-1, 0}, {1, 0}],
|
||||
?- => [{0, -1}, {0, 1}],
|
||||
?L => [{-1, 0}, {0, 1}],
|
||||
?J => [{-1, 0}, {0, -1}],
|
||||
?7 => [{1, 0}, {0, -1}],
|
||||
?F => [{1, 0}, {0, 1}],
|
||||
?. => [],
|
||||
?S => []
|
||||
}
|
||||
|
||||
defp path(s_conns, conns) do
|
||||
loop = fn recur, checked, checking ->
|
||||
checked_ = MapSet.union(checked, checking)
|
||||
|
||||
checking_ =
|
||||
checking
|
||||
|> Enum.flat_map(&Map.get(conns, &1, []))
|
||||
|> MapSet.new()
|
||||
|> MapSet.difference(checked_)
|
||||
|
||||
if MapSet.size(checking_) > 0, do: recur.(recur, checked_, checking_), else: checked_
|
||||
end
|
||||
|
||||
loop.(loop, MapSet.new(), MapSet.new(s_conns))
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
grid =
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(&String.to_charlist/1)
|
||||
|> Enum.with_index()
|
||||
|
||||
s =
|
||||
grid
|
||||
|> Enum.find_value(fn {line, y} ->
|
||||
x = line |> Enum.find_index(&(&1 == ?S))
|
||||
if x, do: {y, x}
|
||||
end)
|
||||
|
||||
conns =
|
||||
grid
|
||||
|> Enum.flat_map(fn {row, y} ->
|
||||
row
|
||||
|> Enum.with_index()
|
||||
|> Enum.map(fn {c, x} ->
|
||||
{
|
||||
{y, x},
|
||||
Map.get(@connections, c) |> Enum.map(pipe(add_vec({y, x})))
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
|
||||
s_conns = conns |> Enum.filter(&(s in elem(&1, 1))) |> Enum.map(pipe(elem(0)))
|
||||
{s, s_conns, grid, path(s_conns, conns)}
|
||||
end
|
||||
|
||||
def part1({_, _, _, path}) do
|
||||
path
|
||||
|> MapSet.size()
|
||||
|> then(&(&1 / 2))
|
||||
|> trunc()
|
||||
end
|
||||
|
||||
def part2({{sy, sx}, s_conns, grid, path}) do
|
||||
s_dirs = s_conns |> Enum.map(pipe(add_vec({-sy, -sx}))) |> Enum.sort()
|
||||
s_char = @connections |> Enum.find(fn {_, conns} -> Enum.sort(conns) == s_dirs end) |> elem(0)
|
||||
grid_ = grid |> list_map_at(sy, pipe(map_nth(0, pipe(List.replace_at(sx, s_char)))))
|
||||
|
||||
grid_
|
||||
|> Stream.map(fn {line, y} ->
|
||||
for x <- 0..length(line) - 1, reduce: {false, 0} do
|
||||
{within, area} ->
|
||||
cond do
|
||||
{y, x} in path and Enum.at(line, x) in [?L, ?J, ?|] -> {not within, area}
|
||||
{y, x} in path -> {within, area}
|
||||
within -> {within, area + 1}
|
||||
true -> {within, area}
|
||||
end
|
||||
end
|
||||
|> elem(1)
|
||||
end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
48
lib/day11.ex
Normal file
48
lib/day11.ex
Normal file
@@ -0,0 +1,48 @@
|
||||
defmodule Aoc2023.Day11 do
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
coords =
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(pipe(String.to_charlist() |> Enum.map(&(&1 == ?#))))
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {row, y} ->
|
||||
row
|
||||
|> Enum.with_index()
|
||||
|> Enum.filter(pipe(elem(0)))
|
||||
|> Enum.map(fn {_, x} -> {y, x} end)
|
||||
end)
|
||||
|
||||
ys = coords |> Enum.map(pipe(elem(0))) |> MapSet.new()
|
||||
empty_rows = MapSet.difference(MapSet.new(0..(ys |> Enum.max())), ys)
|
||||
xs = coords |> Enum.map(pipe(elem(1))) |> MapSet.new()
|
||||
empty_cols = MapSet.difference(MapSet.new(0..(xs |> Enum.max())), xs)
|
||||
fn expansion ->
|
||||
coords_ =
|
||||
coords
|
||||
|> Enum.map(fn {y, x} ->
|
||||
{y + Enum.count(empty_rows, &(&1 < y)) * (expansion - 1),
|
||||
x + Enum.count(empty_cols, &(&1 < x)) * (expansion - 1)}
|
||||
end)
|
||||
|
||||
coords_
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {c, i} -> coords_ |> Enum.drop(i + 1) |> Enum.map(&{c, &1}) end)
|
||||
|> Enum.map(&dist/1)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
|
||||
defp dist({{y1, x1}, {y2, x2}}) do
|
||||
abs(x1 - x2) + abs(y1 - y2)
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
input.(2)
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
input.(1_000_000)
|
||||
end
|
||||
end
|
||||
93
lib/day12.ex
Normal file
93
lib/day12.ex
Normal file
@@ -0,0 +1,93 @@
|
||||
defmodule Aoc2023.Day12 do
|
||||
use Aoc2023
|
||||
|
||||
defmodule Cache do
|
||||
use GenServer
|
||||
|
||||
def start do
|
||||
{:ok, pid} = GenServer.start_link(Cache, nil)
|
||||
pid
|
||||
end
|
||||
|
||||
def memoize(cache, key, fun) do
|
||||
got = GenServer.call(cache, {:get, key})
|
||||
if got == nil do
|
||||
val = fun.(key)
|
||||
GenServer.call(cache, {:set, key, val})
|
||||
val
|
||||
else
|
||||
got
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_) do
|
||||
{:ok, %{}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:get, key}, _, state) do
|
||||
case state do
|
||||
%{^key => value} ->
|
||||
{:reply, value, state}
|
||||
|
||||
_ ->
|
||||
{:reply, nil, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:set, key, value}, _, state) do
|
||||
{:reply, nil, Map.put_new(state, key, value)}
|
||||
end
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(
|
||||
pipe(
|
||||
String.split()
|
||||
|> then(fn [rec, blocks] ->
|
||||
{rec |> String.to_charlist(),
|
||||
blocks |> String.split(",") |> Enum.map(&String.to_integer/1)}
|
||||
end)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
defp possibilities({rec, blocks}) do
|
||||
loop = fn recur, arg ->
|
||||
case arg do
|
||||
{rec, []} -> if Enum.all?(rec, &(&1 in [??, ?.])) do 1 else 0 end
|
||||
{rec, [block | blocks]} ->
|
||||
# Expect rec to start with any number of ./?s up to the max allowing all remaining groups
|
||||
# i.e. their lengths + an undamaged seperator
|
||||
0..(length(rec) - Enum.sum(blocks) - length(blocks) - block)
|
||||
|> Enum.map(fn i -> repeat('.', i) ++ repeat('#', block) ++ '.' end)
|
||||
|> Enum.filter(pipe(Enum.zip_with(rec, &(&1 == &2 || &2 == ??)) |> Enum.all?))
|
||||
|> Enum.map(&(recur.(recur, {Enum.drop(rec, length(&1)), blocks})))
|
||||
|> Enum.sum
|
||||
end
|
||||
end
|
||||
cache = Cache.start()
|
||||
memoized = fn recur, arg -> Cache.memoize(cache, arg, fn arg -> loop.(recur, arg) end) end
|
||||
memoized.(memoized, {rec, blocks})
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
input
|
||||
|> Enum.map(pipe(possibilities()))
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
input
|
||||
|> Enum.map(fn {rec, blocks} -> {
|
||||
[rec] |> repeat(5) |> Enum.intersperse('?') |> Enum.flat_map(&id/1),
|
||||
repeat(blocks, 5)
|
||||
} end)
|
||||
|> Enum.map(&possibilities/1)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
46
lib/day13.ex
Normal file
46
lib/day13.ex
Normal file
@@ -0,0 +1,46 @@
|
||||
defmodule Aoc2023.Day13 do
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> String.split("\n\n")
|
||||
|> Enum.map(pipe(lines |> Enum.map(&String.to_charlist/1)))
|
||||
end
|
||||
|
||||
defp reflected_row(block, smudges) do
|
||||
0..(length(block) - 2)
|
||||
|> Enum.filter(fn i ->
|
||||
Enum.zip_with(
|
||||
Enum.take(block, i + 1) |> Enum.reverse() |> Enum.concat(),
|
||||
Enum.drop(block, i + 1) |> Enum.concat(),
|
||||
&Kernel.==/2
|
||||
)
|
||||
|> Enum.count(&(not &1))
|
||||
|> Kernel.==(smudges)
|
||||
end)
|
||||
|> head
|
||||
end
|
||||
|
||||
defp reflected_column(block, smudges) do
|
||||
block |> transpose() |> reflected_row(smudges)
|
||||
end
|
||||
|
||||
defp reflection(block, smudges \\ 0) do
|
||||
row = reflected_row(block, smudges)
|
||||
if row != nil, do: {:h, row + 1}, else: {:v, reflected_column(block, smudges) + 1}
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
reflections = input |> Enum.map(&reflection/1)
|
||||
|
||||
(Keyword.get_values(reflections, :h) |> Enum.sum()) * 100 +
|
||||
(Keyword.get_values(reflections, :v) |> Enum.sum())
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
reflections = input |> Enum.map(pipe(reflection(1)))
|
||||
|
||||
(Keyword.get_values(reflections, :h) |> Enum.sum()) * 100 +
|
||||
(Keyword.get_values(reflections, :v) |> Enum.sum())
|
||||
end
|
||||
end
|
||||
77
lib/day14.ex
Normal file
77
lib/day14.ex
Normal file
@@ -0,0 +1,77 @@
|
||||
defmodule Aoc2023.Day14 do
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(&String.to_charlist/1)
|
||||
end
|
||||
|
||||
defp replace_many_at(lst, idxs, val) do
|
||||
idxs |> Enum.reduce(lst, &List.replace_at(&2, &1, val))
|
||||
end
|
||||
|
||||
defp slide(grid) do
|
||||
iter = fn recur, grid ->
|
||||
case grid do
|
||||
[last | [next | rest]] ->
|
||||
idxs =
|
||||
last
|
||||
|> Enum.with_index()
|
||||
|> Enum.filter(pipe(elem(0) |> Kernel.==(?O)))
|
||||
|> Enum.map(pipe(elem(1)))
|
||||
|> Enum.filter(&(Enum.at(next, &1) == ?.))
|
||||
|
||||
[
|
||||
last |> replace_many_at(idxs, ?.)
|
||||
| recur.(recur, [next |> replace_many_at(idxs, ?O) | rest])
|
||||
]
|
||||
|
||||
[last] ->
|
||||
[last]
|
||||
end
|
||||
end
|
||||
|
||||
loop = fn recur, grid ->
|
||||
grid_ = iter.(iter, grid)
|
||||
if grid_ == grid, do: grid, else: recur.(recur, grid_)
|
||||
end
|
||||
|
||||
loop.(loop, grid |> Enum.reverse())
|
||||
end
|
||||
|
||||
defp cycle(grid) do
|
||||
for _ <- 1..4, reduce: grid do
|
||||
# reverse |> transpose is rotation clockwise, but slide already reverses
|
||||
grid -> grid |> slide |> transpose
|
||||
end
|
||||
end
|
||||
|
||||
defp cycles(grid, n \\ 1_000_000_000, {cache_to_n, cache_from_n} \\ {%{}, %{}}) when n > 0 do
|
||||
rep_n = Map.get(cache_to_n, grid)
|
||||
if rep_n do
|
||||
n_ = rep_n - Integer.mod(n, rep_n - n)
|
||||
cache_from_n |> Map.get(n_)
|
||||
else
|
||||
grid_ = cycle(grid)
|
||||
cycles(grid_, n - 1, {Map.put(cache_to_n, grid, n), Map.put(cache_from_n, n, grid)})
|
||||
end
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
input
|
||||
|> slide
|
||||
|> Enum.with_index(1)
|
||||
|> Enum.map(fn {row, i} -> Enum.count(row, &(&1 == ?O)) * i end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
input
|
||||
|> cycles()
|
||||
|> Enum.reverse
|
||||
|> Enum.with_index(1)
|
||||
|> Enum.map(fn {row, i} -> Enum.count(row, &(&1 == ?O)) * i end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
32
lib/day15.ex
Normal file
32
lib/day15.ex
Normal file
@@ -0,0 +1,32 @@
|
||||
defmodule Aoc2023.Day15 do
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
input |> String.split(",")
|
||||
end
|
||||
|
||||
defp hash(str) do
|
||||
for <<char <- str>>, reduce: 0 do
|
||||
acc -> Bitwise.band((acc + char) * 17, 255)
|
||||
end
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
input |> Enum.map(&hash/1) |> Enum.sum
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
for instr <- input, reduce: 0..255 |> Enum.map(&{&1, []}) |> Enum.into(%{}) do
|
||||
boxes ->
|
||||
[_, label, op, lens] = Regex.run(~r/([a-z]+)([-=])(\d*)/, instr)
|
||||
box = hash(label)
|
||||
label = String.to_atom(label)
|
||||
case op do
|
||||
"=" -> boxes |> Map.update!(box, &Keyword.update(&1, label, String.to_integer(lens), fn _ -> String.to_integer(lens) end))
|
||||
"-" -> boxes |> Map.update!(box, &Keyword.delete(&1, label))
|
||||
end
|
||||
end
|
||||
|> Enum.flat_map(fn {box, lenses} -> lenses |> Enum.with_index(1) |> Enum.map(fn {{_, focus}, i} -> focus * (box + 1) * i end) end)
|
||||
|> Enum.sum
|
||||
end
|
||||
end
|
||||
67
lib/day16.ex
Normal file
67
lib/day16.ex
Normal file
@@ -0,0 +1,67 @@
|
||||
defmodule Aoc2023.Day16 do
|
||||
use Aoc2023
|
||||
|
||||
defp emissions(char, dir) do
|
||||
case {char, dir} do
|
||||
{?., dir} -> [dir]
|
||||
{?-, {0, dir}} -> [{0, dir}]
|
||||
{?-, {_, 0}} -> [{0, -1}, {0, 1}]
|
||||
{?|, {dir, 0}} -> [{dir, 0}]
|
||||
{?|, {0, _}} -> [{-1, 0}, {1, 0}]
|
||||
{?/, {dir, 0}} -> [{0, -dir}]
|
||||
{?/, {0, dir}} -> [{-dir, 0}]
|
||||
{?\\, {dir, 0}} -> [{0, dir}]
|
||||
{?\\, {0, dir}} -> [{dir, 0}]
|
||||
end
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(&String.to_charlist/1)
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {row, y} ->
|
||||
row |> Enum.with_index() |> Enum.map(fn {c, x} -> {{y, x}, c} end)
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
end
|
||||
|
||||
defp run(input, heads) do
|
||||
loop = fn recur, energized, heads ->
|
||||
energized_ = MapSet.union(energized, heads |> MapSet.new())
|
||||
|
||||
heads_ =
|
||||
heads
|
||||
|> Enum.flat_map(fn {coord, dir} ->
|
||||
char = Map.get(input, coord)
|
||||
|
||||
if char,
|
||||
do:
|
||||
emissions(char, dir)
|
||||
|> Enum.map(&{add_vec(coord, &1), &1})
|
||||
|> Enum.reject(&MapSet.member?(energized_, &1))
|
||||
|> Enum.filter(&Map.has_key?(input, elem(&1, 0))),
|
||||
else: []
|
||||
end)
|
||||
|
||||
if length(heads_) > 0, do: recur.(recur, energized_, heads_), else: energized_
|
||||
end
|
||||
|
||||
loop.(loop, MapSet.new(), heads) |> Enum.map(pipe(elem(0))) |> MapSet.new() |> MapSet.size()
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
run(input, [{{0, 0}, {0, 1}}])
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
{my, mx} = input |> Enum.map(pipe(elem(0))) |> Enum.max()
|
||||
|
||||
[
|
||||
0..my |> Enum.map(&{{&1, 0}, {0, 1}}),
|
||||
0..my |> Enum.map(&{{&1, mx}, {0, -1}}),
|
||||
0..mx |> Enum.map(&{{0, &1}, {1, 0}}),
|
||||
0..mx |> Enum.map(&{{my, &1}, {-1, 0}})
|
||||
] |> Enum.concat |> Enum.map(&run(input, [&1])) |> Enum.max
|
||||
end
|
||||
end
|
||||
167
lib/day17.ex
Normal file
167
lib/day17.ex
Normal file
@@ -0,0 +1,167 @@
|
||||
defmodule Aoc2023.Day17 do
|
||||
use Aoc2023
|
||||
|
||||
defmodule PriorityQueue do
|
||||
defstruct [:set]
|
||||
def new(contents \\ []), do: %__MODULE__{set: :gb_sets.from_list(contents)}
|
||||
|
||||
def add(%__MODULE__{set: set}, elem, prio) do
|
||||
%__MODULE__{set: :gb_sets.add({prio, elem}, set)}
|
||||
end
|
||||
|
||||
def size(%__MODULE__{set: set}) do
|
||||
:gb_sets.size(set)
|
||||
end
|
||||
|
||||
def pop_min(%__MODULE__{set: set}) do
|
||||
case :gb_sets.size(set) do
|
||||
0 ->
|
||||
{nil, new()}
|
||||
|
||||
_ ->
|
||||
{res, set} = :gb_sets.take_smallest(set)
|
||||
{res, %__MODULE__{set: set}}
|
||||
end
|
||||
end
|
||||
|
||||
defimpl Inspect do
|
||||
import Inspect.Algebra
|
||||
|
||||
def inspect(%PriorityQueue{set: set}, opts) do
|
||||
concat(["#PriorityQueue.new(", to_doc(:gb_sets.to_list(set), opts), ")"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
lines = input |> lines
|
||||
|
||||
{
|
||||
{lines |> length() |> Kernel.-(1), lines |> head |> String.length() |> Kernel.-(1)},
|
||||
lines
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {row, y} ->
|
||||
row
|
||||
|> String.to_charlist()
|
||||
|> Enum.with_index()
|
||||
|> Enum.map(fn {cost, x} -> {{y, x}, String.to_integer(<<cost>>)} end)
|
||||
end)
|
||||
|> Enum.into(%{})
|
||||
}
|
||||
end
|
||||
|
||||
defp a_star(starts, neighbors, heuristic, is_goal) do
|
||||
loop = fn recur, explored, frontier ->
|
||||
{explored, frontier}
|
||||
{{_, current}, frontier} = PriorityQueue.pop_min(frontier)
|
||||
|
||||
if is_goal.(current) do
|
||||
{explored, current}
|
||||
else
|
||||
cost_to_here = Map.get(explored, current) |> elem(1)
|
||||
|
||||
{explored, frontier} =
|
||||
for {neighbor, cost} <- neighbors.(current), reduce: {explored, frontier} do
|
||||
{explored, frontier} ->
|
||||
cost_ = cost_to_here + cost
|
||||
|
||||
if Map.get(explored, neighbor, {nil, cost_}) |> elem(1) < cost_ do
|
||||
{explored, frontier}
|
||||
else
|
||||
{
|
||||
Map.put(explored, neighbor, {current, cost_}),
|
||||
PriorityQueue.add(frontier, neighbor, cost_ + heuristic.(neighbor))
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
recur.(recur, explored, frontier)
|
||||
end
|
||||
end
|
||||
|
||||
{explored, goal} =
|
||||
loop.(
|
||||
loop,
|
||||
starts |> Enum.map(&{&1, {nil, 0}}) |> Enum.into(%{}),
|
||||
starts |> Enum.map(&{0, &1}) |> PriorityQueue.new()
|
||||
)
|
||||
|
||||
# This doesn't include the starting point
|
||||
path_find = fn recur, point, path ->
|
||||
case Map.get(explored, point) do
|
||||
nil -> path
|
||||
{nil, _} -> path
|
||||
{prev, _} -> recur.(recur, prev, [point | path])
|
||||
end
|
||||
end
|
||||
|
||||
path_find.(path_find, goal, [])
|
||||
end
|
||||
|
||||
def part1({{my, mx}, grid}) do
|
||||
# Nodes are y, x, dir, straight length
|
||||
a_star(
|
||||
[{0, 0, :d, 0}, {0, 0, :r, 0}],
|
||||
fn {y, x, dir, len} ->
|
||||
case dir do
|
||||
:u ->
|
||||
[{y, x - 1, :l, 0}, {y, x + 1, :r, 0}] ++
|
||||
if len < 2, do: [{y + 1, x, dir, len + 1}], else: []
|
||||
|
||||
:d ->
|
||||
[{y, x - 1, :l, 0}, {y, x + 1, :r, 0}] ++
|
||||
if len < 2, do: [{y - 1, x, dir, len + 1}], else: []
|
||||
|
||||
:l ->
|
||||
[{y + 1, x, :u, 0}, {y - 1, x, :d, 0}] ++
|
||||
if len < 2, do: [{y, x - 1, dir, len + 1}], else: []
|
||||
|
||||
:r ->
|
||||
[{y + 1, x, :u, 0}, {y - 1, x, :d, 0}] ++
|
||||
if len < 2, do: [{y, x + 1, dir, len + 1}], else: []
|
||||
end
|
||||
|> Enum.filter(fn {y, x, _, _} -> y in 0..my and x in 0..mx end)
|
||||
|> Enum.map(fn {y, x, _, _} = pos -> {pos, Map.get(grid, {y, x})} end)
|
||||
end,
|
||||
fn {y, x, _, _} -> abs(y - my) + abs(x - mx) end,
|
||||
fn {y, x, _, _} -> {y, x} == {my, mx} end
|
||||
)
|
||||
|> Enum.map(fn {y, x, _, _} -> Map.get(grid, {y, x}) end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part2({{my, mx}, grid}) do
|
||||
# Nodes are y, x, dir, straight length
|
||||
a_star(
|
||||
[{0, 0, :r, 0}, {0, 0, :d, 0}, {0, 0, :u, 0}, {0, 0, :l, 0}],
|
||||
fn {y, x, dir, len} ->
|
||||
(if(len < 9,
|
||||
do:
|
||||
case dir do
|
||||
:u -> [{y + 1, x, :u, len + 1}]
|
||||
:d -> [{y - 1, x, :d, len + 1}]
|
||||
:l -> [{y, x - 1, :l, len + 1}]
|
||||
:r -> [{y, x + 1, :r, len + 1}]
|
||||
end,
|
||||
else: []
|
||||
) ++
|
||||
if(len > 2,
|
||||
do:
|
||||
case dir do
|
||||
:u -> [{y, x - 1, :l, 0}, {y, x + 1, :r, 0}]
|
||||
:d -> [{y, x - 1, :l, 0}, {y, x + 1, :r, 0}]
|
||||
:l -> [{y + 1, x, :u, 0}, {y - 1, x, :d, 0}]
|
||||
:r -> [{y + 1, x, :u, 0}, {y - 1, x, :d, 0}]
|
||||
end,
|
||||
else: []
|
||||
))
|
||||
|> Enum.filter(fn {y, x, _, _} -> y in 0..my and x in 0..mx end)
|
||||
|> Enum.map(fn {y, x, _, _} = pos -> {pos, Map.get(grid, {y, x})} end)
|
||||
end,
|
||||
fn {y, x, _, _} -> abs(y - my) + abs(x - mx) end,
|
||||
fn {y, x, _, len} -> {y, x} == {my, mx} and len > 2 end
|
||||
)
|
||||
|> Enum.map(fn {y, x, _, _} -> Map.get(grid, {y, x}) end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
67
lib/day18.ex
Normal file
67
lib/day18.ex
Normal file
@@ -0,0 +1,67 @@
|
||||
defmodule Aoc2023.Day18 do
|
||||
require Integer
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(fn line ->
|
||||
[dir, n, color] =
|
||||
Regex.run(~r/^([RDLU]) (\d+) \(#([0-9a-f]{6})\)$/, line, capture: :all_but_first)
|
||||
|
||||
{
|
||||
dir |> String.to_charlist() |> head,
|
||||
n |> String.to_integer(),
|
||||
color
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp simulate({pos, dist, points}, {dir, n}) do
|
||||
p =
|
||||
case dir do
|
||||
:u -> {-n, 0}
|
||||
:d -> {n, 0}
|
||||
:r -> {0, n}
|
||||
:l -> {0, -n}
|
||||
end
|
||||
|> add_vec(pos)
|
||||
|
||||
{p, dist + n, [p | points]}
|
||||
end
|
||||
|
||||
defp area(perim, points),
|
||||
# Shoelace formula
|
||||
do:
|
||||
Stream.zip(points, points |> Stream.cycle() |> Stream.drop(1))
|
||||
|> Stream.map(fn {{y, x}, {y1, x1}} -> x * y1 - x1 * y end)
|
||||
|> Enum.sum()
|
||||
|> abs
|
||||
|> then(&((&1 + perim) / 2))
|
||||
|> trunc
|
||||
|
||||
defp run(instrs) do
|
||||
{_, dist, points} = instrs |> Enum.reduce({{0, 0}, 2, [{0, 0}]}, &simulate(&2, &1))
|
||||
area(dist, points)
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
run(for {dir, n, _} <- input, do: {case dir do
|
||||
?U -> :u
|
||||
?D -> :d
|
||||
?L -> :l
|
||||
?R -> :r
|
||||
end, n})
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
run(for {_, _, <<len::binary-size(5), dir::integer>>} <- input do
|
||||
{case dir do
|
||||
?0 -> :r
|
||||
?1 -> :d
|
||||
?2 -> :l
|
||||
?3 -> :u
|
||||
end, String.to_integer(len, 16)}
|
||||
end)
|
||||
end
|
||||
end
|
||||
110
lib/day3.ex
Normal file
110
lib/day3.ex
Normal file
@@ -0,0 +1,110 @@
|
||||
defmodule Aoc2023.Day3 do
|
||||
use Aoc2023
|
||||
|
||||
@symbols [
|
||||
?$,
|
||||
?%,
|
||||
?&,
|
||||
?*,
|
||||
?+,
|
||||
?-,
|
||||
?/,
|
||||
?=,
|
||||
?@,
|
||||
?#
|
||||
]
|
||||
|
||||
defp adjacents({y, x, len}, grid) do
|
||||
[
|
||||
{y, x - 1},
|
||||
{y, x + len}
|
||||
| for(y <- [y - 1, y + 1], x <- (x - 1)..(x + len), do: {y, x})
|
||||
]
|
||||
|> Enum.filter(fn {y, x} ->
|
||||
0 <= y and y < length(grid) and 0 <= x and x < length(Enum.at(grid, y))
|
||||
end)
|
||||
end
|
||||
|
||||
defp adjacents({y, x}, grid), do: adjacents({y, x, 1}, grid)
|
||||
|
||||
defp get({y, x}, grid) do
|
||||
grid |> Enum.at(y) |> Enum.at(x)
|
||||
end
|
||||
|
||||
defp get({y, x, len}, grid) do
|
||||
x..(x + len - 1) |> Enum.map(&get({y, &1}, grid))
|
||||
end
|
||||
|
||||
defp contains({y, x}, numbers) do
|
||||
numbers
|
||||
|> Enum.filter(fn {ny, nx, nlen} -> ny == y and nx <= x and x < nx + nlen end)
|
||||
end
|
||||
|
||||
defp number(num, grid) do
|
||||
num
|
||||
|> get(grid)
|
||||
|> Enum.map(&(&1 - ?0))
|
||||
|> Integer.undigits()
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
grid =
|
||||
input
|
||||
|> String.split("\n")
|
||||
|> Enum.map(&String.to_charlist/1)
|
||||
|
||||
{
|
||||
grid,
|
||||
grid
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {row, y} ->
|
||||
row
|
||||
|> runs(&(?0 <= &1 && &1 <= ?9))
|
||||
|> Enum.map(fn {x, len} -> {y, x, len} end)
|
||||
end)
|
||||
}
|
||||
end
|
||||
|
||||
def part1({grid, numbers}) do
|
||||
numbers
|
||||
|> Enum.map(id &&& adjacents(grid))
|
||||
|> Enum.filter(
|
||||
pipe(
|
||||
elem(1)
|
||||
|> Enum.any?(&(get(&1, grid) in @symbols))
|
||||
)
|
||||
)
|
||||
|> Enum.map(
|
||||
pipe(
|
||||
elem(0)
|
||||
|> number(grid)
|
||||
)
|
||||
)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part2({grid, numbers}) do
|
||||
grid
|
||||
|> Enum.with_index()
|
||||
|> Enum.flat_map(fn {row, y} ->
|
||||
row
|
||||
|> Enum.with_index()
|
||||
|> Enum.filter(&(elem(&1, 0) == ?*))
|
||||
|> Enum.map(&{y, elem(&1, 1)})
|
||||
|> Enum.map(id &&& adjacents(grid))
|
||||
|> Enum.map(pipe(
|
||||
elem(1)
|
||||
|> Enum.flat_map(pipe(contains(numbers)))
|
||||
|> Enum.uniq()
|
||||
))
|
||||
|> Enum.filter(pipe(
|
||||
length()
|
||||
|> then(&(&1 == 2)))
|
||||
)
|
||||
|> Enum.map(pipe(
|
||||
Enum.map(pipe(number(grid))) |> Enum.product
|
||||
))
|
||||
end)
|
||||
|> Enum.sum
|
||||
end
|
||||
end
|
||||
39
lib/day4.ex
Normal file
39
lib/day4.ex
Normal file
@@ -0,0 +1,39 @@
|
||||
defmodule Aoc2023.Day4 do
|
||||
use Aoc2023
|
||||
|
||||
defp numbers(values) do
|
||||
values |> String.split() |> Enum.map(&String.to_integer/1) |> MapSet.new()
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(
|
||||
&Regex.run(~r/Card\s+(?<id>\d+): (?<winning>(\s*\d+)+) \| (?<values>(\s*\d+)+)/, &1,
|
||||
capture: ["id", "winning", "values"]
|
||||
)
|
||||
)
|
||||
|> Enum.map(fn [id, winning, values] ->
|
||||
{String.to_integer(id),
|
||||
MapSet.intersection(numbers(winning), numbers(values)) |> MapSet.size()}
|
||||
end)
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
for {_, count} <- input,
|
||||
count > 0 do
|
||||
2 ** (count - 1)
|
||||
end
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
for {id, count} <- input,
|
||||
id_ <- (id + 1)..(id + count)//1,
|
||||
reduce: input |> Enum.map(elem(0) &&& const(1)) |> Enum.into(%{}) do
|
||||
acc -> Map.update!(acc, id_, &(&1 + Map.get(acc, id)))
|
||||
end
|
||||
|> Enum.map(pipe(elem(1)))
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
84
lib/day5.ex
Normal file
84
lib/day5.ex
Normal file
@@ -0,0 +1,84 @@
|
||||
defmodule Aoc2023.Day5 do
|
||||
use Aoc2023
|
||||
|
||||
defp numbers(str), do: str |> String.split() |> Enum.map(&String.to_integer/1)
|
||||
|
||||
def parse(input) do
|
||||
[seeds | maps] =
|
||||
input
|
||||
|> String.split("\n\n")
|
||||
|
||||
{
|
||||
seeds |> String.split(": ") |> Enum.at(1) |> numbers,
|
||||
maps
|
||||
|> Enum.map(pipe(
|
||||
String.split("\n")
|
||||
|> tail
|
||||
|> Enum.map(pipe(
|
||||
numbers
|
||||
|> List.to_tuple()
|
||||
|> then(fn {dst, src, len} -> {src .. (src + len - 1), dst - src} end)
|
||||
))
|
||||
))
|
||||
}
|
||||
end
|
||||
|
||||
defp split_range_on(r1, r2) do
|
||||
cond do
|
||||
Range.disjoint?(r1, r2) -> {[r1], []}
|
||||
r1.first < r2.first && r1.last < r2.last ->
|
||||
{a, b} = Range.split(r1, r2.first - r1.first)
|
||||
{[a], [b]}
|
||||
r1.first > r2.first && r1.last > r2.last ->
|
||||
{a, b} = Range.split(r1, r1.first - r2.first)
|
||||
{[b], [a]}
|
||||
r1.first >= r2.first && r1.last <= r2.last ->
|
||||
{[], [r1]}
|
||||
r1.first <= r2.first && r1.last >= r2.last ->
|
||||
{pre, rest} = Range.split(r1, r2.first - r1.first)
|
||||
{mid, last} = Range.split(rest, r2.last - rest.first)
|
||||
{[pre, last], [mid]}
|
||||
end
|
||||
end
|
||||
|
||||
defp map(loc, map) do
|
||||
{unmapped, mapped} = for {src, offset} <- map,
|
||||
reduce: {[loc], []} do
|
||||
{unmapped, mapped} ->
|
||||
for range <- unmapped,
|
||||
reduce: {[], mapped} do
|
||||
{unmapped_, mapped_} ->
|
||||
{unmapped, mapped} = split_range_on(range, src)
|
||||
{
|
||||
unmapped_ ++ unmapped,
|
||||
mapped_ ++ Enum.map(mapped, &(Range.shift(&1, offset)))
|
||||
}
|
||||
end
|
||||
end
|
||||
unmapped ++ mapped
|
||||
end
|
||||
|
||||
defp run(seeds, maps) do
|
||||
for seed <- seeds do
|
||||
for map <- maps, reduce: [seed] do
|
||||
loc ->
|
||||
loc
|
||||
|> Enum.flat_map(pipe(map(map)))
|
||||
end
|
||||
end
|
||||
|> Enum.flat_map(&id/1)
|
||||
|> Enum.min_by(&(&1.first))
|
||||
|> then(&(&1.first))
|
||||
end
|
||||
|
||||
def part1({seeds, maps}) do
|
||||
run(seeds |> Enum.map(&(&1..&1)), maps)
|
||||
end
|
||||
|
||||
def part2({seeds, maps}) do
|
||||
run(
|
||||
seeds |> Enum.chunk_every(2) |> Enum.map(fn [s, len] -> s..(s + len - 1) end),
|
||||
maps
|
||||
)
|
||||
end
|
||||
end
|
||||
37
lib/day6.ex
Normal file
37
lib/day6.ex
Normal file
@@ -0,0 +1,37 @@
|
||||
defmodule Aoc2023.Day6 do
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(pipe(
|
||||
String.split(":")
|
||||
|> Enum.at(1)
|
||||
))
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
input
|
||||
|> Enum.map(pipe(
|
||||
String.split()
|
||||
|> Enum.map(&String.to_integer/1)
|
||||
))
|
||||
|> Enum.zip()
|
||||
|> Enum.map(fn {time, dist} ->
|
||||
1..time
|
||||
|> Enum.map(&(&1 * (time - &1)))
|
||||
|> Enum.filter(&(&1 > dist))
|
||||
|> length
|
||||
end)
|
||||
|> Enum.product()
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
[time, dist] = input
|
||||
|> Enum.map(pipe(String.replace(~r(\s+), "") |> String.to_integer()))
|
||||
1..(time)
|
||||
|> Stream.map(&(&1 * (time - &1)))
|
||||
|> Stream.filter(&(&1 > dist))
|
||||
|> Enum.count
|
||||
end
|
||||
end
|
||||
66
lib/day7.ex
Normal file
66
lib/day7.ex
Normal file
@@ -0,0 +1,66 @@
|
||||
defmodule Aoc2023.Day7 do
|
||||
use Aoc2023
|
||||
|
||||
def hand_type(values) do
|
||||
values
|
||||
|> Enum.frequencies()
|
||||
|> then(fn freq ->
|
||||
{jokers, freq_} = freq |> Map.pop(0, 0)
|
||||
common = freq_ |> Enum.max_by(pipe(elem(1)), fn -> {1, nil} end) |> elem(0)
|
||||
freq_ |> Map.update(common, jokers, &(&1 + jokers))
|
||||
end)
|
||||
|> Enum.map(pipe(elem(1)))
|
||||
|> Enum.sort(:desc)
|
||||
|> case do
|
||||
[5] -> 6
|
||||
[4, 1] -> 5
|
||||
[3, 2] -> 4
|
||||
[3, 1, 1] -> 3
|
||||
[2, 2, 1] -> 2
|
||||
[2, 1, 1, 1] -> 1
|
||||
[1, 1, 1, 1, 1] -> 0
|
||||
end
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
fn rankings ->
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(&String.split/1)
|
||||
|> Enum.map(fn [hand, bid] ->
|
||||
{
|
||||
hand |> String.to_charlist() |> Enum.map(&Map.get(rankings, &1)),
|
||||
bid |> String.to_integer()
|
||||
}
|
||||
end)
|
||||
|> Enum.sort_by(elem(0) |> hand_type &&& elem(0), :asc)
|
||||
|> Enum.with_index(1)
|
||||
|> Enum.map(fn {{_, bid}, index} -> bid * index end)
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
|
||||
@ranking [
|
||||
?2,
|
||||
?3,
|
||||
?4,
|
||||
?5,
|
||||
?6,
|
||||
?7,
|
||||
?8,
|
||||
?9,
|
||||
?T,
|
||||
?J,
|
||||
?Q,
|
||||
?K,
|
||||
?A,
|
||||
] |> Enum.with_index(1) |> Map.new
|
||||
|
||||
def part1(input) do
|
||||
input.(@ranking)
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
input.(@ranking |> Map.put(?J, 0))
|
||||
end
|
||||
end
|
||||
39
lib/day8.ex
Normal file
39
lib/day8.ex
Normal file
@@ -0,0 +1,39 @@
|
||||
defmodule Aoc2023.Day8 do
|
||||
require Integer
|
||||
use Aoc2023
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> String.split("\n\n")
|
||||
|> then(fn [directions, map] ->
|
||||
{
|
||||
directions |> String.to_charlist() |> Enum.map(&%{?L => 0, ?R => 1}[&1]),
|
||||
map
|
||||
|> lines
|
||||
|> Enum.map(&Regex.run(~r/(\w+) = \((\w+), (\w+)\)/, &1, capture: :all_but_first))
|
||||
|> Enum.map(fn [src, dst1, dst2] -> {src, {dst1, dst2}} end)
|
||||
|> Enum.into(%{})
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
defp run({directions, map}, node, filter) do
|
||||
directions
|
||||
|> Stream.cycle()
|
||||
|> Stream.scan(node, fn dir, pos -> map[pos] |> elem(dir) end)
|
||||
|> Enum.find_index(filter)
|
||||
|> Kernel.+(1)
|
||||
end
|
||||
|
||||
def part1({directions, map}) do
|
||||
if map["AAA"], do: run({directions, map}, "AAA", &(&1 == "ZZZ"))
|
||||
end
|
||||
|
||||
def part2({directions, map}) do
|
||||
map
|
||||
|> Enum.map(pipe(elem(0)))
|
||||
|> Enum.filter(pipe(String.ends_with?("A")))
|
||||
|> Enum.map(&run({directions, map}, &1, pipe(String.ends_with?("Z"))))
|
||||
|> lcm
|
||||
end
|
||||
end
|
||||
28
lib/day9.ex
Normal file
28
lib/day9.ex
Normal file
@@ -0,0 +1,28 @@
|
||||
defmodule Aoc2023.Day9 do
|
||||
use Aoc2023
|
||||
|
||||
defp prediction(lst) do
|
||||
case lst |> Enum.uniq() do
|
||||
[val] -> val
|
||||
_ -> List.last(lst) + prediction(Enum.zip_with(lst, Enum.drop(lst, 1), &(&2 - &1)))
|
||||
end
|
||||
end
|
||||
|
||||
def parse(input) do
|
||||
input
|
||||
|> lines
|
||||
|> Enum.map(pipe(String.split() |> Enum.map(&String.to_integer/1)))
|
||||
end
|
||||
|
||||
def part1(input) do
|
||||
input
|
||||
|> Enum.map(&prediction/1)
|
||||
|> Enum.sum()
|
||||
end
|
||||
|
||||
def part2(input) do
|
||||
input
|
||||
|> Enum.map(pipe(Enum.reverse() |> prediction))
|
||||
|> Enum.sum()
|
||||
end
|
||||
end
|
||||
138
lib/mix_tasks.ex
138
lib/mix_tasks.ex
@@ -4,6 +4,22 @@ defmodule Mix.Tasks.Aoc do
|
||||
|
||||
defp module(1), do: Aoc2023.Day1
|
||||
defp module(2), do: Aoc2023.Day2
|
||||
defp module(3), do: Aoc2023.Day3
|
||||
defp module(4), do: Aoc2023.Day4
|
||||
defp module(5), do: Aoc2023.Day5
|
||||
defp module(6), do: Aoc2023.Day6
|
||||
defp module(7), do: Aoc2023.Day7
|
||||
defp module(8), do: Aoc2023.Day8
|
||||
defp module(9), do: Aoc2023.Day9
|
||||
defp module(10), do: Aoc2023.Day10
|
||||
defp module(11), do: Aoc2023.Day11
|
||||
defp module(12), do: Aoc2023.Day12
|
||||
defp module(13), do: Aoc2023.Day13
|
||||
defp module(14), do: Aoc2023.Day14
|
||||
defp module(15), do: Aoc2023.Day15
|
||||
defp module(16), do: Aoc2023.Day16
|
||||
defp module(17), do: Aoc2023.Day17
|
||||
defp module(18), do: Aoc2023.Day18
|
||||
# [MODULE INSERTION POINT]
|
||||
|
||||
defp base_dir(), do: System.get_env("AOC_BASE")
|
||||
@@ -11,7 +27,7 @@ defmodule Mix.Tasks.Aoc do
|
||||
defp tests(day) do
|
||||
case File.ls(tests_dir(day)) do
|
||||
{:ok, paths} ->
|
||||
paths |> Enum.filter(&(not String.contains?(&1, ".")))
|
||||
paths |> Enum.filter(&(not String.contains?(&1, "."))) |> Enum.sort()
|
||||
|
||||
{:error, e} ->
|
||||
dbg(e)
|
||||
@@ -96,10 +112,40 @@ defmodule Mix.Tasks.Aoc do
|
||||
create_file("#{tests_dir(day)}#{last + 1}", IO.read(:stdio, :eof))
|
||||
end
|
||||
|
||||
defp run(day, ["test", "expected", test, part, value]) do
|
||||
create_file("#{tests_dir(day)}#{test}.#{part}", value)
|
||||
end
|
||||
|
||||
defp run(day, ["test", "expected", test, part]) do
|
||||
create_file("#{tests_dir(day)}#{test}.#{part}", IO.read(:stdio, :eof))
|
||||
end
|
||||
|
||||
defp run(day, ["test", "watch"]) do
|
||||
{:ok, pid} = Mix.Tasks.Aoc.Watcher.start_link({[dirs: ["lib/", "tests/day#{day}/"]], self()})
|
||||
Process.monitor(pid)
|
||||
|
||||
loop = fn loop ->
|
||||
IO.puts(IO.ANSI.clear() <> IO.ANSI.cursor(0, 0))
|
||||
IO.puts("At #{DateTime.utc_now(:second)}:")
|
||||
System.shell("mix compile")
|
||||
:code.purge(module(day))
|
||||
:code.purge(Aoc2023.Common)
|
||||
:code.load_file(module(day))
|
||||
:code.load_file(Aoc2023.Common)
|
||||
|
||||
spawn(fn ->
|
||||
run(day, ["test"])
|
||||
end)
|
||||
|
||||
receive do
|
||||
:update -> loop.(loop)
|
||||
{:DOWN, _, :process, ^pid, _} -> nil
|
||||
end
|
||||
end
|
||||
|
||||
loop.(loop)
|
||||
end
|
||||
|
||||
defp run(day, ["test"]) do
|
||||
mod = module(day)
|
||||
tests = tests(day)
|
||||
@@ -108,33 +154,27 @@ defmodule Mix.Tasks.Aoc do
|
||||
|> Enum.map(&test(day, &1))
|
||||
|> Enum.map(fn {test, input, p1e, p2e} ->
|
||||
parsed = mod.parse(input)
|
||||
p1 = mod.part1(parsed)
|
||||
|
||||
if p1e do
|
||||
if stringify(p1) != p1e do
|
||||
IO.puts("Failed at #{test}.1: expected #{p1e}, got:")
|
||||
dbg(p1)
|
||||
else
|
||||
IO.puts("Test #{test}.1 succeeded")
|
||||
result = fn part, got, expected ->
|
||||
cond do
|
||||
stringify(got) == expected ->
|
||||
IO.puts(IO.ANSI.format([:green, "Test #{test}.#{part} succeeded (#{expected})"]))
|
||||
|
||||
expected ->
|
||||
IO.puts(
|
||||
IO.ANSI.format([
|
||||
:red,
|
||||
"Test #{test}.#{part} failed: expected #{expected}, got #{stringify(got)}"
|
||||
])
|
||||
)
|
||||
|
||||
true ->
|
||||
IO.puts("Test #{test}.#{part}: #{stringify(got)}")
|
||||
end
|
||||
else
|
||||
IO.puts("Test #{test}.1")
|
||||
dbg(p1)
|
||||
end
|
||||
|
||||
p2 = mod.part2(parsed)
|
||||
|
||||
if p2e do
|
||||
if stringify(p2) != p2e do
|
||||
IO.puts("Failed at #{test}.2: expected #{p2e}, got:")
|
||||
dbg(p2)
|
||||
else
|
||||
IO.puts("Test #{test}.2 succeeded")
|
||||
end
|
||||
else
|
||||
IO.puts("Test #{test}.2")
|
||||
dbg(p2)
|
||||
end
|
||||
result.(1, mod.part1(parsed), p1e)
|
||||
result.(2, mod.part2(parsed), p2e)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -143,6 +183,30 @@ defmodule Mix.Tasks.Aoc do
|
||||
run_file(day, "#{base_dir()}/inputs/day#{day}")
|
||||
end
|
||||
|
||||
defp run(day, ["run", "submit", part]) do
|
||||
run(day, ["fetch"])
|
||||
mod = module(day)
|
||||
parsed = mod.parse(read("#{base_dir()}/inputs/day#{day}"))
|
||||
|
||||
val =
|
||||
case part do
|
||||
"1" -> mod.part1(parsed)
|
||||
"2" -> mod.part2(parsed)
|
||||
end
|
||||
|
||||
HTTPoison.start()
|
||||
|
||||
resp =
|
||||
HTTPoison.post!(
|
||||
"https://adventofcode.com/2023/day/#{day}/answer",
|
||||
"level=#{part}&answer=#{stringify(val)}",
|
||||
"user-agent": "aoc-ex by ben@soroos.net",
|
||||
cookie: "session=#{System.get_env("AOC_SESSION")}",
|
||||
"content-type": "application/x-www-form-urlencoded"
|
||||
).body
|
||||
Regex.named_captures(~r[<main>(?<main>.*)</main>]is, resp)["main"] |> IO.puts
|
||||
end
|
||||
|
||||
defp run(day, ["run", "-"]) do
|
||||
run_file(day)
|
||||
end
|
||||
@@ -166,4 +230,30 @@ defmodule Mix.Tasks.Aoc do
|
||||
defp run_file(day, file \\ nil) do
|
||||
module(day).main(if file, do: read(file), else: IO.read(:stdio, :eof))
|
||||
end
|
||||
|
||||
defmodule Watcher do
|
||||
use GenServer
|
||||
|
||||
def start_link(args) do
|
||||
GenServer.start_link(__MODULE__, args)
|
||||
end
|
||||
|
||||
def init({args, callback}) do
|
||||
{:ok, watcher_pid} = FileSystem.start_link(args)
|
||||
FileSystem.subscribe(watcher_pid)
|
||||
{:ok, %{watcher_pid: watcher_pid, callback: callback}}
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
{:file_event, watcher_pid, {_path, _events}},
|
||||
%{watcher_pid: watcher_pid, callback: callback} = state
|
||||
) do
|
||||
send(callback, :update)
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info({:file_event, _watcher_pid, :stop}, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
3
mix.exs
3
mix.exs
@@ -19,7 +19,8 @@ defmodule Aoc2023.MixProject do
|
||||
|
||||
defp deps do
|
||||
[
|
||||
{:httpoison, "~> 2.0"}
|
||||
httpoison: "~> 2.0",
|
||||
file_system: "~> 1.0"
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
1
mix.lock
1
mix.lock
@@ -1,5 +1,6 @@
|
||||
%{
|
||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
|
||||
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
|
||||
"httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
|
||||
5
tests/day10/1
Normal file
5
tests/day10/1
Normal file
@@ -0,0 +1,5 @@
|
||||
-L|F7
|
||||
7S-7|
|
||||
L|7||
|
||||
-L-J|
|
||||
L|-JF
|
||||
1
tests/day10/1.1
Normal file
1
tests/day10/1.1
Normal file
@@ -0,0 +1 @@
|
||||
4
|
||||
5
tests/day10/2
Normal file
5
tests/day10/2
Normal file
@@ -0,0 +1,5 @@
|
||||
..F7.
|
||||
.FJ|.
|
||||
SJ.L7
|
||||
|F--J
|
||||
LJ...
|
||||
1
tests/day10/2.1
Normal file
1
tests/day10/2.1
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
9
tests/day10/3
Normal file
9
tests/day10/3
Normal file
@@ -0,0 +1,9 @@
|
||||
...........
|
||||
.S-------7.
|
||||
.|F-----7|.
|
||||
.||.....||.
|
||||
.||.....||.
|
||||
.|L-7.F-J|.
|
||||
.|..|.|..|.
|
||||
.L--J.L--J.
|
||||
...........
|
||||
1
tests/day10/3.2
Normal file
1
tests/day10/3.2
Normal file
@@ -0,0 +1 @@
|
||||
4
|
||||
10
tests/day10/4
Normal file
10
tests/day10/4
Normal file
@@ -0,0 +1,10 @@
|
||||
.F----7F7F7F7F-7....
|
||||
.|F--7||||||||FJ....
|
||||
.||.FJ||||||||L7....
|
||||
FJL7L7LJLJ||LJ.L-7..
|
||||
L--J.L7...LJS7F-7L7.
|
||||
....F-J..F7FJ|L7L7L7
|
||||
....L7.F7||L7|.L7L7|
|
||||
.....|FJLJ|FJ|F7|.LJ
|
||||
....FJL-7.||.||||...
|
||||
....L---J.LJ.LJLJ...
|
||||
1
tests/day10/4.2
Normal file
1
tests/day10/4.2
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
10
tests/day10/5
Normal file
10
tests/day10/5
Normal file
@@ -0,0 +1,10 @@
|
||||
FF7FSF7F7F7F7F7F---7
|
||||
L|LJ||||||||||||F--J
|
||||
FL-7LJLJ||||||LJL-77
|
||||
F--JF--7||LJLJ7F7FJ-
|
||||
L---JF-JLJ.||-FJLJJ7
|
||||
|F|F-JF---7F7-L7L|7|
|
||||
|FFJF7L7F-JF7|JL---7
|
||||
7-L-JL7||F7|L7F-7F7|
|
||||
L.L7LFJ|||||FJL7||LJ
|
||||
L7JLJL-JLJLJL--JLJ.L
|
||||
1
tests/day10/5.2
Normal file
1
tests/day10/5.2
Normal file
@@ -0,0 +1 @@
|
||||
10
|
||||
10
tests/day11/1
Normal file
10
tests/day11/1
Normal file
@@ -0,0 +1,10 @@
|
||||
...#......
|
||||
.......#..
|
||||
#.........
|
||||
..........
|
||||
......#...
|
||||
.#........
|
||||
.........#
|
||||
..........
|
||||
.......#..
|
||||
#...#.....
|
||||
1
tests/day11/1.1
Normal file
1
tests/day11/1.1
Normal file
@@ -0,0 +1 @@
|
||||
374
|
||||
6
tests/day12/1
Normal file
6
tests/day12/1
Normal file
@@ -0,0 +1,6 @@
|
||||
???.### 1,1,3
|
||||
.??..??...?##. 1,1,3
|
||||
?#?#?#?#?#?#?#? 1,3,1,6
|
||||
????.#...#... 4,1,1
|
||||
????.######..#####. 1,6,5
|
||||
?###???????? 3,2,1
|
||||
1
tests/day12/1.1
Normal file
1
tests/day12/1.1
Normal file
@@ -0,0 +1 @@
|
||||
21
|
||||
1
tests/day12/1.2
Normal file
1
tests/day12/1.2
Normal file
@@ -0,0 +1 @@
|
||||
525152
|
||||
15
tests/day13/1
Normal file
15
tests/day13/1
Normal file
@@ -0,0 +1,15 @@
|
||||
#.##..##.
|
||||
..#.##.#.
|
||||
##......#
|
||||
##......#
|
||||
..#.##.#.
|
||||
..##..##.
|
||||
#.#.##.#.
|
||||
|
||||
#...##..#
|
||||
#....#..#
|
||||
..##..###
|
||||
#####.##.
|
||||
#####.##.
|
||||
..##..###
|
||||
#....#..#
|
||||
1
tests/day13/1.1
Normal file
1
tests/day13/1.1
Normal file
@@ -0,0 +1 @@
|
||||
405
|
||||
1
tests/day13/1.2
Normal file
1
tests/day13/1.2
Normal file
@@ -0,0 +1 @@
|
||||
400
|
||||
10
tests/day14/1
Normal file
10
tests/day14/1
Normal file
@@ -0,0 +1,10 @@
|
||||
O....#....
|
||||
O.OO#....#
|
||||
.....##...
|
||||
OO.#O....O
|
||||
.O.....O#.
|
||||
O.#..O.#.#
|
||||
..O..#O..O
|
||||
.......O..
|
||||
#....###..
|
||||
#OO..#....
|
||||
1
tests/day14/1.1
Normal file
1
tests/day14/1.1
Normal file
@@ -0,0 +1 @@
|
||||
136
|
||||
1
tests/day14/1.2
Normal file
1
tests/day14/1.2
Normal file
@@ -0,0 +1 @@
|
||||
64
|
||||
1
tests/day15/1
Normal file
1
tests/day15/1
Normal file
@@ -0,0 +1 @@
|
||||
rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7
|
||||
1
tests/day15/1.1
Normal file
1
tests/day15/1.1
Normal file
@@ -0,0 +1 @@
|
||||
1320
|
||||
1
tests/day15/1.2
Normal file
1
tests/day15/1.2
Normal file
@@ -0,0 +1 @@
|
||||
145
|
||||
10
tests/day16/1
Normal file
10
tests/day16/1
Normal file
@@ -0,0 +1,10 @@
|
||||
.|...\....
|
||||
|.-.\.....
|
||||
.....|-...
|
||||
........|.
|
||||
..........
|
||||
.........\
|
||||
..../.\\..
|
||||
.-.-/..|..
|
||||
.|....-|.\
|
||||
..//.|....
|
||||
1
tests/day16/1.1
Normal file
1
tests/day16/1.1
Normal file
@@ -0,0 +1 @@
|
||||
46
|
||||
1
tests/day16/1.2
Normal file
1
tests/day16/1.2
Normal file
@@ -0,0 +1 @@
|
||||
51
|
||||
13
tests/day17/1
Normal file
13
tests/day17/1
Normal file
@@ -0,0 +1,13 @@
|
||||
2413432311323
|
||||
3215453535623
|
||||
3255245654254
|
||||
3446585845452
|
||||
4546657867536
|
||||
1438598798454
|
||||
4457876987766
|
||||
3637877979653
|
||||
4654967986887
|
||||
4564679986453
|
||||
1224686865563
|
||||
2546548887735
|
||||
4322674655533
|
||||
1
tests/day17/1.1
Normal file
1
tests/day17/1.1
Normal file
@@ -0,0 +1 @@
|
||||
102
|
||||
1
tests/day17/1.2
Normal file
1
tests/day17/1.2
Normal file
@@ -0,0 +1 @@
|
||||
94
|
||||
5
tests/day17/2
Normal file
5
tests/day17/2
Normal file
@@ -0,0 +1,5 @@
|
||||
111111111111
|
||||
999999999991
|
||||
999999999991
|
||||
999999999991
|
||||
999999999991
|
||||
1
tests/day17/2.2
Normal file
1
tests/day17/2.2
Normal file
@@ -0,0 +1 @@
|
||||
71
|
||||
14
tests/day18/1
Normal file
14
tests/day18/1
Normal file
@@ -0,0 +1,14 @@
|
||||
R 6 (#70c710)
|
||||
D 5 (#0dc571)
|
||||
L 2 (#5713f0)
|
||||
D 2 (#d2c081)
|
||||
R 2 (#59c680)
|
||||
D 2 (#411b91)
|
||||
L 5 (#8ceee2)
|
||||
U 2 (#caa173)
|
||||
L 1 (#1b58a2)
|
||||
U 2 (#caa171)
|
||||
R 2 (#7807d2)
|
||||
U 3 (#a77fa3)
|
||||
L 2 (#015232)
|
||||
U 2 (#7a21e3)
|
||||
1
tests/day18/1.1
Normal file
1
tests/day18/1.1
Normal file
@@ -0,0 +1 @@
|
||||
62
|
||||
1
tests/day18/1.2
Normal file
1
tests/day18/1.2
Normal file
@@ -0,0 +1 @@
|
||||
952408144115
|
||||
10
tests/day3/1
Normal file
10
tests/day3/1
Normal file
@@ -0,0 +1,10 @@
|
||||
467..114..
|
||||
...*......
|
||||
..35..633.
|
||||
......#...
|
||||
617*......
|
||||
.....+.58.
|
||||
..592.....
|
||||
......755.
|
||||
...$.*....
|
||||
.664.598..
|
||||
1
tests/day3/1.1
Normal file
1
tests/day3/1.1
Normal file
@@ -0,0 +1 @@
|
||||
4361
|
||||
1
tests/day3/1.2
Normal file
1
tests/day3/1.2
Normal file
@@ -0,0 +1 @@
|
||||
467835
|
||||
6
tests/day4/1
Normal file
6
tests/day4/1
Normal file
@@ -0,0 +1,6 @@
|
||||
Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
|
||||
1
tests/day4/1.1
Normal file
1
tests/day4/1.1
Normal file
@@ -0,0 +1 @@
|
||||
13
|
||||
1
tests/day4/1.2
Normal file
1
tests/day4/1.2
Normal file
@@ -0,0 +1 @@
|
||||
30
|
||||
33
tests/day5/1
Normal file
33
tests/day5/1
Normal file
@@ -0,0 +1,33 @@
|
||||
seeds: 79 14 55 13
|
||||
|
||||
seed-to-soil map:
|
||||
50 98 2
|
||||
52 50 48
|
||||
|
||||
soil-to-fertilizer map:
|
||||
0 15 37
|
||||
37 52 2
|
||||
39 0 15
|
||||
|
||||
fertilizer-to-water map:
|
||||
49 53 8
|
||||
0 11 42
|
||||
42 0 7
|
||||
57 7 4
|
||||
|
||||
water-to-light map:
|
||||
88 18 7
|
||||
18 25 70
|
||||
|
||||
light-to-temperature map:
|
||||
45 77 23
|
||||
81 45 19
|
||||
68 64 13
|
||||
|
||||
temperature-to-humidity map:
|
||||
0 69 1
|
||||
1 0 69
|
||||
|
||||
humidity-to-location map:
|
||||
60 56 37
|
||||
56 93 4
|
||||
1
tests/day5/1.1
Normal file
1
tests/day5/1.1
Normal file
@@ -0,0 +1 @@
|
||||
35
|
||||
1
tests/day5/1.2
Normal file
1
tests/day5/1.2
Normal file
@@ -0,0 +1 @@
|
||||
46
|
||||
2
tests/day6/1
Normal file
2
tests/day6/1
Normal file
@@ -0,0 +1,2 @@
|
||||
Time: 7 15 30
|
||||
Distance: 9 40 200
|
||||
1
tests/day6/1.1
Normal file
1
tests/day6/1.1
Normal file
@@ -0,0 +1 @@
|
||||
288
|
||||
5
tests/day7/1
Normal file
5
tests/day7/1
Normal file
@@ -0,0 +1,5 @@
|
||||
32T3K 765
|
||||
T55J5 684
|
||||
KK677 28
|
||||
KTJJT 220
|
||||
QQQJA 483
|
||||
1
tests/day7/1.1
Normal file
1
tests/day7/1.1
Normal file
@@ -0,0 +1 @@
|
||||
6440
|
||||
1
tests/day7/1.2
Normal file
1
tests/day7/1.2
Normal file
@@ -0,0 +1 @@
|
||||
5905
|
||||
9
tests/day8/1
Normal file
9
tests/day8/1
Normal file
@@ -0,0 +1,9 @@
|
||||
RL
|
||||
|
||||
AAA = (BBB, CCC)
|
||||
BBB = (DDD, EEE)
|
||||
CCC = (ZZZ, GGG)
|
||||
DDD = (DDD, DDD)
|
||||
EEE = (EEE, EEE)
|
||||
GGG = (GGG, GGG)
|
||||
ZZZ = (ZZZ, ZZZ)
|
||||
1
tests/day8/1.1
Normal file
1
tests/day8/1.1
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
5
tests/day8/2
Normal file
5
tests/day8/2
Normal file
@@ -0,0 +1,5 @@
|
||||
LLR
|
||||
|
||||
AAA = (BBB, BBB)
|
||||
BBB = (AAA, ZZZ)
|
||||
ZZZ = (ZZZ, ZZZ)
|
||||
1
tests/day8/2.1
Normal file
1
tests/day8/2.1
Normal file
@@ -0,0 +1 @@
|
||||
6
|
||||
10
tests/day8/3
Normal file
10
tests/day8/3
Normal file
@@ -0,0 +1,10 @@
|
||||
LR
|
||||
|
||||
11A = (11B, XXX)
|
||||
11B = (XXX, 11Z)
|
||||
11Z = (11B, XXX)
|
||||
22A = (22B, XXX)
|
||||
22B = (22C, 22C)
|
||||
22C = (22Z, 22Z)
|
||||
22Z = (22B, 22B)
|
||||
XXX = (XXX, XXX)
|
||||
1
tests/day8/3.2
Normal file
1
tests/day8/3.2
Normal file
@@ -0,0 +1 @@
|
||||
6
|
||||
3
tests/day9/1
Normal file
3
tests/day9/1
Normal file
@@ -0,0 +1,3 @@
|
||||
0 3 6 9 12 15
|
||||
1 3 6 10 15 21
|
||||
10 13 16 21 30 45
|
||||
1
tests/day9/1.1
Normal file
1
tests/day9/1.1
Normal file
@@ -0,0 +1 @@
|
||||
114
|
||||
1
tests/day9/1.2
Normal file
1
tests/day9/1.2
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
Reference in New Issue
Block a user