hanabiapp.game.hint_knowledge_manager

ヒントの知識を管理するクラス

  • 以下のコードを参考にしています: GitHub - yawgmoth/pyhanabi: A research-focused, Python implementation of Hanabi, including a browser-based user interface https://github.com/yawgmoth/pyhanabi
  • ヒント情報を記録するknowledge記録・管理します.

  • knowledge:は,各プレイヤーの知識を保持する4次元リストで,ヒント情報は保存されます.

  • knowledge[player_number][card_position][color][number-1] でアクセス可能です.

    • 各プレイヤの各手札(デフォルトは5枚)に対し,各色(デフォルトは5色),ありうるカードの可能性を示します.
  • 例1 2人プレイ時のknowledgeの初期状態は以下の通りです: [ (プレイヤー 0 の知識) (手札 0:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 1:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 2:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 3:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 4:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] ], [ (プレイヤー 1 の知識) (手札 0:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 1:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 2:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 3:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] (手札 4:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] ]

  • 初期状態のプレイヤー 0の手札0に着目します.

    • なにも情報がないので,各色に対して3,2,2,2,1枚ずつある可能性が示されています.
    • 色はlogic.pyのGameConst.COLOR_NAMESで定義された(デフォルトは["B", "G", "R", "W", "Y"])の順になっています.
  • 例2 プレイヤー1からプレイヤー0に「プレイヤー0の手札0は青色です」とヒントが与えられたときの知識更新は以下の通りです(少し表記を簡単にしています): プレイヤー 0 の知識: 手札 0: [[3, 2, 2, 2, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] 手札 1: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 2: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 3: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 4: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] プレイヤー 1 の知識: 手札 0: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 1: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 2: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 3: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 4: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]

    • プレイヤー 0の手札0-4に着目します.
      • 手札0は青色であり,手札1-4は青色ではないことがわかりました.
      • ですので,手札0は青色以外の色は存在しえない[0, 0, 0, 0, 0]とすることで,青であることを確定させています.
      • 一方,手札1-4は青色である可能性がなくなったので,青色の可能性を[0, 0, 0, 0, 0]としています.
  • 例3 プレイヤー1からプレイヤー0に「プレイヤー0の手札0の数字は3です」とヒントが与えられたときの知識更新は以下の通りです: プレイヤー 0 の知識: 手札 0: [[0, 0, 2, 0, 0], [0, 0, 2, 0, 0], [0, 0, 2, 0, 0], [0, 0, 2, 0, 0], [0, 0, 2, 0, 0]] 手札 1: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]] 手札 2: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]] 手札 3: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]] 手札 4: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]] プレイヤー 1 の知識: 手札 0: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 1: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 2: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 3: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]] 手札 4: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]

    • プレイヤー 0の手札0-4に着目します.
      • 手札0はの数字は3であり,手札1-4の数字は3ではないことがわかりました.
      • ですので,手札0は3以外の色は存在しえない[0, 0, 2, 0, 0]とすることで,3であることを確定させています.
      • 一方,手札1-4は3である可能性がなくなったので,3の可能性を排除した[3, 2, 0, 2, 1]としています.
  • 注意点

    • 相手の手札とか,捨て札とか,ボードの情報は加味した絞り込みはしてないので注意してください.
      • 例えば,場にすでにR1が出ている⇒観測できないところにあるR1は1枚減ったな⇒knowledge更新,とかはしてないです
      • そういう絞り込みしたければ別配列ですること.少なくとも上記で参考にしたもの&AIはその仕様なので合わせています.
    • knowledgeはAIに渡され活用されるもので,直接的にゲームロジックに関係しません.
  1"""ヒントの知識を管理するクラス
  2  * 以下のコードを参考にしています:
  3  GitHub - yawgmoth/pyhanabi: A research-focused, Python implementation of Hanabi, including a browser-based user interface
  4  https://github.com/yawgmoth/pyhanabi
  5
  6  - ヒント情報を記録するknowledge記録・管理します.
  7
  8  - knowledge:は,各プレイヤーの知識を保持する4次元リストで,ヒント情報は保存されます.
  9  - knowledge[player_number][card_position][color][number-1] でアクセス可能です.
 10    - 各プレイヤの各手札(デフォルトは5枚)に対し,各色(デフォルトは5色),ありうるカードの可能性を示します.
 11
 12  - 例1 2人プレイ時のknowledgeの初期状態は以下の通りです:
 13    [ (プレイヤー 0 の知識)
 14      (手札 0:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 15      (手札 1:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 16      (手札 2:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 17      (手札 3:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 18      (手札 4:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 19    ],
 20    [ (プレイヤー 1 の知識)
 21      (手札 0:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 22      (手札 1:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 23      (手札 2:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 24      (手札 3:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 25      (手札 4:) [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 26    ]
 27  - 初期状態のプレイヤー 0の手札0に着目します.
 28    - なにも情報がないので,各色に対して3,2,2,2,1枚ずつある可能性が示されています.
 29    - 色はlogic.pyのGameConst.COLOR_NAMESで定義された(デフォルトは["B", "G", "R", "W", "Y"])の順になっています.
 30  
 31  - 例2 プレイヤー1からプレイヤー0に「プレイヤー0の手札0は青色です」とヒントが与えられたときの知識更新は以下の通りです(少し表記を簡単にしています):
 32    プレイヤー 0 の知識:
 33      手札 0: [[3, 2, 2, 2, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
 34      手札 1: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 35      手札 2: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 36      手札 3: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 37      手札 4: [[0, 0, 0, 0, 0], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 38    プレイヤー 1 の知識:
 39      手札 0: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 40      手札 1: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 41      手札 2: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 42      手札 3: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 43      手札 4: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 44    - プレイヤー 0の手札0-4に着目します.
 45      - 手札0は青色であり,手札1-4は青色ではないことがわかりました.
 46      - ですので,手札0は青色以外の色は存在しえない[0, 0, 0, 0, 0]とすることで,青であることを確定させています.
 47      - 一方,手札1-4は青色である可能性がなくなったので,青色の可能性を[0, 0, 0, 0, 0]としています.
 48
 49  - 例3 プレイヤー1からプレイヤー0に「プレイヤー0の手札0の数字は3です」とヒントが与えられたときの知識更新は以下の通りです:
 50    プレイヤー 0 の知識:
 51      手札 0: [[0, 0, 2, 0, 0], [0, 0, 2, 0, 0], [0, 0, 2, 0, 0], [0, 0, 2, 0, 0], [0, 0, 2, 0, 0]]
 52      手札 1: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]]
 53      手札 2: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]]
 54      手札 3: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]]
 55      手札 4: [[3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1], [3, 2, 0, 2, 1]]
 56    プレイヤー 1 の知識:
 57      手札 0: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 58      手札 1: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 59      手札 2: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 60      手札 3: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 61      手札 4: [[3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1], [3, 2, 2, 2, 1]]
 62    - プレイヤー 0の手札0-4に着目します.
 63      - 手札0はの数字は3であり,手札1-4の数字は3ではないことがわかりました.
 64      - ですので,手札0は3以外の色は存在しえない[0, 0, 2, 0, 0]とすることで,3であることを確定させています.
 65      - 一方,手札1-4は3である可能性がなくなったので,3の可能性を排除した[3, 2, 0, 2, 1]としています.
 66
 67  - 注意点
 68    - 相手の手札とか,捨て札とか,ボードの情報は加味した絞り込みはしてないので注意してください.
 69      - 例えば,場にすでにR1が出ている⇒観測できないところにあるR1は1枚減ったな⇒knowledge更新,とかはしてないです
 70      - そういう絞り込みしたければ別配列ですること.少なくとも上記で参考にしたもの&AIはその仕様なので合わせています.
 71    - knowledgeはAIに渡され活用されるもので,直接的にゲームロジックに関係しません.
 72"""
 73
 74class KnowledgeManager():
 75  """
 76  Note:
 77    - knowledge配列の更新タイミングは以下の通り
 78      1. ゲーム開始時に手札を配ったとき:initialize_all_knowledge()で初期化
 79      2. ヒントを受けたとき:update_knowledge_after_color_hint()か,update_knowledge_after_number_hint()で更新
 80      3. カードをプレイしたとき:update_knowledge_after_play()で更新
 81      4. カードを捨てたとき:update_knowledge_after_discard()で更新
 82      5. カードを引いたとき:update_knowledge_after_draw()で更新
 83      ※3-5については絞り込みはしていません.
 84       ただプレイした,捨てた,引いた,ときにカードが新しくなる
 85  """
 86
 87  def __init__(self, game):
 88    """
 89    KnowledgeManager クラスのコンストラクタ.
 90    
 91    Args:
 92        game (Game): ゲームインスタンス
 93    """
 94    self.game = game
 95  
 96  def initialize_one_card_knowledge(self):
 97    """
 98    すべての色と数字が存在する状態でカード『1枚』の知識を初期化        
 99    Returns:
100        list: 各色と数字の可能性を示すリスト
101    """
102    new_card_knowledge = []
103    for _ in range(5):  # 各色に対して初期状態のカウントを設定
104      new_card_knowledge.append(self.game.game_const.COUNTS[:])
105    return new_card_knowledge
106  
107  def initialize_all_knowledge(self):
108    """
109    ゲーム開始時,各プレイヤーの手札に対する知識をすべて初期化する関数.
110    
111    Returns:
112        dict: 各プレイヤーの知識を格納した辞書
113    """
114    knowledge = {}
115    for player in self.game.players:
116      player_knowledge = []
117      for _ in range(self.game.hand_size):  # プレイヤーの手札枚数に対して知識を設定
118        player_knowledge.append(self.initialize_one_card_knowledge())
119      knowledge[player.player_number] = player_knowledge
120    return knowledge
121
122  def update_knowledge_after_color_hint(self, target_player_number, color_cards_positions, color):
123    """
124    色のヒントを受け取ったときの知識を更新する.
125    
126    Args:
127        target_player_number (int): ヒントを受け取ったプレイヤーの番号
128        color_cards_positions (list): ヒントを受けたカードの位置
129        color (int): ヒントを与えられた色
130    """
131    # 1. ヒントを受けたカードに対する知識更新
132    for pos in color_cards_positions:
133      for i in range(len(self.game.knowledge[target_player_number][pos])):
134        if i != color:
135          self.game.knowledge[target_player_number][pos][i] = [0] * len(self.game.knowledge[target_player_number][pos][i])
136
137    # 2. ヒントを受けなかったカードに対して、その色は少なくともありえないので,更新
138    for pos in range(len(self.game.knowledge[target_player_number])):
139      if pos not in color_cards_positions:  # ヒントを受けたカードの位置以外
140        self.game.knowledge[target_player_number][pos][color] = [0] * len(self.game.knowledge[target_player_number][pos][color])
141
142  def update_knowledge_after_number_hint(self, target_player_number, number_cards_positions, number):
143    """
144    数字のヒントを受け取ったときの知識を更新する.
145    
146    Args:
147        target_player_number (int): ヒントを受け取ったプレイヤーの番号
148        number_cards_positions (list): ヒントを受けたカードの位置
149        number (int): ヒントを与えられた数字
150    """
151    # 1. ヒントを受けたカードに対する知識更新
152    for pos in number_cards_positions:
153      for i in range(len(self.game.knowledge[target_player_number][pos])):
154        for j in range(len(self.game.knowledge[target_player_number][pos][i])):
155          if j + 1 != number:
156            self.game.knowledge[target_player_number][pos][i][j] = 0
157
158    # 2. ヒントを受けなかったカードは、その数字は少なくともありえないので,更新
159    for pos in range(len(self.game.knowledge[target_player_number])):
160      if pos not in number_cards_positions:  # ヒントを受けたカードの位置以外
161        for i in range(len(self.game.knowledge[target_player_number][pos])):
162          self.game.knowledge[target_player_number][pos][i][number - 1] = 0
163          
164  def update_knowledge_after_draw(self, player_number):
165    """
166    カードを引いた後の知識更新処理.
167    
168    Args:
169        player_number (int): カードを引いたプレイヤーの番号
170    """
171    # カードを引いた後の知識更新処理
172    new_card_knowledge = self.initialize_one_card_knowledge()
173    self.game.knowledge[player_number].append(new_card_knowledge)
174
175  def update_knowledge_after_play(self, player_number, card_position):
176    """
177    カードをプレイした後の知識更新処理.
178    
179    Args:
180        player_number (int): カードをプレイしたプレイヤーの番号
181        card_position (int): プレイしたカードの位置
182    """
183    # カードをプレイした後の知識更新処理
184    del self.game.knowledge[player_number][card_position]
185
186  def update_knowledge_after_discard(self, player_number, card_position):
187    """
188    カードを捨てた後の知識更新処理.
189    
190    Args:
191        player_number (int): カードを捨てたプレイヤーの番号
192        card_position (int): 捨てたカードの位置
193    """
194    # カードを捨てた後の知識更新処理
195    del self.game.knowledge[player_number][card_position]
196  
197  def __str__(self):
198    """
199    プレイヤーごとの知識を文字列として表示する関数.
200    
201    Returns:
202        str: 各プレイヤーの知識を表す文字列
203    """
204    status = []
205    status.append("プレイヤーの知識:")
206    for player in self.game.players:
207      status.append(f"プレイヤー {player.player_number} の知識:")
208      for i, card_knowledge in enumerate(self.game.knowledge[player.player_number]):
209        status.append(f"  手札 {i}: {card_knowledge}")
210    return "\n".join(status)
class KnowledgeManager:
 75class KnowledgeManager():
 76  """
 77  Note:
 78    - knowledge配列の更新タイミングは以下の通り
 79      1. ゲーム開始時に手札を配ったとき:initialize_all_knowledge()で初期化
 80      2. ヒントを受けたとき:update_knowledge_after_color_hint()か,update_knowledge_after_number_hint()で更新
 81      3. カードをプレイしたとき:update_knowledge_after_play()で更新
 82      4. カードを捨てたとき:update_knowledge_after_discard()で更新
 83      5. カードを引いたとき:update_knowledge_after_draw()で更新
 84      ※3-5については絞り込みはしていません.
 85       ただプレイした,捨てた,引いた,ときにカードが新しくなる
 86  """
 87
 88  def __init__(self, game):
 89    """
 90    KnowledgeManager クラスのコンストラクタ.
 91    
 92    Args:
 93        game (Game): ゲームインスタンス
 94    """
 95    self.game = game
 96  
 97  def initialize_one_card_knowledge(self):
 98    """
 99    すべての色と数字が存在する状態でカード『1枚』の知識を初期化        
100    Returns:
101        list: 各色と数字の可能性を示すリスト
102    """
103    new_card_knowledge = []
104    for _ in range(5):  # 各色に対して初期状態のカウントを設定
105      new_card_knowledge.append(self.game.game_const.COUNTS[:])
106    return new_card_knowledge
107  
108  def initialize_all_knowledge(self):
109    """
110    ゲーム開始時,各プレイヤーの手札に対する知識をすべて初期化する関数.
111    
112    Returns:
113        dict: 各プレイヤーの知識を格納した辞書
114    """
115    knowledge = {}
116    for player in self.game.players:
117      player_knowledge = []
118      for _ in range(self.game.hand_size):  # プレイヤーの手札枚数に対して知識を設定
119        player_knowledge.append(self.initialize_one_card_knowledge())
120      knowledge[player.player_number] = player_knowledge
121    return knowledge
122
123  def update_knowledge_after_color_hint(self, target_player_number, color_cards_positions, color):
124    """
125    色のヒントを受け取ったときの知識を更新する.
126    
127    Args:
128        target_player_number (int): ヒントを受け取ったプレイヤーの番号
129        color_cards_positions (list): ヒントを受けたカードの位置
130        color (int): ヒントを与えられた色
131    """
132    # 1. ヒントを受けたカードに対する知識更新
133    for pos in color_cards_positions:
134      for i in range(len(self.game.knowledge[target_player_number][pos])):
135        if i != color:
136          self.game.knowledge[target_player_number][pos][i] = [0] * len(self.game.knowledge[target_player_number][pos][i])
137
138    # 2. ヒントを受けなかったカードに対して、その色は少なくともありえないので,更新
139    for pos in range(len(self.game.knowledge[target_player_number])):
140      if pos not in color_cards_positions:  # ヒントを受けたカードの位置以外
141        self.game.knowledge[target_player_number][pos][color] = [0] * len(self.game.knowledge[target_player_number][pos][color])
142
143  def update_knowledge_after_number_hint(self, target_player_number, number_cards_positions, number):
144    """
145    数字のヒントを受け取ったときの知識を更新する.
146    
147    Args:
148        target_player_number (int): ヒントを受け取ったプレイヤーの番号
149        number_cards_positions (list): ヒントを受けたカードの位置
150        number (int): ヒントを与えられた数字
151    """
152    # 1. ヒントを受けたカードに対する知識更新
153    for pos in number_cards_positions:
154      for i in range(len(self.game.knowledge[target_player_number][pos])):
155        for j in range(len(self.game.knowledge[target_player_number][pos][i])):
156          if j + 1 != number:
157            self.game.knowledge[target_player_number][pos][i][j] = 0
158
159    # 2. ヒントを受けなかったカードは、その数字は少なくともありえないので,更新
160    for pos in range(len(self.game.knowledge[target_player_number])):
161      if pos not in number_cards_positions:  # ヒントを受けたカードの位置以外
162        for i in range(len(self.game.knowledge[target_player_number][pos])):
163          self.game.knowledge[target_player_number][pos][i][number - 1] = 0
164          
165  def update_knowledge_after_draw(self, player_number):
166    """
167    カードを引いた後の知識更新処理.
168    
169    Args:
170        player_number (int): カードを引いたプレイヤーの番号
171    """
172    # カードを引いた後の知識更新処理
173    new_card_knowledge = self.initialize_one_card_knowledge()
174    self.game.knowledge[player_number].append(new_card_knowledge)
175
176  def update_knowledge_after_play(self, player_number, card_position):
177    """
178    カードをプレイした後の知識更新処理.
179    
180    Args:
181        player_number (int): カードをプレイしたプレイヤーの番号
182        card_position (int): プレイしたカードの位置
183    """
184    # カードをプレイした後の知識更新処理
185    del self.game.knowledge[player_number][card_position]
186
187  def update_knowledge_after_discard(self, player_number, card_position):
188    """
189    カードを捨てた後の知識更新処理.
190    
191    Args:
192        player_number (int): カードを捨てたプレイヤーの番号
193        card_position (int): 捨てたカードの位置
194    """
195    # カードを捨てた後の知識更新処理
196    del self.game.knowledge[player_number][card_position]
197  
198  def __str__(self):
199    """
200    プレイヤーごとの知識を文字列として表示する関数.
201    
202    Returns:
203        str: 各プレイヤーの知識を表す文字列
204    """
205    status = []
206    status.append("プレイヤーの知識:")
207    for player in self.game.players:
208      status.append(f"プレイヤー {player.player_number} の知識:")
209      for i, card_knowledge in enumerate(self.game.knowledge[player.player_number]):
210        status.append(f"  手札 {i}: {card_knowledge}")
211    return "\n".join(status)
Note:
  • knowledge配列の更新タイミングは以下の通り
    1. ゲーム開始時に手札を配ったとき:initialize_all_knowledge()で初期化
    2. ヒントを受けたとき:update_knowledge_after_color_hint()か,update_knowledge_after_number_hint()で更新
    3. カードをプレイしたとき:update_knowledge_after_play()で更新
    4. カードを捨てたとき:update_knowledge_after_discard()で更新
    5. カードを引いたとき:update_knowledge_after_draw()で更新 ※3-5については絞り込みはしていません.  ただプレイした,捨てた,引いた,ときにカードが新しくなる
