AOC 2024
AOC helper
defmodule AOCHelper do
def to_int_list(txt_file) do
txt_file
|> File.read!()
|> String.split("\n", trim: true)
|> Enum.map(fn list ->
String.split(list) |> Enum.map(&String.to_integer/1)
end)
end
end
# defmodule Day do
# @file_path "/Users/leizhou/Dev/learn_x/aoc/2024/day.txt"
# def part1 do
# end
# def part2 do
# end
# end
# IO.inspect(%{day_part1: Day.part1()})
# IO.inspect(%{day_part2: Day.part2()})
Day 1
day1_file = "/Users/leizhou/Dev/learn_x/aoc/2024/day1.txt"
[group_1, group_2] =
day1_file
|> AOCHelper.to_int_list()
|> Enum.reduce([[], []], fn [num1, num2], [group1, group2] ->
[[num1 | group1], [num2 | group2]]
end)
|> Enum.map(&Enum.sort/1)
[group_1, group_2]
|> Enum.zip()
|> Enum.reduce(0, fn elements, acc ->
acc + abs(elem(elements, 0) - elem(elements, 1))
end)
|> IO.inspect(label: "day1 part1")
count_map = Enum.frequencies(group_2)
Enum.reduce(group_1, 0, fn num, acc ->
acc + num * Map.get(count_map, num, 0)
end)
|> IO.inspect(label: "day1 part2")
Day 2
# part 2
defmodule Day2 do
@file_path "/Users/leizhou/Dev/learn_x/aoc/2024/day2.txt"
def check_sign(list), do: Enum.all?(list, fn x -> x >= 0 end) or Enum.all?(list, fn x -> x <= 0 end)
def check_abs(list), do: Enum.all?(list, fn x -> abs(x) >= 1 and abs(x) <= 3 end)
def check_cond(list), do: check_sign(list) and check_abs(list)
def diff_report(list) do
Enum.reduce(Enum.zip([list, tl(list)]), [], fn {prev, current}, acc ->
[current - prev | acc]
end)
end
def part1_check(list) do
list
|> diff_report()
|> check_cond()
end
def part1() do
@file_path
|> AOCHelper.to_int_list()
|> Enum.map(fn list ->
part1_check(list)
end)
|> Enum.frequencies()
end
def part2_check(list) do
1..length(list)
|> Enum.map(fn index ->
List.delete_at(list, index - 1)
|> part1_check()
end)
|> Enum.any?()
end
def part2() do
@file_path
|> AOCHelper.to_int_list()
|> Enum.map(fn list ->
part2_check(list)
end)
|> Enum.frequencies()
end
end
%{day2_part1: Day2.part1(), day2_part2: Day2.part2()}
Day 3
defmodule Day3 do
@file_path "/Users/leizhou/Dev/learn_x/aoc/2024/day3.txt"
def part1 do
@file_path
|> File.read!()
|> then(fn string -> Regex.scan(~r/mul\((?<num1>\d{1,3}),(?<num2>\d{1,3})\)/, string) end)
|> Enum.reduce(0, fn [_, num_string1, num_string2], acc ->
acc + String.to_integer(num_string1) * String.to_integer(num_string2)
end)
end
def make_instruct_map(text) do
map_do =
Regex.scan(~r/do\(\)/, text, return: :index)
|> Enum.reduce(%{}, fn [{index, _}], acc ->
Map.put(acc, index, 1)
end)
map_not =
Regex.scan(~r/don't\(\)/, text, return: :index)
|> Enum.reduce(%{}, fn [{index, _}], acc ->
Map.put(acc, index, 0)
end)
Map.merge(map_do, map_not) |> Map.put(0, 1)
end
def make_instruct_index_list(map_instruct) do
Map.keys(map_instruct) |> Enum.sort()
end
def make_mul_index_list(text) do
text
|> then(fn string ->
Regex.scan(~r/mul\((?<num1>\d{1,3}),(?<num2>\d{1,3})\)/, string, return: :index)
end)
|> Enum.reduce([], fn [{index, _}, _, _], acc ->
[index | acc]
end)
|> Enum.reverse()
end
def make_mul_number_list(text) do
text
|> then(fn string -> Regex.scan(~r/mul\((?<num1>\d{1,3}),(?<num2>\d{1,3})\)/, string) end)
|> Enum.reduce([], fn [_, num_string1, num_string2], acc ->
[String.to_integer(num_string1) * String.to_integer(num_string2) | acc]
end)
|> Enum.reverse()
end
def make_instuct_ind_list(mul_index_list, list_instruct_index, map_instruct) do
mul_index_list
|> Enum.map(fn index ->
Enum.reduce_while(list_instruct_index, nil, fn instruct_index, acc ->
if index - instruct_index > 0, do: {:cont, instruct_index}, else: {:halt, acc}
end)
|> then(fn index -> Map.get(map_instruct, index) end)
end)
end
def calculate_sum(instruct_ind_list, mul_number_list) do
Enum.zip(instruct_ind_list, mul_number_list)
|> Enum.reduce(0, fn {ind, num}, acc ->
acc + ind * num
end)
end
def process_text(text) do
[make_instruct_map(text), make_mul_index_list(text), make_mul_number_list(text)]
end
def part2 do
text = File.read!(@file_path)
[map_instruct, mul_index_list, mul_number_list] = process_text(text)
list_instruct_index = make_instruct_index_list(map_instruct)
instruct_ind_list = make_instuct_ind_list(mul_index_list, list_instruct_index, map_instruct)
calculate_sum(instruct_ind_list, mul_number_list)
end
end
IO.inspect(%{day3_part1: Day3.part1()})
IO.inspect(%{day3_part2: Day3.part2()})
Day 4
defmodule Day4 do
@file_path "/Users/leizhou/Dev/learn_x/aoc/2024/day4.txt"
def to_mat(file_path) do
File.read!(file_path)
|> String.split("\n", trim: true)
|> Enum.map(&(String.split(&1, "", trim: true) |> List.to_tuple()))
|> List.to_tuple()
end
def mat_elem(mat, x, y) do
elem(elem(mat, x), y)
end
def to_four_letter(mat, x, y, :lr) do
0..3
|> Enum.reduce("", fn index, acc ->
acc <> mat_elem(mat, x, y + index)
end)
end
def to_four_letter(mat, x, y, :td) do
0..3
|> Enum.reduce("", fn index, acc ->
acc <> mat_elem(mat, x + index, y)
end)
end
def to_four_letter(mat, x, y, :nw_se) do
0..3
|> Enum.reduce("", fn index, acc ->
acc <> mat_elem(mat, x + index, y + index)
end)
end
def to_four_letter(mat, x, y, :sw_ne) do
0..3
|> Enum.reduce("", fn index, acc ->
acc <> mat_elem(mat, x - index, y + index)
end)
end
def to_xmas_ind(string) do
case string do
"XMAS" -> 1
"SAMX" -> 1
_ -> 0
end
end
def check_four_letter(mat, x, y, direction) do
to_four_letter(mat, x, y, direction) |> to_xmas_ind()
end
def count_row(mat, x) do
0..(tuple_size(elem(mat, x)) - 4)
|> Enum.map(fn index ->
check_four_letter(mat, x, index, :lr)
end)
|> Enum.sum()
end
def count_rows(mat) do
0..(tuple_size(mat) - 1)
|> Enum.reduce(0, fn x, acc ->
acc + count_row(mat, x)
end)
end
def count_column(mat, y) do
0..(tuple_size(mat) - 4)
|> Enum.map(fn index ->
check_four_letter(mat, index, y, :td)
end)
|> Enum.sum()
end
def count_columns(mat) do
0..(tuple_size(elem(mat, 0)) - 1)
|> Enum.reduce(0, fn y, acc ->
acc + count_column(mat, y)
end)
end
def count_nw_se(mat, x) when x <= tuple_size(mat) - 4 do
0..(tuple_size(elem(mat, x)) - 4)
|> Enum.map(fn index ->
check_four_letter(mat, x, index, :nw_se)
end)
|> Enum.sum()
end
def count_nw_se(_mat, _x), do: 0
def count_sw_ne(mat, x) when x >= 3 do
0..(tuple_size(elem(mat, x)) - 4)
|> Enum.map(fn index ->
check_four_letter(mat, x, index, :sw_ne)
end)
|> Enum.sum()
end
def count_sw_ne(_mat, _x), do: 0
def count_diags(mat) do
0..(tuple_size(mat) - 1)
|> Enum.reduce(0, fn x, acc ->
acc + count_nw_se(mat, x) + count_sw_ne(mat, x)
end)
end
def count_all(mat) do
count_rows(mat) + count_columns(mat) + count_diags(mat)
end
def part1() do
@file_path
|> to_mat()
|> count_all()
end
def to_mas_string(mat, x, y, :nw_se) do
-1..1
|> Enum.reduce("", fn index, acc ->
acc <> mat_elem(mat, x + index, y + index)
end)
end
def to_mas_string(mat, x, y, :sw_ne) do
-1..1
|> Enum.reduce("", fn index, acc ->
acc <> mat_elem(mat, x - index, y + index)
end)
end
def to_mas_ind(string) do
case string do
"MAS" -> 1
"SAM" -> 1
_ -> 0
end
end
def count_nw_se_mas(mat, x, y), do: to_mas_string(mat, x, y, :nw_se) |> to_mas_ind()
def count_sw_ne_mas(mat, x, y), do: to_mas_string(mat, x, y, :sw_ne) |> to_mas_ind()
def count_mas(mat, x, y), do: (if count_nw_se_mas(mat, x, y) + count_sw_ne_mas(mat, x, y) == 2, do: 1, else: 0)
def count_mas_all(mat) do
for x <- 1..(tuple_size(mat)-2), y <- 1..(tuple_size(elem(mat, 0))-2), reduce: 0 do
acc -> acc + count_mas(mat, x, y)
end
end
def part2 do
@file_path
|> to_mat()
|> count_mas_all()
end
end
IO.inspect(%{day4_part1: Day4.part1()})
IO.inspect(%{day4_part2: Day4.part2()})