見出し画像

ヤッツィーLOVE

「サイコロ遊び」でも書いたのだけれど、私は基本的にダイスゲームが好きだ。

これまでの自作ゲームも、「ダイス☆スター」だったり、「もじキューブ」だったり、サイコロ絡みのものが多い。

その中でも、とりわけ、「ヤッツィー」「GREED$」「クニツィアのデカスロン」が好きすぎるので、このどれかを遊び始めると、かなり長く遊んでいるし、そのうち息子と延々と遊ぶことになると思っている。

というわけで、今日はヤッツィーについて考えてみたい。


由来とか

確かに、最初に遊んだ時は、「ヨット」という名前で紹介された記憶がある。調べたら、「Generala(ヘネラーラ)」みたいな名前もあったりして、かなり古いゲームで、出自があまりはっきりしないんだなぁ、ということがわかる。

Jr.というバージョンもあって、これは数字の概念を捨てて、絵合わせの要素だけで遊ばせるもので、ディズニーキャラクターのやつとか、何種類か出ていた気がする。

アルゴリズム?

かなり間をすっ飛ばして、皆さんがヤッツィーを理解しているものと考える。そのうえで、ChatGPT-4oくんに、得点をたくさん取るためのアルゴリズム的なものを考えてもらおう。

ヤッツィーの最適なスコアを目指すアルゴリズムを設計するために、以下のようなフローチャートを考えました。このフローチャートは、各ターンでの行動を決定するための戦略を示しています。

フローチャート
スタート
最初のサイコロを振る(5個)
役の可能性を確認する
もし「ヤッツィー」が可能なら、ヤッツィーを選択して終了
もし「Large Straight」が可能なら、Large Straightを選択して終了
もし「Full House」が可能なら、Full Houseを選択して終了
もし「Small Straight」が可能なら、Small Straightを選択して終了
優先順位に基づいてサイコロを保持し、残りを再振り
3 of a Kindまたは4 of a Kindを目指す
特定の数字を目指す(例えば、同じ目を集める)
再度サイコロを振る
再度役の可能性を確認する
もし「Yahtzee」が可能なら、Yahtzeeを選択して終了
もし「Large Straight」が可能なら、Large Straightを選択して終了
もし「Full House」が可能なら、Full Houseを選択して終了
もし「Small Straight」が可能なら、Small Straightを選択して終了
再振りが必要な場合、再度サイコロを保持し、残りを再振り
最終的なサイコロの目で役を決定する
最高得点を取れる役を選択
役をスコアシートに記入し、次のターンへ
13ターン終了後、ゲーム終了

ChatGPTの出力

なるほど。4oくんが考えるアルゴリズムは、5つ同じ目が出るYahtzee、5つの目が階段状に並んでいるLarge Straight、3個、2個と出目が揃っているFull House、4つの目が階段状に並んでいるSmall Straightをこの順に優先取得し、それが出ていない時には(或いは既に埋まっているときには)できるだけ同じ目をたくさん出す方向に切り替える、というものらしい。

このときに、既に埋まっているAceからSixまでの数字のことを考えたり、BONUSの事を考えたり、Chance効率の事を考えたりと、本当に強いアルゴリズムにするのならばもう少し考慮する必要がありそうだが、よくもまぁ、こんな個別のゲームのアルゴリズムをササッと答えてくれるものだなぁ、と感心している。

ついでの実装

例によって例のごとく、ここまできたらPythonで実装してくれないかな、と。

import random
from collections import Counter

# サイコロを振る関数
def roll_dice(num_dice):
return [random.randint(1, 6) for _ in range(num_dice)]

# サイコロを保持する関数
def hold_dice(dice, hold_indices):
return [dice[i] for i in hold_indices]

# 役のスコアを計算する関数
def calculate_score(dice, category):
dice_count = Counter(dice)
if category == 'three_of_a_kind':
for num, count in dice_count.items():
if count >= 3:
return sum(dice)
return 0
elif category == 'four_of_a_kind':
for num, count in dice_count.items():
if count >= 4:
return sum(dice)
return 0
elif category == 'full_house':
if sorted(dice_count.values()) == [2, 3]:
return 25
return 0
elif category == 'small_straight':
straights = [{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}]
if any(straight.issubset(set(dice)) for straight in straights):
return 30
return 0
elif category == 'large_straight':
straights = [{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}]
if any(straight.issubset(set(dice)) for straight in straights):
return 40
return 0
elif category == 'yahtzee':
if len(dice_count) == 1:
return 50
return 0
elif category == 'chance':
return sum(dice)
else:
return 0

# AIが役を選ぶための関数
def ai_choose_category(dice, available_categories):
best_category = None
best_score = 0
for category in available_categories:
score = calculate_score(dice, category)
if score > best_score:
best_category = category
best_score = score
return best_category, best_score

# 優先順位に基づいてサイコロを保持する関数
def hold_for_best_outcome(dice):
dice_count = Counter(dice)
max_count = max(dice_count.values())
hold_indices = [i for i, die in enumerate(dice) if dice_count[die] == max_count]
return hold_indices

# メインルーチン
def main():
available_categories = ['three_of_a_kind', 'four_of_a_kind', 'full_house', 'small_straight', 'large_straight', 'yahtzee', 'chance']
for turn in range(13): # 13ターンのプレイ
dice = roll_dice(5)
print(f"Roll {turn + 1}: {dice}")

# 最初のサイコロ振りで役を確認
chosen_category, score = ai_choose_category(dice, available_categories)
if chosen_category:
print(f"Initial Choice - Category: {chosen_category}, Score: {score}")
else:
print("No initial category chosen, re-rolling dice.")