KnowledgeManager(game)
88  def __init__(self, game):
89    """
90    KnowledgeManager クラスのコンストラクタ.
91    
92    Args:
93        game (Game): ゲームインスタンス
94    """
95    self.game = game

KnowledgeManager クラスのコンストラクタ.

Arguments:
  • game (Game): ゲームインスタンス
game
def initialize_one_card_knowledge(self):
 97  def initialize_one_card_knowledge(self):
 98    """
 99    すべての色と数字が存在する状態でカード『1枚』の知識を初期化        
100    Returns:
101        list: 各色と数字の可能性を示すリスト
102    """
103    new_card_knowledge = []
104    for _ in range(5):  # 各色に対して初期状態のカウントを設定
105      new_card_knowledge.append(self.game.game_const.COUNTS[:])
106    return new_card_knowledge

すべての色と数字が存在する状態でカード『1枚』の知識を初期化

Returns:

list: 各色と数字の可能性を示すリスト

def initialize_all_knowledge(self):
108  def initialize_all_knowledge(self):
109    """
110    ゲーム開始時,各プレイヤーの手札に対する知識をすべて初期化する関数.
111    
112    Returns:
113        dict: 各プレイヤーの知識を格納した辞書
114    """
115    knowledge = {}
116    for player in self.game.players:
117      player_knowledge = []
118      for _ in range(self.game.hand_size):  # プレイヤーの手札枚数に対して知識を設定
119        player_knowledge.append(self.initialize_one_card_knowledge())
120      knowledge[player.player_number] = player_knowledge
121    return knowledge

