$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います}$
はじめに
@torifukukaiou さんの パク リスペクト記事です
Elixir Livebook で Advent of Code 2023 の問題を解いてみます
実装したノートブックはこちら
問題はこちら
Part 1 はこちら
セットアップ
Kino AOC をインストールします
Mix.install([
{:kino_aoc, "~> 0.1.5"}
])
Kino AOC の使い方はこちらを参照
入力の取得
Day 7 の入力を取得します
私の答え
私の答えです。
折りたたんでおきます。
▶を押して開いてください。
details
回答用のモジュールです
入力を扱いやすい形にするための parse
と、回答を作るための resolve
関数を持っています
defmodule Resolver do
@card_strength %{
"T" => 10,
"J" => 1,
"Q" => 12,
"K" => 13,
"A" => 14
}
def parse(input) do
input
|> String.split("\n")
|> Enum.map(fn line ->
line
|> String.split(" ", trim: true)
|> then(fn [hand, bet] ->
hand =
hand
|> String.codepoints()
|> Enum.map(fn card ->
strength = Map.get(@card_strength, card)
if is_nil(strength) do
String.to_integer(card)
else
strength
end
end)
has_j = Enum.member?(hand, 1)
{min_freq, max_freq, uniq} =
hand
|> Enum.filter(& &1 != 1)
|> Enum.frequencies()
|> Map.values()
|> then(fn frequencies ->
if frequencies == [] do
{0, 0, 0}
else
{
Enum.min(frequencies),
Enum.max(frequencies),
Enum.count(frequencies)
}
end
end)
type_strength =
case {min_freq, max_freq, uniq, has_j} do
{_, _, 0, _} ->
6
{_, _, 1, _} ->
6
{2, _, 2, _} ->
4
{_, _, 2, _} ->
5
{_, 3, 3, false} ->
3
{_, 2, 3, false} ->
2
{_, _, 3, true} ->
3
{_, _, 4, _} ->
1
{_, _, 5, _} ->
0
end
hand_strength =
0..4
|> Enum.map(fn index ->
Enum.at(hand, index) * Integer.pow(14, 4 - index)
end)
|> Enum.sum()
|> Kernel.+(type_strength * Integer.pow(14, 5))
%{
hand_strength: hand_strength,
bet: String.to_integer(bet)
}
end)
end)
end
def resolve(games) do
games
|> Enum.sort(& &1.hand_strength < &2.hand_strength)
|> Enum.with_index()
|> Enum.map(fn {game, index} ->
game.bet * (index + 1)
end)
|> Enum.sum()
end
end
カードの強さの計算方法(14進数)は Part 1 と同じです
J を 11 ではなくジョーカー(役を最も強くするように変化するカード)として扱います
ただし、タイプの識別以外では最弱として扱います
役は以下の数の組み合わせで決定できます
- ジョーカー以外の種類毎の最大枚数
- ジョーカー以外の種類毎の最小枚数
- ジョーカー以外の種類数
- ジョーカーの有無
全ての場合分け
- ジョーカー以外のカードが 0 種類の場合、つまり全てジョーカーなので必ずファイブカードです
- ジョーカー以外のカードが 1 種類の場合、他のカードを全て同じカードにするので必ずファイブカードです
- ジョーカー以外のカードが 2 種類の場合
- ジョーカー以外の種類毎の最小枚数が 2 の場合、つまり XXYYJ か XXYYY の場合はフルハウスしか作れません
- それ以外の場合、つまり XYJJJ か XYYJJ か XYYYJ の場合、必ずフォーカードになります
- ジョーカー以外のカードが 3 種類の場合
- ジョーカーがない場合
- 種類毎の最大枚数が 3 の場合、つまり XYZZZ の場合はスリーカードです
- それ以外の場合、つまり XYYZZ の場合はツーペアです
- ジョーカーがある場合
- XYZJJ か XYZZJ ですが、いずれも必ずスリーカードになります
- ジョーカーがない場合
- ジョーカー以外のカードが 4 種類の場合、 XYZWJ か XYZWW なので必ずワンペアになります
- カードが 5 種類の場合、ハイカードです
resolve
関数は Part 1 と同じです
まとめ
ジョーカーがあるときの場合分けが更に面白いですね