Advent of Code 2024 Day 15 Part 1
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Get Inputs
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2024", "15", System.fetch_env!("LB_SESSION"))
My answer
small_sample_input =
"""
########
#..O.O.#
##@.O..#
#...O..#
#.#.O..#
#...O..#
#......#
########
<^^>>>vv>v<<
"""
|> String.trim()
parse_map = fn input ->
[map_rows, direction_rows] = String.split(input, "\n\n")
map =
map_rows
|> String.split("\n")
|> Enum.with_index()
|> Enum.flat_map(fn {row, row_index} ->
row
|> String.codepoints()
|> Enum.with_index()
|> Enum.map(fn {mark, col_index} ->
{{col_index, row_index}, mark}
end)
end)
|> Enum.into(%{})
directions =
direction_rows
|> String.replace("\n", "")
|> String.codepoints()
{map, directions}
end
{map, directions} = parse_map.(small_sample_input)
get_robot_point = fn map ->
map
|> Enum.find(fn {_, mark} -> mark == "@" end)
|> elem(0)
end
robot_point = get_robot_point.(map)
defmodule Robot do
def move({map, robot_point}, direction) do
moving_points = search_end_point(robot_point, direction, map, [])
end_point_mark = moving_points |> hd |> elem(1)
case end_point_mark do
"#" ->
{map, robot_point}
"." ->
{
go_next(robot_point, moving_points, map),
get_next_point(robot_point, direction)
}
end
end
defp go_next(robot_point, moving_points, map) do
moving_points
|> Enum.reverse()
|> Enum.with_index()
|> Enum.reduce(map, fn {moving_point, index}, acc_map ->
mark =
case index do
0 -> "@"
_ -> "O"
end
Map.put(acc_map, elem(moving_point, 0), mark)
end)
|> Map.put(robot_point, ".")
end
def search_end_point(robot_point, direction, map, acc) do
next_point = get_next_point(robot_point, direction)
next_point_mark = Map.get(map, next_point)
next_acc = [{next_point, next_point_mark} | acc]
case next_point_mark do
nil -> acc
"#" -> next_acc
"." -> next_acc
"O" -> search_end_point(next_point, direction, map, next_acc)
end
end
defp get_next_point({px, py}, direction) do
case direction do
"^" -> {px, py - 1}
"v" -> {px, py + 1}
"<" -> {px - 1, py}
">" -> {px + 1, py}
end
end
def get_map_size(map) do
{
map |> Enum.map(fn {{x, _}, _} -> x end) |> Enum.max() |> Kernel.+(1),
map |> Enum.map(fn {{_, y}, _} -> y end) |> Enum.max() |> Kernel.+(1)
}
end
def display_map(map, {tx, ty}) do
0..(ty - 1)
|> Enum.map(fn y ->
0..(tx - 1)
|> Enum.map(fn x ->
Map.get(map, {x, y})
end)
|> Enum.join()
end)
|> Enum.join("\n")
end
end
map_size = Robot.get_map_size(map)
map
|> Robot.display_map(map_size)
|> Kino.Text.new(terminal: true)
Robot.search_end_point({2, 2}, "<", map, [])
Robot.search_end_point({3, 2}, ">", map, [])
{map, robot_point}
|> Robot.move("^")
|> elem(0)
|> Robot.display_map(map_size)
|> Kino.Text.new(terminal: true)
{moved_map, _} =
directions
|> Enum.reduce({map, robot_point}, fn direction, {acc_map, acc_robot_point} ->
{acc_map, acc_robot_point} = Robot.move({acc_map, acc_robot_point}, direction)
IO.puts(direction)
acc_map |> Robot.display_map(map_size) |> IO.puts()
IO.puts("")
{acc_map, acc_robot_point}
end)
moved_map
|> Robot.display_map(map_size)
|> Kino.Text.new(terminal: true)
get_gps_coordinate = fn map ->
map
|> Enum.map(fn {{x, y}, mark} ->
case mark do
"O" -> x + y * 100
_ -> 0
end
end)
|> Enum.sum()
end
get_gps_coordinate.(moved_map)
{map, directions} =
"""
##########
#..O..O.O#
#......O.#
#.OO..O.O#
#..O@..O.#
#O#..O...#
#O..O..O.#
#.OO.O.OO#
#....O...#
##########
^v>^vv^v>v<>v^v<<><>>v^v^>^<<<><^
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<^<^^>>>^<>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^v^^<^^vv<
<>^^^^>>>v^<>vvv^>^^^vv^^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
^><^><>>><>^^<<^^v>>><^^>v>>>^v><>^v><<<>vvvv>^<><<>^><
^>><>^v<><^vvv<^^<><^v<<<><<<^^<^>>^<<<^>>^v^>>^v>vv>^<<^v<>><<><<>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
<><^^>^^^<>^vv<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
^^>vv<^v^v^<>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><
v^^>>><<^^<>>^v^v^<<>^<^v^v><^<<<><<^vv>>v>v^<<^
"""
|> String.trim()
|> parse_map.()
robot_point = get_robot_point.(map)
map_size = Robot.get_map_size(map)
{moved_map, _} =
directions
|> Enum.reduce({map, robot_point}, fn direction, {acc_map, acc_robot_point} ->
Robot.move({acc_map, acc_robot_point}, direction)
end)
moved_map
|> Robot.display_map(map_size)
|> Kino.Text.new(terminal: true)
get_gps_coordinate.(moved_map)
{map, directions} = parse_map.(puzzle_input)
robot_point = get_robot_point.(map)
map_size = Robot.get_map_size(map)
directions
|> Enum.reduce({map, robot_point}, fn direction, {acc_map, acc_robot_point} ->
Robot.move({acc_map, acc_robot_point}, direction)
end)
|> elem(0)
|> get_gps_coordinate.()