ゲーム開始時,各プレイヤーの手札に対する知識をすべて初期化する関数.

Returns:

dict: 各プレイヤーの知識を格納した辞書

def update_knowledge_after_color_hint(self, target_player_number, color_cards_positions, color):
123  def update_knowledge_after_color_hint(self, target_player_number, color_cards_positions, color):
124    """
125    色のヒントを受け取ったときの知識を更新する.
126    
127    Args:
128        target_player_number (int): ヒントを受け取ったプレイヤーの番号
129        color_cards_positions (list): ヒントを受けたカードの位置
130        color (int): ヒントを与えられた色
131    """
132    # 1. ヒントを受けたカードに対する知識更新
133    for pos in color_cards_positions:
134      for i in range(len(self.game.knowledge[target_player_number][pos])):
135        if i != color:
136          self.game.knowledge[target_player_number][pos][i] = [0] * len(self.game.knowledge[target_player_number][pos][i])
137
138    # 2. ヒントを受けなかったカードに対して、その色は少なくともありえないので,更新
139    for pos in range(len(self.game.knowledge[target_player_number])):
140      if pos not in color_cards_positions:  # ヒントを受けたカードの位置以外
141        self.game.knowledge[target_player_number][pos][color] = [0] * len(self.game.knowledge[target_player_number][pos][color])

