5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 22

Advent of code 2023 Day 14 Part 1 を Livebook で楽しむ

Last updated at Posted at 2024-12-04

はじめに

Advent of code 2023 Day 14 の Part 1 を解きます

問題文はこちら

実装したノートブックはこちら

セットアップ

Kino AOC をインストールします

Mix.install([
  {:kino_aoc, "~> 0.1"}
])

Kino AOC の使い方はこちらを参照

入力の取得

"Advent of Code Helper" スマートセルを追加し、 Day 14 の入力を取得します

スクリーンショット 2024-12-04 9.01.19.png

私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

回答

まずは入力例の小さいマップで解いてみましょう

入力を文字毎の配列に変換します

map =
  """
  O....#....
  O.OO#....#
  .....##...
  OO.#O....O
  .O.....O#.
  O.#..O.#.#
  ..O..#O..O
  .......O..
  #....###..
  #OO..#....
  """
  |> String.trim()
  |> String.split("\n")
  |> Enum.map(fn row ->
    String.codepoints(row)
  end)

実行結果

[
  ["O", ".", ".", ".", ".", "#", ".", ".", ".", "."],
  ["O", ".", "O", "O", "#", ".", ".", ".", ".", "#"],
  [".", ".", ".", ".", ".", "#", "#", ".", ".", "."],
  ["O", "O", ".", "#", "O", ".", ".", ".", ".", "O"],
  [".", "O", ".", ".", ".", ".", ".", "O", "#", "."],
  ["O", ".", "#", ".", ".", "O", ".", "#", ".", "#"],
  [".", ".", "O", ".", ".", "#", "O", ".", ".", "O"],
  [".", ".", ".", ".", ".", ".", ".", "O", ".", "."],
  ["#", ".", ".", ".", ".", "#", "#", "#", ".", "."],
  ["#", "O", "O", ".", ".", "#", ".", ".", ".", "."]
]

北にスライドさせる = 上方向にずらす、ということですが、列方向の操作はやりづらいので、縦横を入れ替えるために 90 度回転します

turned_map =
  map
  |> Enum.zip()
  |> Enum.map(fn col ->
    Tuple.to_list(col)
  end)
  |> Enum.reverse()

実行結果

[
  [".", "#", ".", "O", ".", "#", "O", ".", ".", "."],
  [".", ".", ".", ".", "#", ".", ".", ".", ".", "."],
  [".", ".", ".", ".", "O", "#", ".", "O", "#", "."],
  [".", ".", "#", ".", ".", ".", "O", ".", "#", "."],
  ["#", ".", "#", ".", ".", "O", "#", ".", "#", "#"],
  [".", "#", ".", "O", ".", ".", ".", ".", ".", "."],
  [".", "O", ".", "#", ".", ".", ".", ".", ".", "."],
  [".", "O", ".", ".", ".", "#", "O", ".", ".", "O"],
  [".", ".", ".", "O", "O", ".", ".", ".", ".", "O"],
  ["O", "O", ".", "O", ".", "O", ".", ".", "#", "#"]
]

この状態で左方向にずらせば北にずらしたのと同じことになります

岩をスライドさせるためのモジュールを定義します

defmodule Rock do
  def turn(map) do
    map
    |> Enum.zip()
    |> Enum.map(fn col ->
      Tuple.to_list(col)
    end)
    |> Enum.reverse()
  end

  def slide(map) do
    Enum.map(map, fn row ->
      slide(row, length(row) - 1)
    end)
  end
  
  def slide(row, 0), do: row
  def slide(row, current_index) do
    current_block = Enum.at(row, current_index)
    next_block = Enum.at(row, current_index - 1)

    case {current_block, next_block} do
      {"O", "."} ->
        row
        |> List.update_at(current_index, fn _ -> "." end)
        |> List.update_at(current_index - 1, fn _ -> "O" end)
        |> slide(length(row) - 1)
      _ ->
        slide(row, current_index - 1)
    end
  end

  def sum_load(map) do
    map
    |> Enum.map(fn row ->
      row
      |> Enum.reverse()
      |> Enum.with_index(1)
      |> Enum.map(fn {mark, index} ->
        case mark do
          "O" -> index
          _ -> 0
        end
      end)
      |> Enum.sum()
    end)
    |> Enum.sum()
  end
end

ある位置の記号と右隣の記号が .O であればスライドできるため、次の状態は O. になります

それ以外の .., O., OO, ##, #O, O#, #., .# では、どのパターンもスライドできないので変化しません

順次岩をスライドさせていくため、このスライドを右側から順に行い、スライドできたら(状態が変わったら)右端から再度スライドしていくことで、全ての岩をスライドさせることができます

実行例

  • .O#.OO. 初期状態
  • .O#O.O. 右端から順にチェックしていくと、2番目の岩を動かすことができた
  • .O#OO.. 改めて右端から順にチェックしていくと、3番目の岩を動かすことができた
  • O.#OO.. 改めて右端から順にチェックしていくと、1番目の岩を動かすことができた
  • O.#OO.. 最後に左端までチェックして何も動かすことができなかったのでスライド終了

これを全ての行に対して実行すれば良いことになります

実際に入力例でスライドさせてみましょう

map
|> Rock.turn()
|> Rock.slide()

実行結果

[
  [".", "#", "O", ".", ".", "#", "O", ".", ".", "."],
  [".", ".", ".", ".", "#", ".", ".", ".", ".", "."],
  ["O", ".", ".", ".", ".", "#", "O", ".", "#", "."],
  [".", ".", "#", "O", ".", ".", ".", ".", "#", "."],
  ["#", ".", "#", "O", ".", ".", "#", ".", "#", "#"],
  [".", "#", "O", ".", ".", ".", ".", ".", ".", "."],
  ["O", ".", ".", "#", ".", ".", ".", ".", ".", "."],
  ["O", ".", ".", ".", ".", "#", "O", "O", ".", "."],
  ["O", "O", "O", ".", ".", ".", ".", ".", ".", "."],
  ["O", "O", "O", "O", ".", ".", ".", ".", "#", "#"]
]

全ての丸い岩が可能な分だけ左に移動しました

左から順に重量の影響は 10, 9, 8, ..., 3, 2, 1 となっているため、左右反転させて岩の 列番号 + 1 を合計します

map
|> Rock.turn()
|> Rock.slide()
|> Rock.sum_load()

実行結果は 136 となり、問題文の結果と一致しました

同様の操作を実際の入力に対して実行しましょう

map =
  puzzle_input
  |> String.split("\n")
  |> Enum.map(fn row ->
    String.codepoints(row)
  end)
map
|> Rock.turn()
|> Rock.slide()
|> Rock.sum_load()

まとめ

ややこしくはありますが、ここまでは考えやすかったです

Part 2 がもっとややこしくて考えないといけないことが多く、記事を分けました

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?