Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 14

2023/day14.livemd

Day 14

Mix.install([:kino_aoc])

Section

{: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..##...." <> ...}
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"
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

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}}
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
Day14.weight(map, width, height)
136

Part 2

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, &amp;round(&amp;1, width, height))
  end
end
{:module, Day14.Part2, <<70, 79, 82, 49, 0, 0, 17, ...>>, {:rounds_with_memoisation, 3}}
{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}
Day14.Part2.rounds_with_memoisation(map, width, height)
|> Enum.take(11)
|> Stream.each(&amp;Day14.print(&amp;1, width, height))
|> Enum.map(&amp;Day14.weight(&amp;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]