色のヒントを受け取ったときの知識を更新する.

Arguments:
  • target_player_number (int): ヒントを受け取ったプレイヤーの番号
  • color_cards_positions (list): ヒントを受けたカードの位置
  • color (int): ヒントを与えられた色
def update_knowledge_after_number_hint(self, target_player_number, number_cards_positions, number):
143  def update_knowledge_after_number_hint(self, target_player_number, number_cards_positions, number):
144    """
145    数字のヒントを受け取ったときの知識を更新する.
146    
147    Args:
148        target_player_number (int): ヒントを受け取ったプレイヤーの番号
149        number_cards_positions (list): ヒントを受けたカードの位置
150        number (int): ヒントを与えられた数字
151    """
152    # 1. ヒントを受けたカードに対する知識更新
153    for pos in number_cards_positions:
154      for i in range(len(self.game.knowledge[target_player_number][pos])):
155        for j in range(len(self.game.knowledge[target_player_number][pos][i])):
156          if j + 1 != number:
157            self.game.knowledge[target_player_number][pos][i][j] = 0
158
159    # 2. ヒントを受けなかったカードは、その数字は少なくともありえないので,更新
160    for pos in range(len(self.game.knowledge[target_player_number])):
161      if pos not in number_cards_positions:  # ヒントを受けたカードの位置以外
162        for i in range(len(self.game.knowledge[target_player_number][pos])):
163          self.game.knowledge[target_player_number][pos][i][number - 1] = 0