# 最初の保持
hold_indices = hold_for_best_outcome(dice)
dice = hold_dice(dice, hold_indices)
dice += roll_dice(5 - len(dice))
print(f"Second Roll: {dice}")

# 2回目のサイコロ振りで役を再確認
chosen_category, score = ai_choose_category(dice, available_categories)
if chosen_category:
print(f"Second Choice - Category: {chosen_category}, Score: {score}")
else:
print("No second category chosen, re-rolling dice.")

# 2回目の保持
hold_indices = hold_for_best_outcome(dice)
dice = hold_dice(dice, hold_indices)
dice += roll_dice(5 - len(dice))
print(f"Third Roll: {dice}")

# 最終的な役を決定
chosen_category, score = ai_choose_category(dice, available_categories)
if chosen_category:
available_categories.remove(chosen_category)
print(f"Final Choice - Category: {chosen_category}, Score: {score}")
else:
print("No available category left.")

if __name__ == "__main__":
main()

ChatGPTの出力

もちろん細かい部分は手を加えないと行けない部分はあるし、ん?と思う部分はあるのだけれど、大枠これで問題なかろう。

そのうち、この4o版のAIとYahtzeeでサクッと対戦できるようにして、延々と時間を溶かそうではないか。

まとめ

学習データに、「Yahtzeeで高い得点を取るためのアルゴリズム」なんてものが入っているとは思えないので、このレベルでアルゴリズムが組めているのは、改めて凄いことだなぁ、と思う。

ここまで理解しているのなら、Yahtzeeにアレンジを加えることもできそうだ。

素晴らしいアイデアですね!Yahtzeeをベースに新しい魅力的なゲームを作るためのいくつかの提案を考えてみました。以下のアイデアは、既存のルールにアレンジを加えて、ゲームに新しい要素や戦略を導入するものです。

### アイデア1: マジックダイス
- **特殊サイコロ:** 通常の5つのサイコロに加えて、「マジックダイス」を1つ追加します。このサイコロは特別な効果を持つ目(例えば、スコア2倍、もう一度振る、相手のサイコロを1つ選んで再振りさせるなど)が出る可能性があります。
- **ルール:** マジックダイスは1ラウンドに1回だけ振ることができ、特定の状況(例えば、役が完成した後)で使用します。

### アイデア2: エレメントダイス
- **エレメントサイコロ:** 通常の数字サイコロに加えて、火、水、風、土の「エレメントサイコロ」を導入します。エレメントサイコロは特定の役に追加ポイントを与える効果があります。
- **ルール:** 各プレイヤーは1ラウンドごとにエレメントサイコロを振ることができ、特定の役(例えば、フルハウスやストレート)と組み合わせることでボーナスポイントを獲得します。

### アイデア3: カードパワーアップ
- **パワーアップカード:** 各プレイヤーはゲーム開始時に5枚のパワーアップカードを配られます。これらのカードは特定の状況で使用でき、サイコロの目を変更したり、相手のスコアを減らしたりする効果があります。
- **ルール:** パワーアップカードは1ラウンドに1枚まで使用でき、使いどころが重要な戦略要素となります。

### アイデア4: 役のカスタマイズ
- **カスタム役:** プレイヤーはゲーム開始前に自分のスコアシートの役を一部カスタマイズできます。例えば、特定の数字の組み合わせで特別な役を作ることができます。
- **ルール:** 各プレイヤーは3つの役を自分で設定でき、それにより戦略の幅が広がります。

### アイデア5: ダブルフェイスモード
- **ダブルフェイスサイコロ:** 各サイコロの面に通常の数字と特別な効果が書かれています。プレイヤーはサイコロを振るたびに、数字か効果を選ぶことができます。
- **ルール:** 特別な効果には、特定の役のスコア2倍、もう一度振る、他のプレイヤーのサイコロを1つ選んで再振りさせるなどがあります。

### アイデア6: チームバトル
- **チームプレイ:** 2つのチームに分かれて対戦します。各チームのプレイヤーは順番にサイコロを振り、チーム全体のスコアを競います。
- **ルール:** チームメンバーは互いに協力して役を完成させることができ、チーム全体の戦略が重要となります。

これらのアイデアを組み合わせることで、既存のYahtzeeに新しい要素を追加し、さらに魅力的なゲームに生まれ変わらせることができます。どのアイデアが一番興味深いかを考えて、さらに詳細なルールを作り込んでいくと良いでしょう。

ChatGPTの出力

モノポリーだって、Expressルールが登場して、追加のサイコロを振って時間を短くしたりしていたし、アイデア1のマジックダイスの追加は面白い変化をもたらしてくれそうな予感がある。(例えば、6面のうち1つは、「1/2」となっていて、1または2でYahtzeeを作る時の補助に使えるとかでもよさそうだ)

…あ、これは久々に熱が入りすぎて、とんでもないところまで来てしまったやつだ、となっているので、ここまで真面目に読んでくれた読者さんへ感謝の意を示しつつ、今日はこのへんで終わりにしたいと思う。ほなね!

例のAI画像のコーナー

ちょっと文章パートに熱を入れすぎて疲れてしまっているので、画像パートはいい加減に、「Ms. Yahtzee」とだけ入れて何が出力されるか見てみた。

売り込みしてくるタイプのMs.Yahtzee
まさかの猫。いいね。

ギリギリまで猫と迷ったが、もう1枚生成されていたいかにもYahtzee強者の画像を、今日の見出し画像としたい。

いただいたサポートは、きっと、ドイツアマゾンからの送料に変わると思います。 温かいご支援、お待ちしております。