defmodule AdventOfCode do
def solve(input, prev \\ -1, acc \\ 0)
def solve([], _, acc), do: acc
def solve([hd | tl], -1, 0), do: solve(tl, hd, 0)
def solve([hd | tl], prev, acc) do
solve(tl, hd, acc + (if prev < hd, do: 1, else: 0))
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&String.to_integer/1)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input, prev \\ -1, acc \\ 0)
def solve([], _, acc), do: acc
def solve([hd | tl], -1, 0), do: solve(tl, hd, 0)
def solve([hd | tl], prev, acc) do
solve(tl, hd, acc + (if prev < hd, do: 1, else: 0))
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&String.to_integer/1)
|> Enum.chunk_every(3, 1, :discard)
|> Enum.map(&Enum.sum/1)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
Enum.reduce(input, {0, 0}, fn val, {x, y} ->
case val do
"forward " <> num -> {x + String.to_integer(num), y}
"up " <> num -> {x, y - String.to_integer(num)}
"down " <> num -> {x, y + String.to_integer(num)}
end
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> AdventOfCode.solve
|> then(fn {x, y} -> IO.inspect(x * y, label: "Answer") end)
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
Enum.reduce(input, {0, 0, 0}, fn val, {x, y, aim} ->
case val do
"forward " <> num -> {x + String.to_integer(num), y + (aim * String.to_integer(num)), aim}
"up " <> num -> {x, y, aim - String.to_integer(num)}
"down " <> num -> {x, y, aim + String.to_integer(num)}
end
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> AdventOfCode.solve
|> then(fn {x, y, _} -> IO.inspect(x * y, label: "Answer") end)
else
_ -> IO.inspect("Failed to read input file")
end
use Bitwise
defmodule AdventOfCode do
def solve(input) do
total_length = length(input)
number_of_places = String.length(Enum.at(input, 0))
Enum.map(input, &(String.to_integer(&1, 2)))
|> Enum.reduce(List.duplicate(0, number_of_places), fn val, results ->
for i <- Range.new(0, number_of_places - 1) do
Enum.at(results, i) + (if (val &&& (1 <<< i)) > 0, do: 1, else: 0)
end
end)
|> Enum.with_index
|> Enum.reduce(0, fn {elm, ind}, acc ->
if elm > (total_length / 2), do: acc + (1 <<< ind), else: acc
end)
|> then(&({&1, bxor(trunc(:math.pow(2, number_of_places) - 1), &1)}))
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> AdventOfCode.solve
|> then(fn {gamma, epsilon} -> IO.inspect(gamma * epsilon, label: "Answer") end)
else
_ -> IO.inspect("Failed to read input file")
end
use Bitwise
defmodule AdventOfCode do
def solve(input, bit, comparator) do
number_of_ones = Enum.reduce(input, 0, fn val, acc -> if (val &&& (1 <<< bit)) > 0, do: acc + 1, else: acc end)
filter_ones? = comparator.(number_of_ones, length(input) / 2)
Enum.filter(input, fn val -> if filter_ones?, do: (val &&& (1 <<< bit)) > 0, else: (val &&& (1 <<< bit)) == 0 end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> then(fn content -> {String.length(Enum.at(content, 0)), Enum.map(content, &(String.to_integer(&1, 2)))} end)
|> then(fn {bit_length, basis} ->
Enum.reduce(Range.new(bit_length - 1, 0), {basis, basis}, fn bit, {lesser, greater} ->
{
(if length(lesser) == 1, do: lesser, else: AdventOfCode.solve(lesser, bit, &Kernel.</2)),
(if length(greater) == 1, do: greater, else: AdventOfCode.solve(greater, bit, &Kernel.>=/2))
}
end)
end)
|> Tuple.to_list
|> List.flatten
|> Enum.product
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(numbers, boards) do
max_position = length(numbers)
number_map = Enum.with_index(numbers) |> Enum.into(%{})
Enum.with_index(boards)
|> Enum.map(fn { board, index } ->
List.zip(board)
|> Enum.map(&Tuple.to_list/1)
|> then(&(board ++ &1))
|> Enum.map(fn possibility ->
Enum.map(possibility, &(Map.get(number_map, &1, max_position))) |> Enum.max
end)
|> Enum.min
|> then(&({index, &1}))
end)
|> Enum.max_by(fn {_, res} -> res end)
|> then(fn {index, position} ->
used_number_map = Enum.take(numbers, position + 1) |> MapSet.new
Enum.at(boards, index)
|> List.flatten
|> Enum.reject(&(MapSet.member?(used_number_map, &1)))
|> Enum.sum
|> then(&(&1 * Enum.at(numbers, position)))
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n\n", trim: true)
|> then(fn [numbers | boards] ->
{
String.split(numbers, ",", trim: true) |> Enum.map(&String.to_integer/1),
Enum.map(boards, fn board ->
String.split(board, "\n", trim: true)
|> Enum.map(fn r -> String.split(r, " ", trim: true) |> Enum.map(&String.to_integer/1) end)
end)
}
end)
|> then(fn {numbers, boards} -> AdventOfCode.solve(numbers, boards) end)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(numbers, boards) do
max_position = length(numbers)
number_map = Enum.with_index(numbers) |> Enum.into(%{})
Enum.with_index(boards)
|> Enum.map(fn { board, index } ->
List.zip(board)
|> Enum.map(&Tuple.to_list/1)
|> then(&(board ++ &1))
|> Enum.map(fn possibility ->
Enum.map(possibility, &(Map.get(number_map, &1, max_position))) |> Enum.max
end)
|> Enum.min
|> then(&({index, &1}))
end)
|> Enum.max_by(fn {_, res} -> res end)
|> then(fn {index, position} ->
used_number_map = Enum.take(numbers, position + 1) |> MapSet.new
Enum.at(boards, index)
|> List.flatten
|> Enum.reject(&(MapSet.member?(used_number_map, &1)))
|> Enum.sum
|> then(&(&1 * Enum.at(numbers, position)))
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n\n", trim: true)
|> then(fn [numbers | boards] ->
{
String.split(numbers, ",", trim: true) |> Enum.map(&String.to_integer/1),
Enum.map(boards, fn board ->
String.split(board, "\n", trim: true)
|> Enum.map(fn r -> String.split(r, " ", trim: true) |> Enum.map(&String.to_integer/1) end)
end)
}
end)
|> then(fn {numbers, boards} -> AdventOfCode.solve(numbers, boards) end)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule Point do
defstruct [:x, :y]
end
defmodule AdventOfCode do
def solve(segments) do
Enum.filter(segments, fn [start, finish] -> start.x == finish.x || start.y == finish.y end)
|> Enum.reduce(%{}, fn [start, finish], acc ->
distance = Enum.max([abs(start.x - finish.x), abs(start.y - finish.y)])
x_direction = if start.x > finish.x, do: -1, else: 1
y_direction = if start.y > finish.y, do: -1, else: 1
for i <- Range.new(0, distance), into: acc do
x = if start.x == finish.x, do: start.x, else: start.x + (i * x_direction)
y = if start.y == finish.y, do: start.y, else: start.y + (i * y_direction)
{{x,y}, Map.get(acc, {x,y}, 0) + 1}
end
end)
|> Enum.filter(fn {_, v} -> v >= 2 end)
|> length
end
end
defmodule Main do
def main() do
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(fn line ->
String.split(line, " -> ", trim: true)
|> Enum.map(fn point ->
String.split(point, ",", trim: true)
|> Enum.map(&String.to_integer/1)
|> then(fn [x, y] -> %Point{x: x, y: y} end)
end)
end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
end
end
Main.main()
defmodule Point do
defstruct [:x, :y]
end
defmodule AdventOfCode do
def solve(segments) do
Enum.reduce(segments, %{}, fn [start, finish], acc ->
distance = Enum.max([abs(start.x - finish.x), abs(start.y - finish.y)])
x_direction = if start.x > finish.x, do: -1, else: 1
y_direction = if start.y > finish.y, do: -1, else: 1
for i <- Range.new(0, distance), into: acc do
x = if start.x == finish.x, do: start.x, else: start.x + (i * x_direction)
y = if start.y == finish.y, do: start.y, else: start.y + (i * y_direction)
{{x,y}, Map.get(acc, {x,y}, 0) + 1}
end
end)
|> Enum.filter(fn {_, v} -> v >= 2 end)
|> length
end
end
defmodule Main do
def main() do
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(fn line ->
String.split(line, " -> ", trim: true)
|> Enum.map(fn point ->
String.split(point, ",", trim: true)
|> Enum.map(&String.to_integer/1)
|> then(fn [x, y] -> %Point{x: x, y: y} end)
end)
end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
end
end
Main.main()
defmodule AdventOfCode do
def solve(fish, days) do
Enum.reduce(Range.new(0, days - 1), fish, fn _, acc ->
newborn_fish = Map.get(acc, 0, 0)
Enum.reduce(1..8, acc, &(Map.put(&2, &1 - 1, Map.get(&2, &1, 0))))
|> Map.put(8, newborn_fish)
|> Map.update(6, newborn_fish, &(&1 + newborn_fish))
end)
|> Map.values
|> Enum.sum
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split(",", trim: true)
|> Enum.reduce(%{}, fn s, acc ->
n = String.to_integer(s)
Map.update(acc, n, 1, &(&1 + 1))
end)
|> AdventOfCode.solve(80)
|> IO.inspect
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(fish, days) do
Enum.reduce(Range.new(0, days - 1), fish, fn _, acc ->
newborn_fish = Map.get(acc, 0, 0)
Enum.reduce(1..8, acc, &(Map.put(&2, &1 - 1, Map.get(&2, &1, 0))))
|> Map.put(8, newborn_fish)
|> Map.update(6, newborn_fish, &(&1 + newborn_fish))
end)
|> Map.values
|> Enum.sum
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split(",", trim: true)
|> Enum.reduce(%{}, fn s, acc ->
n = String.to_integer(s)
Map.update(acc, n, 1, &(&1 + 1))
end)
|> AdventOfCode.solve(256)
|> IO.inspect
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(numbers) do
Enum.map(Range.new(Enum.min(numbers), Enum.max(numbers)), fn i ->
Enum.map(numbers, fn n -> abs(i - n) end) |> Enum.sum
end)
|> Enum.min
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split(",", trim: true)
|> Enum.map(&String.to_integer/1)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(numbers) do
Enum.map(Range.new(Enum.min(numbers), Enum.max(numbers)), fn i ->
Enum.map(numbers, fn n -> trunc((abs(i - n) * (abs(i - n) + 1)) / 2) end) |> Enum.sum
end)
|> Enum.min
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split(",", trim: true)
|> Enum.map(&String.to_integer/1)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
String.split(line, "|", trim: true)
|> Enum.map(fn part ->
String.split(part, " ", trim: true)
|> Enum.map(&String.to_charlist/1)
end)
end)
|> Enum.map(fn [_, outputs] ->
Enum.count(outputs, &(length(&1) in [2,3,4,7]))
end)
|> Enum.sum
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
@correct_digits %{
0 => 'abcefg',
1 => 'cf',
2 => 'acdeg',
3 => 'acdfg',
4 => 'bcdf',
5 => 'abdfg',
6 => 'abdefg',
7 => 'acf',
8 => 'abcdefg',
9 => 'abcdfg'
}
@length_map %{
2 => 1,
3 => 7,
4 => 4,
7 => 8
}
def solve(inputs, outputs) do
Enum.filter(inputs, &(length(&1) in Map.keys(@length_map)))
|> Enum.reduce(%{}, fn parts, acc ->
true_parts = MapSet.new(@correct_digits[@length_map[length(parts)]])
Enum.reduce(parts, acc, fn part, map ->
Map.update(map, part, true_parts, &(MapSet.intersection(&1, true_parts)))
end)
end)
|> Enum.reduce([%{}], fn {letter, options}, acc ->
Enum.flat_map(acc, fn val ->
Enum.reject(options, &(&1 in Map.values(val)))
|> Enum.map(&(Map.put(val, letter, &1)))
end)
end)
|> build_output(outputs)
end
defp build_output(options, outputs) do
inverted_digits = Enum.map(@correct_digits, fn {k, v} -> {v, k} end) |> Enum.into(%{})
Enum.find_value(options, fn option ->
Enum.map(outputs, fn output ->
Enum.map(output, &(Map.get(option, &1))) |> Enum.sort
end)
|> Enum.map(&(Map.get(inverted_digits, Enum.sort(&1))))
|> then(fn val -> if Enum.all?(val), do: val, else: nil end)
end)
|> Integer.undigits
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
String.split(line, "|", trim: true)
|> Enum.map(fn part ->
String.split(part, " ", trim: true)
|> Enum.map(&String.to_charlist/1)
end)
end)
|> Enum.map(fn [inputs, outputs] -> AdventOfCode.solve(inputs, outputs) end)
|> Enum.sum
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
Enum.zip(input)
|> Enum.map(&Tuple.to_list/1)
|> find_row_lowpoints
|> MapSet.to_list
|> Enum.reduce(MapSet.new, fn {i, j}, acc -> MapSet.put(acc, {j, i}) end)
|> then(&(MapSet.intersection(&1, find_row_lowpoints(input))))
|> Enum.map(fn {i, j} -> Enum.at(Enum.at(input, i), j) + 1 end)
|> Enum.sum
end
defp find_row_lowpoints(input) do
Enum.map(input, &Enum.with_index/1)
|> Enum.with_index
|> Enum.reduce(MapSet.new, fn {row, i}, outer_acc ->
Enum.reduce(row, outer_acc, fn {val, j}, acc ->
left = if j == 0, do: 10, else: elem(Enum.at(row, j - 1), 0)
right = if j == (length(row) - 1), do: 10, else: elem(Enum.at(row, j + 1), 0)
if val < left && val < right, do: MapSet.put(acc, {i, j}), else: acc
end)
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(&(String.split(&1, "", trim: true) |> Enum.map(fn i -> String.to_integer(i) end)))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
Enum.with_index(input)
|> Enum.reduce(MapSet.new, fn {row, i}, acc ->
Enum.reduce(Enum.with_index(row), acc, fn {val, j}, i_acc ->
if val == 9, do: i_acc, else: MapSet.put(i_acc, {i, j})
end)
end)
|> Stream.unfold(fn
%MapSet{map: map} when map_size(map) == 0 -> nil
points ->
MapSet.to_list(points)
|> then(&({Enum.take(&1, 1), MapSet.new}))
|> Stream.unfold(fn
{[], _} -> nil
{[{i, j} = hd | tl], used} ->
if MapSet.member?(used, hd) do
{nil, {tl, used}}
else
next_points = for n_i <- Range.new(i - 1, i + 1),
n_j <- Range.new(j - 1, j + 1),
n_i >= 0 and n_j >= 0,
n_i < length(input) and n_j < length(List.first(input)),
n_i != i or n_j != j,
n_i == i or n_j == j,
MapSet.member?(points, {n_i, n_j}),
!MapSet.member?(used, {n_i, n_j}) do
{n_i, n_j}
end
{hd, {next_points ++ tl, MapSet.put(used, hd)}}
end
end)
|> Enum.reject(&is_nil/1)
|> then(&({&1, MapSet.difference(points, MapSet.new(&1))}))
end)
|> Enum.map(&length/1)
|> Enum.sort(:desc)
|> Enum.take(3)
|> Enum.product
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(&(String.split(&1, "", trim: true) |> Enum.map(fn i -> String.to_integer(i) end)))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
Enum.map(input, fn line ->
Stream.unfold({line, []}, fn
nil -> nil
{[], _} -> nil
{[hd | tl], stack} when hd in ["[", "(", "<", "{"] -> {nil, {tl, [hd | stack]}}
{[hd | tl], [s_hd | s_tl]} -> case {s_hd, hd} do
{"(", ")"} -> {nil, {tl, s_tl}}
{"{", "}"} -> {nil, {tl, s_tl}}
{"[", "]"} -> {nil, {tl, s_tl}}
{"<", ">"} -> {nil, {tl, s_tl}}
_ -> {hd, nil}
end
{[hd | _], _} -> {hd, nil}
end)
|> Enum.reject(&is_nil/1)
end)
|> List.flatten
|> Enum.frequencies
|> Enum.reduce(0, fn {key, count}, acc ->
acc + count * case key do
")" -> 3
"]" -> 57
"}" -> 1197
">" -> 25137
end
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, "", trim: true))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
Enum.map(input, fn line ->
Stream.unfold({line, []}, fn
nil -> nil
{[], stack} -> {stack, nil}
{[hd | tl], stack} when hd in ["[", "(", "<", "{"] -> {nil, {tl, [hd | stack]}}
{[hd | tl], [s_hd | s_tl]} -> case {s_hd, hd} do
{"(", ")"} -> {nil, {tl, s_tl}}
{"{", "}"} -> {nil, {tl, s_tl}}
{"[", "]"} -> {nil, {tl, s_tl}}
{"<", ">"} -> {nil, {tl, s_tl}}
_ -> {[], nil}
end
_ -> {[], nil}
end)
|> Enum.reject(&is_nil/1)
end)
|> Enum.map(&List.first/1)
|> Enum.map(fn line ->
Enum.reduce(line, 0, fn c, acc ->
acc * 5 + case c do
"(" -> 1
"[" -> 2
"{" -> 3
"<" -> 4
end
end)
end)
|> Enum.reject(&(&1 == 0))
|> Enum.sort
|> then(&(Enum.at(&1, div(length(&1), 2))))
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, "", trim: true))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input, steps, counter \\ 0)
def solve(_, 0, counter), do: counter
def solve(input, steps, counter) do
Enum.with_index(input)
|> Enum.reverse
|> Enum.reduce({[], []}, fn {line, i}, {acc, flashes} ->
{new_line, new_flashes} = Enum.reduce(Enum.reverse(Enum.with_index(line)), {[], flashes}, fn {n, j}, {i_acc, i_flashes} ->
{[n + 1 | i_acc], (if n == 9, do: [{i, j} | i_flashes], else: i_flashes)}
end)
{[new_line | acc], new_flashes}
end)
|> Stream.unfold(fn
nil -> nil
{input, []} -> {input, nil}
{input, [{i, j} | tl]} ->
{new_input, new_flashes} = for n_i <- Range.new(i - 1, i + 1),
n_j <- Range.new(j - 1, j + 1),
n_i != i or n_j != j,
n_i >= 0 and n_i < length(input),
n_j >= 0 and n_j < length(Enum.at(input, 0)),
reduce: {input, []} do
{acc, new_flashes} ->
n = Enum.at(Enum.at(acc, n_i), n_j)
sublist = Enum.at(acc, n_i)
{
List.replace_at(acc, n_i, List.replace_at(sublist, n_j, n + 1)),
(if n == 9, do: [{n_i, n_j} | new_flashes], else: new_flashes)
}
end
{new_input, {new_input, tl ++ new_flashes}}
end)
|> Enum.to_list
|> then(fn res ->
new_input = Enum.map(List.last(res), fn line -> Enum.map(line, &(if &1 > 9, do: 0, else: &1)) end)
solve(new_input, steps - 1, counter + length(res) - 1)
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(fn l -> String.split(l, "", trim: true) |> Enum.map(&String.to_integer/1) end)
|> AdventOfCode.solve(100)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input, step \\ 1) do
Enum.with_index(input)
|> Enum.reverse
|> Enum.reduce({[], []}, fn {line, i}, {acc, flashes} ->
{new_line, new_flashes} = Enum.reduce(Enum.reverse(Enum.with_index(line)), {[], flashes}, fn {n, j}, {i_acc, i_flashes} ->
{[n + 1 | i_acc], (if n == 9, do: [{i, j} | i_flashes], else: i_flashes)}
end)
{[new_line | acc], new_flashes}
end)
|> Stream.unfold(fn
nil -> nil
{input, []} -> {input, nil}
{input, [{i, j} | tl]} ->
{new_input, new_flashes} = for n_i <- Range.new(i - 1, i + 1),
n_j <- Range.new(j - 1, j + 1),
n_i != i or n_j != j,
n_i >= 0 and n_i < length(input),
n_j >= 0 and n_j < length(Enum.at(input, 0)),
reduce: {input, []} do
{acc, new_flashes} ->
n = Enum.at(Enum.at(acc, n_i), n_j)
sublist = Enum.at(acc, n_i)
{
List.replace_at(acc, n_i, List.replace_at(sublist, n_j, n + 1)),
(if n == 9, do: [{n_i, n_j} | new_flashes], else: new_flashes)
}
end
{new_input, {new_input, tl ++ new_flashes}}
end)
|> Enum.to_list
|> then(fn res ->
new_input = Enum.map(List.last(res), fn line -> Enum.map(line, &(if &1 > 9, do: 0, else: &1)) end)
if (length(res) - 1) == Enum.sum(Enum.map(new_input, &length/1)) do
step
else
solve(new_input, step + 1)
end
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(fn l -> String.split(l, "", trim: true) |> Enum.map(&String.to_integer/1) end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
defmodule Node do
defstruct [:name, neighbors: []]
def add_neighbor(%Node{neighbors: n} = base_node, name) do
%{base_node | neighbors: [name | n]}
end
end
def solve(input) do
List.flatten(input)
|> Enum.uniq
|> Enum.map(&{&1, %Node{name: &1}})
|> Enum.into(%{})
|> then(fn nodes ->
Enum.reduce(input, nodes, fn [start, stop], acc ->
{start_node, stop_node} = {acc[start], acc[stop]}
Map.merge(acc, %{
start => Node.add_neighbor(start_node, stop),
stop => Node.add_neighbor(stop_node, start)
})
end)
end)
|> then(&find_paths(&1, &1["start"], &1["end"]))
|> length
end
defp find_paths(graph, start_node, end_node, path \\ [], visited \\ MapSet.new) do
next_path = [start_node.name | path]
next_nodes = MapSet.difference(MapSet.new(start_node.neighbors), visited)
visited_set = if start_node.name == String.upcase(start_node.name) do
visited
else
MapSet.put(visited, start_node.name)
end
if start_node.name == end_node.name do
[next_path]
else
Enum.reduce(next_nodes, [], fn next_node, acc ->
acc ++ find_paths(graph, graph[next_node], end_node, next_path, visited_set)
end)
|> Enum.reject(&length(&1) == 0)
end
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, "-", trim: true))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
defmodule Node do
defstruct [:name, neighbors: []]
def add_neighbor(%Node{neighbors: n} = base_node, name) do
%{base_node | neighbors: [name | n]}
end
end
def solve(input) do
List.flatten(input)
|> Enum.uniq
|> Enum.map(&{&1, %Node{name: &1}})
|> Enum.into(%{})
|> then(fn nodes ->
Enum.reduce(input, nodes, fn [start, stop], acc ->
{start_node, stop_node} = {acc[start], acc[stop]}
Map.merge(acc, %{
start => Node.add_neighbor(start_node, stop),
stop => Node.add_neighbor(stop_node, start)
})
end)
end)
|> then(&find_paths(&1, &1["start"], &1["end"]))
|> length
end
defp find_paths(graph, start_node, end_node, path \\ [], visited \\ MapSet.new) do
next_path = [start_node.name | path]
contains_lowercase_duplicate = Enum.frequencies(next_path)
|> Enum.any?(fn {k, v} ->
String.upcase(k) != k and v > 1
end)
next_nodes = if contains_lowercase_duplicate do
MapSet.difference(MapSet.new(start_node.neighbors), visited)
else
start_node.neighbors -- ["start"]
end
visited_set = if start_node.name == String.upcase(start_node.name) do
visited
else
MapSet.put(visited, start_node.name)
end
if start_node.name == end_node.name do
[next_path]
else
Enum.reduce(next_nodes, [], fn next_node, acc ->
acc ++ find_paths(graph, graph[next_node], end_node, next_path, visited_set)
end)
|> Enum.reject(&length(&1) == 0)
end
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(&String.split(&1, "-", trim: true))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(coords, folds) do
Enum.reduce(folds, MapSet.new(coords), fn {let, val}, current_coords ->
Enum.reduce(MapSet.to_list(current_coords), MapSet.new, fn {x, y}, new_coords ->
cond do
let == "x" and x > val -> MapSet.put(new_coords, {val - (x - val), y})
let == "y" and y > val -> MapSet.put(new_coords, {x, val - (y - val)})
true -> MapSet.put(new_coords, {x, y})
end
end)
end)
|> MapSet.size
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n\n", trim: true)
|> Enum.map(&String.split(&1, "\n", trim: true))
|> then(fn [coords, folds] ->
{
Enum.map(coords, fn l -> String.split(l, ",", trim: true) |> Enum.map(&String.to_integer/1) |> List.to_tuple end),
Enum.map(folds, fn l ->
String.replace(l, "fold along ", "")
|> String.split("=", trim: true)
|> then(fn [let, val] -> {let, String.to_integer(val)} end)
end)
}
end)
|> then(&AdventOfCode.solve(elem(&1, 0), Enum.take(elem(&1, 1), 1)))
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(coords, folds) do
Enum.reduce(folds, MapSet.new(coords), fn {let, val}, current_coords ->
Enum.reduce(MapSet.to_list(current_coords), MapSet.new, fn {x, y}, new_coords ->
cond do
let == "x" and x > val -> MapSet.put(new_coords, {val - (x - val), y})
let == "y" and y > val -> MapSet.put(new_coords, {x, val - (y - val)})
true -> MapSet.put(new_coords, {x, y})
end
end)
end)
|> then(&print_board(MapSet.to_list(&1)))
end
defp print_board(coords) do
max_x = Enum.map(coords, &elem(&1, 0) + 1) |> Enum.max
max_y = Enum.map(coords, &elem(&1, 1) + 1) |> Enum.max
board = List.duplicate(List.duplicate(".", max_x), max_y)
Enum.reduce(coords, board, fn {x, y}, acc ->
List.replace_at(acc, y, List.replace_at(Enum.at(acc, y), x, "#"))
end)
|> Enum.map(&Enum.join(&1, ""))
|> IO.inspect
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n\n", trim: true)
|> Enum.map(&String.split(&1, "\n", trim: true))
|> then(fn [coords, folds] ->
{
Enum.map(coords, fn l -> String.split(l, ",", trim: true) |> Enum.map(&String.to_integer/1) |> List.to_tuple end),
Enum.map(folds, fn l ->
String.replace(l, "fold along ", "")
|> String.split("=", trim: true)
|> then(fn [let, val] -> {let, String.to_integer(val)} end)
end)
}
end)
|> then(&AdventOfCode.solve(elem(&1, 0), elem(&1, 1)))
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(basis, rules, steps) do
Enum.chunk_every(basis, 2, 1, :discard)
|> Enum.reduce({%{}, %{}}, fn chunk, {memo, res} ->
{result_freqs, new_memo} = expand(chunk, rules, steps, memo)
Map.merge(res, result_freqs, fn _, v1, v2 -> v1 + v2 end)
|> Map.update(List.last(chunk), 0, &(&1 - 1))
|> then(&{new_memo, &1})
end)
|> then(fn {_, res} ->
Map.update(res, List.last(basis), 0, &(&1 + 1))
end)
|> Map.values
|> Enum.min_max
|> then(&elem(&1, 1) - elem(&1, 0))
end
def expand([first, last], _, 0, memo) when first == last, do: {%{first => 2}, memo}
def expand([first, last], _, 0, memo), do: {%{first => 1, last => 1}, memo}
def expand([first, last] = basis, rules, steps, memo) do
basis_key = "#{first}#{last}"
inner_letter = rules[basis_key]
cond do
Map.has_key?(memo, "#{basis_key}-#{steps}") -> {Map.get(memo, "#{basis_key}-#{steps}"), memo}
Map.has_key?(rules, basis_key) ->
{left_res, left_memo} = expand([first, inner_letter], rules, steps - 1, memo)
{right_res, new_memo} = expand([inner_letter, last], rules, steps - 1, Map.put(left_memo, "#{first}#{inner_letter}-#{steps - 1}", left_res))
Map.merge(%{inner_letter => -1}, left_res, fn _, v1, v2 -> v1 + v2 end)
|> Map.merge(right_res, fn _, v1, v2 -> v1 + v2 end)
|> then(&{&1, Map.put(new_memo, "#{inner_letter}#{last}-#{steps - 1}", right_res)})
first == last -> {%{first => 2}, memo}
true -> {%{first => 1, last => 1}, memo}
end
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n\n", trim: true)
|> Enum.map(&String.split(&1, "\n", trim: true))
|> then(fn [[basis], rules] ->
{
String.graphemes(basis),
Enum.map(rules, fn l ->
String.split(l, " -> ", trim: true)
|> then(&List.to_tuple/1)
end)
|> Enum.into(%{})
}
end)
|> then(&AdventOfCode.solve(elem(&1, 0), elem(&1, 1), 40))
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
@effective_infinity 999999999999999
def solve(board) do
max_x = length(Enum.at(board, 0)) - 1
max_y = length(board) - 1
distance_map = for i <- Range.new(0, max_x),
j <- Range.new(0, max_y), into: %{} do
{{i, j}, @effective_infinity}
end
|> Map.put({0,0}, 0)
find_shortest_path(board, [{0, 0}], MapSet.new, distance_map)
|> Map.get({max_x, max_y})
end
def find_shortest_path(board, [{c_x, c_y} | tail], used, distance_map) do
possible_next_points = for i <- Range.new(c_x - 1, c_x + 1),
j <- Range.new(c_y - 1, c_y + 1),
i >= 0 and j >= 0,
i < length(Enum.at(board, 0)) and j < length(board),
i == c_x or j == c_y,
i != c_x or j != c_y,
!MapSet.member?(used, {i, j}) do
{i, j}
end
Enum.reduce(possible_next_points, distance_map, fn {x, y}, acc ->
existing_cost = Map.get(acc, {x, y})
current_path_cost = Map.get(acc, {c_x, c_y})
edge_cost = Enum.at(Enum.at(board, x), y)
if existing_cost > (current_path_cost + edge_cost) do
Map.put(acc, {x, y}, current_path_cost + edge_cost)
else
acc
end
end)
|> then(fn new_distance_map ->
Enum.uniq(possible_next_points ++ tail)
|> Enum.sort_by(&Map.get(new_distance_map, &1))
|> then(&{&1, new_distance_map})
end)
|> then(fn
{[], ndm} -> ndm
{points, ndm} -> find_shortest_path(board, points, MapSet.put(used, List.first(points)), ndm)
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(fn l -> String.graphemes(l) |> Enum.map(&String.to_integer/1) end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
@effective_infinity 999999999999999
def solve(board) do
max_x = length(Enum.at(board, 0)) - 1
max_y = length(board) - 1
distance_map = for i <- Range.new(0, max_x),
j <- Range.new(0, max_y), into: %{} do
{{i, j}, @effective_infinity}
end
|> Map.put({0,0}, 0)
find_shortest_path(board, [{0, 0}], MapSet.new, distance_map)
|> Map.get({max_x, max_y})
end
def find_shortest_path(board, [{c_x, c_y} | tail], used, distance_map) do
possible_next_points = for i <- Range.new(c_x - 1, c_x + 1),
j <- Range.new(c_y - 1, c_y + 1),
i >= 0 and j >= 0,
i < length(Enum.at(board, 0)) and j < length(board),
i == c_x or j == c_y,
i != c_x or j != c_y,
!MapSet.member?(used, {i, j}) do
{i, j}
end
Enum.reduce(possible_next_points, distance_map, fn {x, y}, acc ->
existing_cost = Map.get(acc, {x, y})
current_path_cost = Map.get(acc, {c_x, c_y})
edge_cost = Enum.at(Enum.at(board, x), y)
if existing_cost > (current_path_cost + edge_cost) do
Map.put(acc, {x, y}, current_path_cost + edge_cost)
else
acc
end
end)
|> then(fn new_distance_map ->
Enum.uniq(possible_next_points ++ tail)
|> Enum.sort_by(&Map.get(new_distance_map, &1))
|> then(&{&1, new_distance_map})
end)
|> then(fn
{[], ndm} -> ndm
{points, ndm} -> find_shortest_path(board, points, MapSet.put(used, List.first(points)), ndm)
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> Enum.map(fn l -> String.graphemes(l) |> Enum.map(&String.to_integer/1) end)
|> then(fn board ->
Enum.reduce(0..4, [], fn y, outer_acc ->
outer_acc ++ Enum.reduce(0..4, List.duplicate([], length(board)), fn x, inner_acc ->
Enum.map(Enum.with_index(board), fn {row, i} ->
Enum.at(inner_acc, i) ++ Enum.map(row, &rem(&1 + x + y, 10) + div(&1 + x + y, 10))
end)
end)
end)
end)
|> AdventOfCode.solve
|> IO.inspect
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(<<version::3, id::3, remainder::bitstring>>) do
if id == 4 do
Stream.unfold(remainder, fn
nil -> nil
<<0::size(1), _::size(4), _::bitstring>> -> {5, nil}
<<1::size(1), _::size(4), rest::bitstring>> -> {5, rest}
end)
|> Enum.sum
|> then(&{version, &1 + 6})
else
case remainder do
<<0::size(1), remaining_length::size(15), rest::bitstring>> ->
Stream.unfold({remaining_length, rest}, fn
{0, _} -> nil
{n, bits} ->
{version, bits_used} = solve(bits)
<<_::size(bits_used), remaining_bits::bitstring>> = bits
{{version, bits_used}, {n - bits_used, remaining_bits}}
end)
|> Enum.reduce({0, 16}, fn {v1, v2}, {a1, a2} -> {v1 + a1, v2 + a2} end)
<<1::size(1), subpackets::size(11), other_bits::bitstring>> ->
Enum.reduce(Range.new(subpackets, 1, -1), {other_bits, 12, 0}, fn _, {bits, bits_used, version_sum} ->
{version, used} = solve(bits)
<<_::size(used), next_bits::bitstring>> = bits
{next_bits, bits_used + used, version_sum + version}
end)
|> then(fn {_, bits_used, version} -> {version, bits_used} end)
end
|> then(fn {v, b} -> {v + version, 6 + b} end)
end
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> then(fn [num] ->
len = 4 * String.length(num)
<<String.to_integer(num, 16)::size(len)>>
end)
|> AdventOfCode.solve
|> then(&elem(&1, 0))
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
use Bitwise
defmodule AdventOfCode do
def solve(<<_::3, id::3, remainder::bitstring>>) do
if id == 4 do
Stream.unfold(remainder, fn
nil -> nil
<<0::size(1), val::size(4), _::bitstring>> -> {val, nil}
<<1::size(1), val::size(4), rest::bitstring>> -> {val, rest}
end)
|> Enum.with_index
|> then(fn values ->
Enum.reduce(values, 0, fn {val, i}, acc ->
acc + (val <<< (4 * (length(values) - i - 1)))
end)
|> then(&{&1, 6 + (5 * length(values))})
end)
else
{inputs, bits_used} = case remainder do
<<0::size(1), remaining_length::size(15), rest::bitstring>> ->
Stream.unfold({remaining_length, rest}, fn
{0, _} -> nil
{n, bits} ->
{answer, bits_used} = solve(bits)
<<_::size(bits_used), remaining_bits::bitstring>> = bits
{answer, {n - bits_used, remaining_bits}}
end)
|> Enum.to_list
|> then(&{&1, 16 + remaining_length})
<<1::size(1), subpackets::size(11), other_bits::bitstring>> ->
Enum.reduce(Range.new(subpackets, 1, -1), {other_bits, 12, []}, fn _, {bits, bits_used, answer_acc} ->
{answer, used} = solve(bits)
<<_::size(used), next_bits::bitstring>> = bits
{next_bits, bits_used + used, [answer | answer_acc]}
end)
|> then(fn {_, bits_used, answer_acc} -> {Enum.reverse(answer_acc), bits_used} end)
end
case id do
0 -> Enum.sum(inputs)
1 -> Enum.product(inputs)
2 -> Enum.min(inputs)
3 -> Enum.max(inputs)
5 -> if Enum.at(inputs, 0) > Enum.at(inputs, 1), do: 1, else: 0
6 -> if Enum.at(inputs, 0) < Enum.at(inputs, 1), do: 1, else: 0
7 -> if Enum.at(inputs, 0) == Enum.at(inputs, 1), do: 1, else: 0
end
|> then(fn res -> {res, 6 + bits_used} end)
end
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.split("\n", trim: true)
|> then(fn [num] ->
len = 4 * String.length(num)
<<String.to_integer(num, 16)::size(len)>>
end)
|> AdventOfCode.solve
|> then(&elem(&1, 0))
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
@max_step 500
def solve(x_range, y_range) do
x_max = Enum.max(x_range)
y_min = Enum.min(y_range)
possible_x_values = Enum.reduce(x_max..1, [], fn n, acc ->
positions = Enum.scan(n..1, &(&1 + &2))
min_index = Enum.find_index(positions, &(&1 in x_range))
max_index = Enum.find_index(positions, &(&1 > x_max)) || @max_step
if min_index, do: [{n, min_index + 1, max_index} | acc], else: acc
end)
|> Enum.to_list
{_, min_steps, max_steps} = Enum.min_by(possible_x_values, &elem(&1, 0))
Stream.unfold(y_min, fn
nil -> nil
n ->
positions = Enum.map(min_steps..max_steps, &Enum.sum(Range.new(n, n - &1)))
y_index = Enum.find_index(positions, &(&1 in y_range))
cond do
!is_nil(y_index) -> {n, n + 1}
Enum.min(positions) > Enum.max(y_range) -> {nil, nil}
true -> {nil, n+1}
end
end)
|> Enum.reject(&is_nil/1)
|> Enum.max
|> then(&div(&1 * (&1+1), 2))
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.trim("target area: ")
|> String.split(", ", trim: true)
|> Enum.map(fn part ->
String.slice(part, 2, String.length(part) - 2)
|> String.split("..")
|> Enum.map(&String.to_integer/1)
|> then(fn [l, u] -> Range.new(l, u) end)
end)
|> then(fn [x, y] -> AdventOfCode.solve(x, y) end)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
@max_step 1000
def solve(x_range, y_range) do
x_max = Enum.max(x_range)
y_min = Enum.min(y_range)
possible_x_values = Enum.reduce(x_max..1, [], fn n, acc ->
positions = Enum.scan(n..1, &(&1 + &2))
min_index = Enum.find_index(positions, &(&1 in x_range))
max_index = Enum.find_index(positions, &(&1 > x_max)) || @max_step
if min_index, do: [{n, min_index + 1, max_index} | acc], else: acc
end)
|> Enum.to_list
Enum.flat_map(possible_x_values, fn {x_vel, min_steps, max_steps} ->
Enum.reduce_while(y_min..@max_step, [], fn y_vel, acc ->
positions = Enum.map(min_steps..max_steps, &Enum.sum(Range.new(y_vel, y_vel - (&1-1))))
cond do
Enum.any?(positions, &(&1 in y_range)) -> {:cont, [{x_vel, y_vel} | acc]}
Enum.min(positions) > Enum.max(y_range) -> {:halt, acc}
true -> {:cont, acc}
end
end)
end)
|> length
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.trim(contents)
|> String.trim("target area: ")
|> String.split(", ", trim: true)
|> Enum.map(fn part ->
String.slice(part, 2, String.length(part) - 2)
|> String.split("..")
|> Enum.map(&String.to_integer/1)
|> then(fn [l, u] -> Range.new(l, u) end)
end)
|> then(fn [x, y] -> AdventOfCode.solve(x, y) end)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
use Bitwise
defmodule AdventOfCode do
def solve(input) do
Enum.reduce(input, fn elm, acc ->
Stream.unfold({:explode, [acc, elm]}, fn
nil -> nil
{:explode, current} -> case explode(current) do
{0, _, _, res} -> {nil, {:split, res}}
{_, _, _, res} -> {nil, {:explode, res}}
end
{:split, current} -> case split(current) do
{true, res} -> {nil, {:explode, res}}
{_, res} -> {res, nil}
end
end)
|> Enum.at(-1)
end)
|> magnitude
end
defp explode(input, depth \\ 0)
defp explode(a, _) when is_number(a), do: {0, nil, nil, a}
defp explode([a, b], 4) when is_number(a) and is_number(b), do: {7, a, b, 0}
defp explode([a, b], _) when is_number(a) and is_number(b), do: {0, a, b, [a, b]}
defp explode([a, b], depth) do
with {:a, {0, _, _, a}} <- {:a, explode(a, depth + 1)},
{:b, {0, _, _, b}} <- {:b, explode(b, depth + 1)} do
{0, nil, nil, [a, b]}
else
{:a, {n, v1, v2, a}} when (n &&& 4) > 0 -> {n - 4, v1, v2, [a, add_to_outermost(b, :left, v2)]}
{:a, {n, v1, v2, a}} -> {n, v1, v2, [a, b]}
{:b, {n, v1, v2, b}} when (n &&& 2) > 0 -> {n - 2, v1, v2, [add_to_outermost(a, :right, v1), b]}
{:b, {n, v1, v2, b}} -> {n, v1, v2, [a, b]}
end
end
defp split(n) when is_number(n) and n >= 10, do: {true, [div(n, 2), n - div(n, 2)]}
defp split(n) when is_number(n), do: {false, n}
defp split([a, b]) do
with {:a, {false, a}} <- {:a, split(a)},
{:b, {false, b}} <- {:b, split(b)} do
{false, [a, b]}
else
{:a, {_, a}} -> {true, [a, b]}
{:b, {_, b}} -> {true, [a, b]}
end
end
defp magnitude(n) when is_number(n), do: n
defp magnitude([a, b]), do: 3 * magnitude(a) + 2 * magnitude(b)
defp add_to_outermost(a, _, val) when is_number(a), do: a + val
defp add_to_outermost([a, b], :left, val), do: [add_to_outermost(a, :left, val), b]
defp add_to_outermost([a, b], :right, val), do: [a, add_to_outermost(b, :right, val)]
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&Code.eval_string(&1) |> elem(0))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
use Bitwise
defmodule AdventOfCode do
def solve(input) do
Enum.flat_map(Enum.with_index(input), fn {outer_elm, outer_i} ->
for {inner_elm, inner_i} <- Enum.with_index(input), outer_i != inner_i do
[outer_elm, inner_elm]
end
end)
|> Enum.map(fn entry ->
Stream.unfold({:explode, entry}, fn
nil -> nil
{:explode, current} -> case explode(current) do
{0, _, _, res} -> {nil, {:split, res}}
{_, _, _, res} -> {nil, {:explode, res}}
end
{:split, current} -> case split(current) do
{true, res} -> {nil, {:explode, res}}
{_, res} -> {res, nil}
end
end)
|> Enum.at(-1)
|> magnitude
end)
|> Enum.max
end
defp explode(input, depth \\ 0)
defp explode(a, _) when is_number(a), do: {0, nil, nil, a}
defp explode([a, b], 4) when is_number(a) and is_number(b), do: {7, a, b, 0}
defp explode([a, b], _) when is_number(a) and is_number(b), do: {0, a, b, [a, b]}
defp explode([a, b], depth) do
with {:a, {0, _, _, a}} <- {:a, explode(a, depth + 1)},
{:b, {0, _, _, b}} <- {:b, explode(b, depth + 1)} do
{0, nil, nil, [a, b]}
else
{:a, {n, v1, v2, a}} when (n &&& 4) > 0 -> {n - 4, v1, v2, [a, add_to_outermost(b, :left, v2)]}
{:a, {n, v1, v2, a}} -> {n, v1, v2, [a, b]}
{:b, {n, v1, v2, b}} when (n &&& 2) > 0 -> {n - 2, v1, v2, [add_to_outermost(a, :right, v1), b]}
{:b, {n, v1, v2, b}} -> {n, v1, v2, [a, b]}
end
end
defp split(n) when is_number(n) and n >= 10, do: {true, [div(n, 2), n - div(n, 2)]}
defp split(n) when is_number(n), do: {false, n}
defp split([a, b]) do
with {:a, {false, a}} <- {:a, split(a)},
{:b, {false, b}} <- {:b, split(b)} do
{false, [a, b]}
else
{:a, {_, a}} -> {true, [a, b]}
{:b, {_, b}} -> {true, [a, b]}
end
end
defp magnitude(n) when is_number(n), do: n
defp magnitude([a, b]), do: 3 * magnitude(a) + 2 * magnitude(b)
defp add_to_outermost(a, _, val) when is_number(a), do: a + val
defp add_to_outermost([a, b], :left, val), do: [add_to_outermost(a, :left, val), b]
defp add_to_outermost([a, b], :right, val), do: [a, add_to_outermost(b, :right, val)]
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&Code.eval_string(&1) |> elem(0))
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
[basis | others] = generate_candidates(input)
Stream.unfold({MapSet.new([basis.name]), %{basis.name => %{position: {0,0,0}, beacons: MapSet.new(basis.beacons)}}}, fn
nil -> nil
{%{map: m}, tbm} when map_size(m) == length(input) -> {tbm, nil}
{used_scanners, transformed_beacon_map} ->
[unknown, known] = Enum.reject(others, &MapSet.member?(used_scanners, &1.name))
|> Enum.find_value(fn scanner ->
known_candidate = Enum.find(scanner.candidates, &MapSet.member?(used_scanners, &1.name))
if known_candidate, do: [scanner, known_candidate], else: nil
end)
known_beacons = Map.fetch!(transformed_beacon_map, known.name).beacons
Enum.map(unknown.beacons, &generate_rotations/1)
|> Enum.zip
|> Enum.map(&Tuple.to_list/1)
|> Enum.find_value(fn points ->
foreach_pair(MapSet.to_list(known_beacons), points, &Enum.find_value/2, fn {k_x, k_y, k_z}, {x, y, z} ->
{t_x, t_y, t_z} = {x - k_x, y - k_y, z - k_z}
transformed_points = MapSet.new(Enum.map(points, fn {p_x, p_y, p_z} -> {p_x - t_x, p_y - t_y, p_z - t_z} end))
MapSet.intersection(known_beacons, transformed_points)
|> MapSet.size
|> then(&if &1 >= 12, do: {{t_x, t_y, t_z}, transformed_points}, else: nil)
end)
end)
|> then(fn {{t_x, t_y, t_z}, points} ->
{nil, {MapSet.put(used_scanners, unknown.name), Map.put(transformed_beacon_map, unknown.name, %{position: {-t_x, -t_y, -t_z}, beacons: points})}}
end)
end)
|> Enum.at(-1)
|> Enum.reduce(MapSet.new, fn {_, v}, acc -> MapSet.union(acc, v.beacons) end)
|> MapSet.size
end
defp generate_candidates(input) do
scanners = Enum.map(input, fn scanner ->
foreach_pair(scanner.beacons, scanner.beacons, &Enum.map/2, &distance/2)
|> List.flatten
|> Enum.reject(&(&1 == 0))
|> MapSet.new
|> then(&Map.put(scanner, :distances, &1))
end)
Enum.map(scanners, fn s1 ->
Enum.filter(scanners, fn s2 -> s1.name != s2.name and MapSet.size(MapSet.intersection(s1.distances, s2.distances)) >= 66 end)
|> then(&Map.put(s1, :candidates, &1))
end)
end
defp distance({x1, y1, z1}, {x2, y2, z2}), do: abs(x1 - x2) + abs(y1 - y2) + abs(z1 - z2)
defp foreach_pair(set1, set2, enum, func) do
enum.(set1, fn s1 -> enum.(set2, &func.(s1, &1)) end)
end
defp generate_rotations(p) do
roll = fn {a, b, c} -> {a, c, -b} end
turn = fn {a, b, c} -> {-b, a, c} end
Enum.scan(0..23, p, fn i, acc ->
acc
|> then(&(if i == 12, do: roll.(turn.(roll.(&1))), else: &1))
|> then(&(if rem(i, 4) == 0, do: roll.(&1), else: turn.(&1)))
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n\n", trim: true)
|> Enum.map(fn scanner ->
[name | coords] = String.split(scanner, "\n", trim: true)
Enum.map(coords, fn l -> String.split(l, ",", trim: true) |> Enum.map(&String.to_integer/1) |> List.to_tuple end)
|> then(&%{name: name, beacons: &1})
end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
[basis | others] = generate_candidates(input)
Stream.unfold({MapSet.new([basis.name]), %{basis.name => %{position: {0,0,0}, beacons: MapSet.new(basis.beacons)}}}, fn
nil -> nil
{%{map: m}, tbm} when map_size(m) == length(input) -> {tbm, nil}
{used_scanners, transformed_beacon_map} ->
[unknown, known] = Enum.reject(others, &MapSet.member?(used_scanners, &1.name))
|> Enum.find_value(fn scanner ->
known_candidate = Enum.find(scanner.candidates, &MapSet.member?(used_scanners, &1.name))
if known_candidate, do: [scanner, known_candidate], else: nil
end)
known_beacons = Map.fetch!(transformed_beacon_map, known.name).beacons
Enum.map(unknown.beacons, &generate_rotations/1)
|> Enum.zip
|> Enum.map(&Tuple.to_list/1)
|> Enum.find_value(fn points ->
foreach_pair(MapSet.to_list(known_beacons), points, &Enum.find_value/2, fn {k_x, k_y, k_z}, {x, y, z} ->
{t_x, t_y, t_z} = {x - k_x, y - k_y, z - k_z}
transformed_points = MapSet.new(Enum.map(points, fn {p_x, p_y, p_z} -> {p_x - t_x, p_y - t_y, p_z - t_z} end))
MapSet.intersection(known_beacons, transformed_points)
|> MapSet.size
|> then(&if &1 >= 12, do: {{t_x, t_y, t_z}, transformed_points}, else: nil)
end)
end)
|> then(fn {{t_x, t_y, t_z}, points} ->
{nil, {MapSet.put(used_scanners, unknown.name), Map.put(transformed_beacon_map, unknown.name, %{position: {-t_x, -t_y, -t_z}, beacons: points})}}
end)
end)
|> Enum.at(-1)
|> Map.values
|> Enum.map(&(&1.position))
|> then(fn vals -> foreach_pair(vals, vals, &Enum.map/2, &distance/2) end)
|> List.flatten
|> Enum.max
end
defp generate_candidates(input) do
scanners = Enum.map(input, fn scanner ->
foreach_pair(scanner.beacons, scanner.beacons, &Enum.map/2, &distance/2)
|> List.flatten
|> Enum.reject(&(&1 == 0))
|> MapSet.new
|> then(&Map.put(scanner, :distances, &1))
end)
Enum.map(scanners, fn s1 ->
Enum.filter(scanners, fn s2 -> s1.name != s2.name and MapSet.size(MapSet.intersection(s1.distances, s2.distances)) >= 66 end)
|> then(&Map.put(s1, :candidates, &1))
end)
end
defp distance({x1, y1, z1}, {x2, y2, z2}), do: abs(x1 - x2) + abs(y1 - y2) + abs(z1 - z2)
defp foreach_pair(set1, set2, enum, func) do
enum.(set1, fn s1 -> enum.(set2, &func.(s1, &1)) end)
end
defp generate_rotations(p) do
roll = fn {a, b, c} -> {a, c, -b} end
turn = fn {a, b, c} -> {-b, a, c} end
Enum.scan(0..23, p, fn i, acc ->
acc
|> then(&(if i == 12, do: roll.(turn.(roll.(&1))), else: &1))
|> then(&(if rem(i, 4) == 0, do: roll.(&1), else: turn.(&1)))
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n\n", trim: true)
|> Enum.map(fn scanner ->
[name | coords] = String.split(scanner, "\n", trim: true)
Enum.map(coords, fn l -> String.split(l, ",", trim: true) |> Enum.map(&String.to_integer/1) |> List.to_tuple end)
|> then(&%{name: name, beacons: &1})
end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input, runs, border \\ ".")
def solve({_, image}, 0, _), do: List.flatten(image) |> Enum.count(&(&1 == "#"))
def solve({algo_map, image}, runs, border) do
width = length(Enum.at(image, 0))
top_border_row = List.duplicate(border, width + 4)
Enum.map(image, &([border, border] ++ &1 ++ [border, border]))
|> then(&(List.duplicate(top_border_row, 2) ++ &1 ++ List.duplicate(top_border_row, 2)))
|> Enum.map(&Enum.chunk_every(&1, 3, 1, :discard))
|> Enum.zip
|> Enum.map(&Tuple.to_list(&1) |> Enum.chunk_every(3, 1, :discard))
|> Enum.zip
|> Enum.map(&Tuple.to_list/1)
|> Enum.reduce([], fn row, acc ->
Enum.map(row, fn entry ->
List.flatten(entry)
|> Enum.map(&(if &1 == ".", do: 0, else: 1))
|> Integer.undigits(2)
|> then(&Map.fetch!(algo_map, &1))
end)
|> then(&[&1 | acc])
end)
|> Enum.reverse
|> then(&solve({algo_map, &1}, runs - 1, (if border == ".", do: algo_map[0], else: algo_map[511])))
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n\n", trim: true)
|> then(fn [algo, image] ->
algo_map = String.split(algo, "", trim: true)
|> Enum.with_index
|> Enum.into(%{}, fn {k, v} -> {v, k} end)
input_image = String.split(image, "\n", trim: true)
|> Enum.map(&String.graphemes/1)
{algo_map, input_image}
end)
|> AdventOfCode.solve(2)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input, runs, border \\ ".")
def solve({_, image}, 0, _), do: List.flatten(image) |> Enum.count(&(&1 == "#"))
def solve({algo_map, image}, runs, border) do
top_border_row = List.duplicate(border, length(Enum.at(image, 0)) + 4)
Enum.map(image, &([border, border] ++ &1 ++ [border, border]))
|> then(&(List.duplicate(top_border_row, 2) ++ &1 ++ List.duplicate(top_border_row, 2)))
|> Enum.map(&Enum.chunk_every(&1, 3, 1, :discard))
|> Enum.zip
|> Enum.map(&Tuple.to_list(&1) |> Enum.chunk_every(3, 1, :discard))
|> Enum.zip
|> Enum.map(&Tuple.to_list/1)
|> Enum.reduce([], fn row, acc ->
Enum.map(row, fn entry ->
List.flatten(entry)
|> Enum.map(&(if &1 == ".", do: 0, else: 1))
|> Integer.undigits(2)
|> then(&Map.fetch!(algo_map, &1))
end)
|> then(&[&1 | acc])
end)
|> Enum.reverse
|> then(&solve({algo_map, &1}, runs - 1, (if border == ".", do: algo_map[0], else: algo_map[511])))
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n\n", trim: true)
|> then(fn [algo, image] ->
input_image = String.split(image, "\n", trim: true) |> Enum.map(&String.graphemes/1)
algo_map = for {v, i} <- Enum.with_index(String.graphemes(algo)), into: %{} do
{i, v}
end
{algo_map, input_image}
end)
|> AdventOfCode.solve(50)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
score_stream = Stream.cycle(1..10)
Stream.cycle(1..100)
|> Stream.chunk_every(3)
|> then(fn stream ->
Enum.with_index(input)
|> Enum.map(fn {start, i} -> {start, Stream.drop(stream, i) |> Stream.take_every(2)} end)
end)
|> Enum.map(fn {start, stream} ->
Stream.transform(stream, {0, start}, fn roll, {score, position} ->
if score >= 1000 do
{:halt, {score, position}}
else
new_position = Enum.at(score_stream, Enum.sum(roll) + position - 1)
new_score = score + new_position
{[new_score], {new_score, new_position}}
end
end)
|> Enum.to_list
end)
|> Enum.with_index
|> Enum.map(fn {r, i} -> {i, i + length(r), r} end)
|> then(fn results ->
{winning_position, total_turns, _} = Enum.min_by(results, &elem(&1, 1))
rolls_and_scores = Enum.map(results, fn {i, _, r} ->
player_turns = if i <= winning_position, do: total_turns, else: total_turns - 1
{player_turns, Enum.at(r, player_turns - 1)}
end)
3 * Enum.sum(Enum.map(rolls_and_scores, &elem(&1, 0))) * elem(Enum.min_by(rolls_and_scores, &elem(&1, 1)), 1)
end)
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&String.split(&1, " ", trim: true) |> Enum.at(-1) |> String.to_integer)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
@winning_score 21
def solve([p1, p2]) do
initial_state = {{0, p1}, {0, p2}}
permutations(Enum.to_list(1..3), 3)
|> Enum.map(&Enum.sum/1)
|> Enum.frequencies
|> then(&build_map(initial_state, &1, %{}))
|> Map.fetch!(initial_state)
|> Tuple.to_list
|> Enum.max
end
defp build_map({{s, _}, _} = state, _, acc) when s >= @winning_score, do: Map.put(acc, state, {1, 0})
defp build_map({_, {s, _}} = state, _, acc) when s >= @winning_score, do: Map.put(acc, state, {0, 1})
defp build_map({{s1, p1}, state2} = game_state, roll_map, acc) do
if !Map.has_key?(acc, game_state) do
score_stream = Stream.cycle(1..10)
Enum.map(Map.keys(roll_map), fn roll ->
new_position = Enum.at(score_stream, roll + p1 - 1)
{roll, {state2, {new_position + s1, new_position}}}
end)
|> Enum.reduce({{0, 0}, acc}, fn {roll, state}, {{p1, p2}, next_acc} ->
next_map = build_map(state, roll_map, next_acc)
{p2_next, p1_next} = Map.fetch!(next_map, state)
roll_multiplier = Map.fetch!(roll_map, roll)
{{p1 + p1_next * roll_multiplier, p2 + p2_next * roll_multiplier}, next_map}
end)
|> then(fn {res, next_map} -> Map.put(next_map, game_state, res) end)
else
acc
end
end
defp permutations(l, i) when i == 0 or length(l) == 0, do: [[]]
defp permutations(l, i) do
for x <- l, y <- permutations(l, i - 1), do: [x|y]
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&String.split(&1, " ", trim: true) |> Enum.at(-1) |> String.to_integer)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
constraint = Range.new(-50, 50)
Enum.reject(input, fn {_, {x, y, z}} -> Enum.any?([x,y,z], &Range.disjoint?(constraint, &1)) end)
|> Enum.reduce(MapSet.new, fn {type, {x_r, y_r, z_r}}, acc ->
for x <- x_r, y <- y_r, z <- z_r, reduce: acc do
n -> if type == "on", do: MapSet.put(n, {x,y,z}), else: MapSet.delete(n, {x,y,z})
end
end)
|> MapSet.size
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&String.split(&1, " ", trim: true))
|> Enum.map(fn [type, contents] ->
String.split(contents, ",", trim: true)
|> Enum.map(&String.split(&1, ".."))
|> List.flatten
|> Enum.map(&String.replace(&1, ~r/[^0-9\-]/, "") |> String.to_integer)
|> Enum.chunk_every(2)
|> Enum.map(fn [a, b] -> Range.new(a, b) end)
|> then(&{type, List.to_tuple(&1)})
end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
Enum.with_index(input)
|> Enum.filter(fn {r, _} -> elem(r, 0) == "on" end)
|> Enum.map(fn {r, i} ->
Enum.drop(input, i + 1)
|> Enum.filter(&(overlaps?(elem(r, 1), elem(&1, 1))))
|> Enum.map(&elem(&1, 1))
|> then(&{elem(r, 1), &1})
end)
|> Enum.map(fn {start, remove} ->
Enum.reduce(remove, [start], fn range, acc ->
Enum.flat_map(acc, &remove_intersection(&1, range))
end)
end)
|> List.flatten
|> Enum.map(fn r -> Tuple.to_list(r) |> Enum.map(&Range.size/1) |> Enum.product end)
|> Enum.sum
end
def remove_intersection({x_a, y_a, _} = a, b) do
if overlaps?(a, b) do
res = run_on_all(a, b, &find_range_overlap/2)
[x_s, y_s, z_s] = run_on_all(a, List.to_tuple(res), &remove_range_intersection/2)
Enum.with_index([x_s, y_s])
|> Enum.map(fn {v, i} -> [elem(b, i) | v] end)
|> then(&(&1 ++ [[Enum.at(res, 2)]]))
|> Enum.reduce([{}], fn l, acc ->
Enum.flat_map(l, fn entry -> Enum.map(acc, &Tuple.append(&1, entry)) end)
end)
|> then(fn r -> r ++ Enum.map(z_s, &{x_a, y_a, &1}) end)
|> Enum.map(fn r -> run_on_all(r, a, &find_range_overlap/2) |> List.to_tuple end)
|> Enum.reject(&(&1 == b or fully_covered?(&1, b)))
else
[a]
end
end
def overlaps?(a, b), do: !Enum.any?(run_on_all(a, b, &Range.disjoint?/2))
def fully_covered?(a, b) do
Enum.map([a, b], fn elm -> Tuple.to_list(elm) |> Enum.map(&Enum.min_max/1) end)
|> Enum.zip
|> Enum.all?(fn {{a1, a2}, {b1, b2}} -> b1 <= a1 and b2 >= a2 end)
end
def run_on_all(a, b, func), do: Enum.map([a, b], &Tuple.to_list/1) |> Enum.zip |> Enum.map(fn {x, y} -> func.(x, y) end)
def find_range_overlap(r1, r2) do
{min_1, max_1} = Enum.min_max(r1)
{min_2, max_2} = Enum.min_max(r2)
Range.new(Enum.max([min_1, min_2]), Enum.min([max_1, max_2]))
end
def remove_range_intersection(r1, r2) do
{min_1, max_1} = Enum.min_max(r1)
{min_2, max_2} = Enum.min_max(r2)
cond do
min_1 == min_2 and max_1 == max_2 -> []
min_1 < min_2 and max_1 > max_2 -> [Range.new(min_1, min_2 - 1), Range.new(max_2 + 1, max_1)]
min_1 < min_2 -> [Range.new(min_1, min_2 - 1)]
true -> [Range.new(max_2 + 1, max_1)]
end
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&String.split(&1, " ", trim: true))
|> Enum.map(fn [type, contents] ->
String.split(contents, ",", trim: true)
|> Enum.map(&String.split(&1, ".."))
|> List.flatten
|> Enum.map(&String.replace(&1, ~r/[^0-9\-]/, "") |> String.to_integer)
|> Enum.chunk_every(2)
|> Enum.map(fn [a, b] -> Range.new(a, b) end)
|> then(&{type, List.to_tuple(&1)})
end)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
@effective_infinity 99999999999999999999999
@movement_multiplier %{?A => 1, ?B => 10, ?C => 100, ?D => 1000}
@room_to_index %{?A => 2, ?B => 4, ?C => 6, ?D => 8}
def solve(input, room_size, acc \\ %{}) do
if Map.has_key?(acc, input) do
{Map.get(acc, input), [], acc}
else
possible_moves = next_moves(input, room_size)
winning_move = Enum.find(possible_moves, fn {_, {_, rooms}} -> complete?(rooms, room_size) end)
if winning_move do
{move, board} = winning_move
{elem(move, 0), [board], Map.put(acc, board, elem(move, 0))}
else
non_looping_moves = Enum.reject(possible_moves, &(Map.has_key?(acc, elem(&1, 1)) and is_nil(Map.get(acc, elem(&1, 1)))))
if length(non_looping_moves) == 0 do
{@effective_infinity, [], Map.put(acc, input, @effective_infinity)}
else
Enum.reduce(non_looping_moves, {[], acc}, fn {move, board}, {res, next_acc} ->
{cost, moves, result_acc} = solve(board, room_size, next_acc)
{[{move, board, {cost, moves, result_acc}} | res], result_acc}
end)
|> then(fn {results, next_acc} ->
{move, board, {cost, all_boards, _}} = Enum.min_by(results, fn {move, _, {cost, _, _}} ->
elem(move, 0) + cost
end)
total_cost = if cost >= @effective_infinity, do: @effective_infinity, else: elem(move, 0) + cost
{total_cost, [board | all_boards], Map.put(next_acc, input, total_cost)}
end)
end
end
end
end
def next_moves({hallway, rooms}, room_size) do
room_indexes = Map.values(@room_to_index)
open_hallway_ranges = Enum.with_index(hallway)
|> Enum.reduce({-1, []}, fn {v, i}, {left, acc} ->
cond do
left == -1 and v == ?. -> {i, acc}
left == -1 -> {-1, acc}
i == (length(hallway) - 1) -> {nil, [Range.new(left, i) | acc]}
v != ?. -> {-1, [Range.new(left, i - 1) | acc]}
true -> {left, acc}
end
end)
|> then(&Enum.reverse(elem(&1, 1)))
room_to_hallway_or_room_moves = Enum.with_index(rooms)
|> Enum.filter(fn {r, i} ->
length(r) > 0 and Enum.any?(r, &(&1 != (?A + i)))
end)
|> Enum.flat_map(fn {[hd | tl] = room, i} ->
index_outside_room = 2 + 2 * i
if Enum.at(hallway, index_outside_room) != ?. do
[]
else
start_point = {index_outside_room, room_size - length(room) + 1}
target_room_index = abs(?A - hd)
target_room = Enum.at(rooms, target_room_index)
target_room_hallway_index = 2 + 2 * target_room_index
target_all_correct = Enum.all?(target_room, &(&1 == hd))
Enum.filter(open_hallway_ranges, &((index_outside_room + 1) in &1 or (index_outside_room - 1) in &1))
|> Enum.uniq
|> Enum.flat_map(fn range ->
if length(target_room) < room_size and target_room_hallway_index in range and target_all_correct do
end_point = {target_room_hallway_index, room_size - length(target_room)}
distance = room_size - length(room) + 1 + abs(target_room_hallway_index - index_outside_room) + room_size - length(target_room)
next_state = {hallway, List.replace_at(List.replace_at(rooms, i, tl), target_room_index, [hd | target_room])}
[{{distance * @movement_multiplier[hd], hd, start_point, end_point}, next_state}]
else
Enum.reject(range, &(&1 in room_indexes))
|> Enum.map(fn destination ->
#IO.inspect(destination, label: "Destination")
end_point = {destination, 0}
distance = manhattan_distance(start_point, end_point)
next_state = {List.replace_at(hallway, destination, hd), List.replace_at(rooms, i, tl)}
{{distance * @movement_multiplier[hd], hd, start_point, end_point}, next_state}
end)
end
end)
end
end)
hallway_to_room_moves = Enum.with_index(hallway)
|> Enum.filter(fn {v, _} -> v != ?. and Enum.all?(Enum.at(rooms, abs(?A - v)), &(&1 == v)) end)
|> Enum.filter(fn {v, i} ->
Enum.any?(open_hallway_ranges, &(((i+1) in &1 or (i-1) in &1) and @room_to_index[v] in &1))
end)
|> Enum.map(fn {v, i} ->
target_room = Enum.at(rooms, abs(?A - v))
start_point = {i, 0}
end_point = {@room_to_index[v], room_size - length(target_room)}
distance = manhattan_distance(start_point, end_point)
next_state = {List.replace_at(hallway, i, ?.), List.replace_at(rooms, abs(?A - v), [v | target_room])}
{{distance * @movement_multiplier[v], v, start_point, end_point}, next_state}
end)
room_to_hallway_or_room_moves ++ hallway_to_room_moves
end
def complete?(rooms, room_size), do: Enum.all?(Enum.with_index(rooms), fn {r, i} -> length(r) == room_size && Enum.all?(r, &(&1 == (?A + i))) end)
def manhattan_distance({x1, y1}, {x2, y2}), do: abs(x2 - x1) + abs(y2 - y1)
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> then(&Enum.slice(&1, 1, length(&1) - 2))
|> then(fn [hallway | rooms] ->
Enum.map(rooms, &String.trim(&1) |> String.split("#", trim: true))
|> Enum.zip
|> Enum.map(&(Tuple.to_list(&1) |> List.to_charlist))
|> then(fn r -> {Enum.filter(String.to_charlist(hallway), &(&1 == ?.)), r} end)
end)
|> AdventOfCode.solve(4)
|> elem(0)
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(instruction_sets) do
Enum.with_index(instruction_sets)
|> Enum.reduce({[], []}, fn {instruction_set, i}, {res, acc} ->
is_pop = Enum.any?(instruction_set, &(&1 == {"div", "z", 26}))
if is_pop do
{_, _, val} = Enum.at(instruction_set, 5)
[var, init] = hd(acc)
[left, right, digit] = if (init + val) < 0 do
[var, i, abs(init + val)]
else
[i, var, init + val]
end
{[{left, 9}, {right, 9 - digit} | res], tl(acc)}
else
{_, _, val} = Enum.at(instruction_set, 15)
{res, [[i, val] | acc]}
end
end)
|> elem(0)
|> Enum.sort_by(&elem(&1, 0))
|> Enum.map(&elem(&1, 1))
|> Enum.join("")
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(fn line ->
String.split(line, " ", trim: true)
|> Enum.map(&(if Regex.match?(~r/[\-0-9]+/, &1), do: String.to_integer(&1), else: &1))
|> List.to_tuple
end)
|> Enum.chunk_by(fn x -> elem(x, 0) == "inp" end)
|> Enum.chunk_every(2, 2, :discard)
|> Enum.map(&List.flatten/1)
|> AdventOfCode.solve
#|> AdventOfCode.find_dependencies_and_outputs
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(instruction_sets) do
Enum.with_index(instruction_sets)
|> Enum.reduce({[], []}, fn {instruction_set, i}, {res, acc} ->
is_pop = Enum.any?(instruction_set, &(&1 == {"div", "z", 26}))
if is_pop do
{_, _, val} = Enum.at(instruction_set, 5)
[var, init] = hd(acc)
[left, right, digit] = if (init + val) < 0 do
[var, i, abs(init + val)]
else
[i, var, init + val]
end
{[{left, 1 + digit}, {right, 1} | res], tl(acc)}
else
{_, _, val} = Enum.at(instruction_set, 15)
{res, [[i, val] | acc]}
end
end)
|> elem(0)
|> Enum.sort_by(&elem(&1, 0))
|> Enum.map(&elem(&1, 1))
|> Enum.join("")
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(fn line ->
String.split(line, " ", trim: true)
|> Enum.map(&(if Regex.match?(~r/[\-0-9]+/, &1), do: String.to_integer(&1), else: &1))
|> List.to_tuple
end)
|> Enum.chunk_by(fn x -> elem(x, 0) == "inp" end)
|> Enum.chunk_every(2, 2, :discard)
|> Enum.map(&List.flatten/1)
|> AdventOfCode.solve
#|> AdventOfCode.find_dependencies_and_outputs
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end
defmodule AdventOfCode do
def solve(input) do
width = length(Enum.at(input, 0))
height = length(input)
Enum.with_index(input)
|> Enum.reduce(%{}, fn {row, y}, acc ->
Enum.reduce(Enum.with_index(row), acc, fn {val, x}, inner_acc ->
if val != ".", do: Map.put(inner_acc, {x, y}, val), else: inner_acc
end)
end)
|> Stream.unfold(fn
nil -> nil
map ->
{east, south} = Enum.group_by(map, &elem(&1, 1)) |> then(fn x -> {Enum.into(x[">"], %{}), Enum.into(x["v"], %{})} end)
{east_moves, east_stationary} = Map.keys(east)
|> Enum.group_by(fn {x, y} -> Map.has_key?(map, {rem(x+1, width), y}) end)
|> then(&{MapSet.new(Enum.map(Map.get(&1, false, []), fn {x, y} -> {rem(x+1, width), y} end)), MapSet.new(Map.get(&1, true, []))})
{south_moves, south_stationary} = Map.keys(south)
|> Enum.group_by(fn {x, y} ->
result_key = {x, rem(y + 1, height)}
Map.has_key?(south, result_key) or MapSet.member?(east_moves, result_key) or MapSet.member?(east_stationary, result_key)
end)
|> then(&{MapSet.new(Enum.map(Map.get(&1, false, []), fn {x, y} -> {x, rem(y+1, height)} end)), MapSet.new(Map.get(&1, true, []))})
if (MapSet.size(east_moves) + MapSet.size(south_moves)) == 0 do
{1, nil}
else
east_result = Enum.reduce(MapSet.union(east_moves, east_stationary), %{}, &Map.put(&2, &1, ">"))
south_result = Enum.reduce(MapSet.union(south_moves, south_stationary), %{}, &Map.put(&2, &1, "v"))
{1, Map.merge(east_result, south_result)}
end
end)
|> Enum.sum
end
end
with {:ok, contents} <- File.read('advent-of-code-input.txt') do
String.split(contents, "\n", trim: true)
|> Enum.map(&String.graphemes/1)
|> AdventOfCode.solve
|> IO.inspect(label: "Answer")
else
_ -> IO.inspect("Failed to read input file")
end