# Day 14 ```elixir Mix.install([:kino_aoc]) ``` ## Section ```elixir {:ok, puzzle_input} = KinoAOC.download_puzzle("2023", "14", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) ``` ``` {:ok, "####....#..O#O..#.....OO.O#..O.......O.#OO.#...O.O..O..O..OO.##.O#...........#....##O#..O#.O.O......\n....#..#.........O.O#..OO#OO....O.....#O.#.O##..#...OO#OOO.O...#...O..#.O.#....##.....#O............\n...#O..#........#....O...O.......O#.##.O.......O..O#O#.#OO....O..O.......#O.........#O.#.O...#...#..\n#O...O...O.O..O..OO.#...O.O#....##O.##..#.OOO#...OO.#...OOO.#.O.#....#....O..##.....OO....#..O...#O.\n.#.......##.#...#...O............O...#......#..#.OO...O#....O.#..........O..O.OOO#.#O#....OO..#.#O.#\n..#..........#..O.O#.....O.OOO.#.##...##...OO..#..#.O#..OO.O#..#O..#O.O#.O.O#..#.#OOO..#OO.O.##..#..\n#..#....O.#O.O.#...O......O...###O.#...OOO#..#.O..#O.O..O.#OO...O...#..#OOO.....O...O...OO..##....O.\n...##....#..#.O#..#O...#.#......##.OO.O.......O....#O#..OOOO#....O.#OO.#O....#...O#O#..O.#.....O....\n...#O....#.#O........O.O#O....O...#.O....#....#...#O.....O.O.O.#.#.......#.........#O#........O.....\n...O...#.O#....#O#O.....O..O#...#O........O.#.##.....O.#...O..#...##O.#.#O#..O..##......#O.#...O#..#\n#..OO#.#.........O#......#O.##.O#...O..#.#.#.OO........#......#....#..#.......O.#O.##.###.####....O.\nO..O...#O..O..##.O..............#O......OOO#...#.#.#.........OO....OO....O#.#.O#.O.........#.......O\n..O#.#....O..#....#OO..##...#..#...O..##O...##.O..O.OO.#.###...O..#.OO..O#...#......#.....O.#..O..#.\nO..####.O..O.OO##.O...O..O#.#O..O...O..........#O.#..#..O..O#..O##O.O.#O.#..O.OO.O..#...O.#O..O.O.#.\n.......O..........#...OO.O#.#.#OOOO...OO#O..O.#.#......#O.#.#...#.O#......O.O.OO...#.##..#.O.#..O..#\n.#.....#O........#.O...#........O............#O......##.O..O..#.#......O#O..O...O..O.#.O...O.#..OOOO\n.......O#...O...OO#.....#..O.#O..##..#O.#....OO.##.#O#......O#..O....OO..#...#O...O...##O..O###..OOO\n...O...#..O..O..#O.O......#.O...#..O#..#..O.OO...O....O.#O#..###O....O..##OOO.#O.....#...#.....#...O\nO...OO.#...#...O.O..#O.OO..O.#.#.#O#.O.#.O..O#O.....##O..O#.O..O........O...#.......O#.#...#.#..OO..\n..OO..#.#.O#.OOO.....##.O..OOO##O#.O..O.##OOO...O..##.O......#O.##..#O..O....#.##.O###...##..O......\n.......O..OO....##......O..O#O.O.O#....#O.....#....O..O.OO...#.O.#..#....#.O..#O....O......##O.....#\n......O..#...O..O#O.#.O.......#.O#.....O.O#..#.#...O..##......O.O..O#.#.#..#.O.#O.O#.O.#......#.O...\n....O.....O..O.......#.O.OO.....O##....##.#OO..#O..#.#...##..O#O.O...O..OO..##....O#O..O....#...O.#O\n.......O.##O.#O#.........O#.OO....###.OO..O.#..#.....OO.O.O...O......O..O..O....O...#.#....#....#O..\nO..#O......#.O..#O.O.#......O#..#.O##..#.#.O.....#.O...O..OO..####.#...##......#.....#O#......OO.O.#\n...OOO.#O....O#O...O.##OO..#....OO...O.#.....OO.#OOO.#.........#....O....#.#..O.#O#.#...O.O...O.#...\n..O.#.OOO..O.#...#OO.#.O.##OO..O..####.#....#.OO##O..#.O..O#..O#....#..O#..#.O.O..O...O...O.....O.O.\n.#.#O.O..#.O.O##.....O#..#..#..OO##...OOO.#O...#.O#...#O....#OO.OO..#.OO#.OO#O#............O......#.\nO#..#....O...#.#.O....#.OOO.#.OO.....OO###.O..#..#.O..#...#.#....O#.O#....#.#.O.#.....#....O.....O#.\nO..O.#.....#.....OOO..O..OOO.#..#.##.O..O.......#..O.##O#...#.#.......#.#....#.O.O..OO..#.O..#..O#O.\n...O...O#....#O.......#........#.O.O..O.#O#...O...#..O.#..OO#O...#........O...#.....OO.#...#.O...#.#\nO.#.O#...O#....#OO.O.##......O...##..#..O#.#.#O.....OOO..#O....#...O..O#O....#.#....OO.#..#.....OO.#\n...O#..O.#.#..O........O.....#.........#.....O.......O......#..#.#O....#O.O#O.#..##O#....#O...O.O...\n#..O.O...O#..O.O.#O..#...O#....#..#...O..#O...O.....O..OO#OOO#OOO...#.O...#.OO#O.....#O.#.........O.\nO.O...#....O#OO...O.OO..#..OO...#..O..O.O....#...#..O..OOO#.....#..OO.#O....O.#.O.OOO.#OO....##OO..O\n.#O#.#.##...###O..O#...#.O.#.O...O#.O.....O....O..OOO....#...O...OO.....#.#O#O..#O......#.O.....#.#O\nO.#O.OO......##......O..OOO##.OOO.#..O...O.O#..#O.#O.O......#................##..#....#O......#.....\n........#.....##...OO.O......#..#.......#O.....O....O....#O.##..OO...O...O..........#..O.....OO...#.\n#..O.#.......O......O#.O..........#O#.O#.#..#..O..O#.O.O..O.O........O......O..O.O..O.O..#O....O#.#.\n...#...OO#..#..##.O.....O...........O.#O#O...##...O..#..#..O....#..O#O.##..O##......OOO....##..###.#\n.#..#....OOO......O#O...##O..O.OO...O..#.....#.O..##...." <> ...} ``` ```elixir puzzle_input = """ O....#.... O.OO#....# .....##... OO.#O....O .O.....O#. O.#..O.#.# ..O..#O..O .......O.. #....###.. #OO..#.... """ ``` ``` "O....#....\nO.OO#....#\n.....##...\nOO.#O....O\n.O.....O#.\nO.#..O.#.#\n..O..#O..O\n.......O..\n#....###..\n#OO..#....\n" ``` ```elixir map = puzzle_input |> String.split("\n", trim: true) |> Enum.with_index(0) |> Enum.flat_map(fn {line, y} -> line |> String.to_charlist() |> Enum.with_index() |> Enum.filter(fn {p, _} -> p != ?. end) |> Enum.map(fn {?#, x} -> {{x, y}, :cube} {?O, x} -> {{x, y}, :round} end) end) |> Map.new() {width, height} = Enum.reduce(map, {0, 0}, fn {{x, y}, _}, {w, h} -> {max(x, w), max(y, h)} end) ``` ``` {9, 9} ``` ## Part 1 ```elixir defmodule Day14 do def weight(map, width, height) do for(col <- 0..width, do: Day14.column_weight(map, col, height)) |> Enum.sum() end def column_weight(map, col, height) do do_column_weight(map, col, height, 0, 0, height) end defp do_column_weight(_map, _col, -1, stack, sum, height) do sum + sum(height + 1, stack) end defp do_column_weight(map, col, row, stack, sum, height) do case Map.fetch(map, {col, row}) do :error -> do_column_weight(map, col, row - 1, stack, sum, height) {:ok, :cube} -> do_column_weight(map, col, row - 1, 0, sum + sum(height - row, stack), height) {:ok, :round} -> do_column_weight(map, col, row - 1, stack + 1, sum, height) end end def sum(_, 0), do: 0 def sum(s, n), do: div((2 * s - n + 1) * n, 2) def print(map, width, height) do for y <- 0..height do row = for x <- 0..width do case Map.get(map, {x, y}) do nil -> " " :cube -> "#" :round -> "O" end end ["#{y}\t", row, "\n"] end |> IO.puts() end end ``` ``` {:module, Day14, <<70, 79, 82, 49, 0, 0, 15, ...>>, {:print, 3}} ``` ```elixir Day14.print(map, width, height) ``` ``` 0 O    #     1 O OO#    # 2      ##    3 OO #O    O 4  O     O#  5 O #  O # # 6   O  #O  O 7        O   8 #    ###   9 #OO  #     ``` ``` :ok ``` ```elixir Day14.weight(map, width, height) ``` ``` 136 ``` ## Part 2 ```elixir defmodule Day14.Part2 do def round(map, width, height) do map |> move(width, height) |> rotate(height) |> move(height, width) |> rotate(width) |> move(width, height) |> rotate(height) |> move(height, width) |> rotate(width) end def move(map, width, height) do for(x <- 0..width, col = move_column(map, x, height), c <- col, into: %{}, do: c) end def move_column(map, col, height) do do_move(map, col, height, 0, []) end defp do_move(_map, col, -1, stack, acc) do expand_stack(0, col, stack) ++ acc end defp do_move(map, col, row, stack, acc) do case Map.fetch(map, {col, row}) do :error -> do_move(map, col, row - 1, stack, acc) {:ok, :cube} -> do_move( map, col, row - 1, 0, expand_stack(row + 1, col, stack) ++ [{{col, row}, :cube} | acc] ) {:ok, :round} -> do_move(map, col, row - 1, stack + 1, acc) end end defp expand_stack(start, col, len) do for y <- 0..(len - 1)//1, do: {{col, start + y}, :round} end def rotate(map, height) do Map.new(map, fn {{x, y}, v} -> {{height - y, x}, v} end) end def rounds_with_memoisation(map, width, height) do Stream.iterate(map, &round(&1, width, height)) end end ``` ``` {:module, Day14.Part2, <<70, 79, 82, 49, 0, 0, 17, ...>>, {:rounds_with_memoisation, 3}} ``` ```elixir {nmap, _, _} = Day14.Part2.rounds_with_memoisation(map, width, height) |> Stream.with_index() |> Enum.reduce_while(%{}, fn {map, idx}, set -> case Map.fetch(set, map) do :error -> {:cont, Map.put(set, map, idx)} {:ok, prev} -> {:halt, {map, idx, prev}} end end) ``` ``` {%{ {9, 8} => :round, {4, 6} => :round, {9, 9} => :round, {7, 7} => :round, {9, 7} => :round, {1, 5} => :round, {7, 5} => :cube, {8, 1} => :round, {0, 8} => :cube, {9, 5} => :cube, {4, 1} => :cube, {9, 6} => :round, {5, 9} => :cube, {8, 7} => :round, {6, 4} => :round, {5, 4} => :round, {9, 1} => :cube, {5, 6} => :cube, {5, 2} => :cube, {4, 9} => :round, {2, 5} => :cube, {3, 9} => :round, {0, 9} => :cube, {4, 8} => :round, {6, 2} => :cube, {7, 8} => :cube, {6, 5} => :round, {6, 8} => :cube, {2, 3} => :round, {5, 0} => :cube, {5, 8} => :cube, {7, 4} => :round, {3, 3} => :cube, {8, 4} => :cube, {2, 9} => :round }, 10, 3} ``` ```elixir Day14.Part2.rounds_with_memoisation(map, width, height) |> Enum.take(11) |> Stream.each(&Day14.print(&1, width, height)) |> Enum.map(&Day14.weight(&1, width, height)) |> IO.inspect(charlists: :as_lists) ``` ``` 0 O    #     1 O OO#    # 2      ##    3 OO #O    O 4  O     O#  5 O #  O # # 6   O  #O  O 7        O   8 #    ###   9 #OO  #     0      #     1     #   O# 2    OO##    3  OO#       4      OOO#  5  O#   O# # 6     O#     7       OOOO 8 #   O###   9 #  OO#     0      #     1     #   O# 2      ##    3   O#       4      OOO#  5  O#   O# # 6     O#   O 7        OOO 8 #  OO###   9 # OOO#   O 0      #     1     #   O# 2      ##    3   O#       4      OOO#  5  O#   O# # 6     O#   O 7        OOO 8 #   O### O 9 # OOO#   O 0      #     1     #   O# 2      ##    3   O#       4      OOO#  5  O#   O# # 6     O#   O 7        OOO 8 #   O### O 9 #  OO#  OO 0      #     1     #   O# 2      ##    3    #       4      OOO#  5  O#   O# # 6     O#   O 7       OOOO 8 #   O### O 9 #  OO#  OO 0      #     1     #   O# 2      ##    3    #       4      OOO#  5  O#   O# # 6     O#   O 7       OOOO 8 #    ### O 9 # OOO#  OO 0      #     1     #   O# 2      ##    3   O#       4       OO#  5  O#   O# # 6     O#   O 7       OOOO 8 #    ### O 9 # OOO#  OO 0      #     1     #   O# 2      ##    3   O#       4       OO#  5  O#   O# # 6     O#     7       OOOO 8 #   O### O 9 # OOO#  OO 0      #     1     #   O# 2      ##    3   O#       4      OOO#  5  O#   O# # 6     O#     7       OOOO 8 #   O### O 9 # OOO#   O 0      #     1     #   O# 2      ##    3   O#       4      OOO#  5  O#   O# # 6     O#   O 7        OOO 8 #   O### O 9 # OOO#   O [136, 129, 114, 110, 110, 105, 103, 106, 111, 114, 110] ``` ``` [136, 129, 114, 110, 110, 105, 103, 106, 111, 114, 110] ```