数字のヒントを受け取ったときの知識を更新する.

Arguments:
  • target_player_number (int): ヒントを受け取ったプレイヤーの番号
  • number_cards_positions (list): ヒントを受けたカードの位置
  • number (int): ヒントを与えられた数字
def update_knowledge_after_draw(self, player_number):
165  def update_knowledge_after_draw(self, player_number):
166    """
167    カードを引いた後の知識更新処理.
168    
169    Args:
170        player_number (int): カードを引いたプレイヤーの番号
171    """
172    # カードを引いた後の知識更新処理
173    new_card_knowledge = self.initialize_one_card_knowledge()
174    self.game.knowledge[player_number].append(new_card_knowledge)

カードを引いた後の知識更新処理.

Arguments:
  • player_number (int): カードを引いたプレイヤーの番号
def update_knowledge_after_play(self, player_number, card_position):
176  def update_knowledge_after_play(self, player_number, card_position):
177    """
178    カードをプレイした後の知識更新処理.
179    
180    Args:
181        player_number (int): カードをプレイしたプレイヤーの番号
182        card_position (int): プレイしたカードの位置
183    """
184    # カードをプレイした後の知識更新処理
185    del self.game.knowledge[player_number][card_position]

カードをプレイした後の知識更新処理.

Arguments:
  • player_number (int): カードをプレイしたプレイヤーの番号
  • card_position (int): プレイしたカードの位置
def update_knowledge_after_discard(self, player_number, card_position):
187  def update_knowledge_after_discard(self, player_number, card_position):
188    """
189    カードを捨てた後の知識更新処理.
190    
191    Args:
192        player_number (int): カードを捨てたプレイヤーの番号
193        card_position (int): 捨てたカードの位置
194    """
195    # カードを捨てた後の知識更新処理
196    del self.game.knowledge[player_number][card_position]

カードを捨てた後の知識更新処理.

Arguments:
  • player_number (int): カードを捨てたプレイヤーの番号
  • card_position (int): 捨てたカードの位置