hanabiapp.game.agent.internal_state_agent

  1from .agent import Agent
  2from ..action import Action
  3
  4class InternalStateAgent(Agent):
  5  """
  6  内部状態を考慮したエージェントを表現するクラス.
  7  
  8  エージェントは手札やボードの状態に基づいて,プレイ可能なカードの識別,破棄,
  9  そしてヒントの提供を戦略的に実施する.
 10  """
 11
 12  def __init__(self, name, player_number):
 13    """
 14    InternalStateAgent のコンストラクタ.
 15
 16    Args:
 17        name (str): エージェントの名前
 18        player_number (int): プレイヤーの番号
 19    """
 20    super().__init__(name, player_number)
 21    self.need_hle_convert= False
 22    self.last_playable_hint_type = None # 相手がプレイ可能カードを持っている際に数字か色のヒントを交互に出すために,前回に出したヒント(ランダムヒント除く)の種類を記憶する変数.
 23
 24  def get_possible(self,knowledge):
 25    """
 26    各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す.
 27
 28    Args:
 29        knowledge (dict): カードの知識情報
 30
 31    Returns:
 32        list: 可能性のあるカードの色とランクのリスト
 33    """
 34    possible = []
 35    for color in self.game.game_const.ALL_COLORS:
 36      for number, count in enumerate(knowledge[color]):
 37        if count > 0:
 38          possible.append((color, number + 1))  # 色と数字のペアを追加
 39    #check_type_and_dtype(possible)
 40    return possible
 41  
 42  def playable(self,possible, board):
 43    """
 44    プレイヤーの手札の中から,プレイ可能なカードがあるかを判定する関数.
 45
 46    Args:
 47        possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
 48        board (dict): 現在のボードの状態(各色ごとの進行状況)
 49
 50    Returns:
 51        bool: プレイ可能なカードが存在すればTrue,そうでなければFalse
 52    """
 53    #self.print_log("playable関数")
 54    for (color,number) in possible:
 55      #self.print_log(f"color:{color},number:{number}")
 56      #self.print_log(f"{color}色の最大値:{board[color]}")
 57      if board[color] + 1 != number:
 58        #self.print_log(f"Playable:{color,number} is False")
 59        return False # possibleのリスト内で、少なくとも1つでもplayableでないタプルが含まれていると、そのリスト全体に対してFalseが返されます
 60    #self.print_log(f"Playable:{possible} is True")
 61    return True 
 62  
 63  def discardable(self,possible, board):
 64    """
 65    プレイヤーの手札の中から,破棄可能なカードがあるかを判定する関数.
 66
 67    Args:
 68        possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
 69        board (dict): 現在のボードの状態(各色ごとの進行状況)
 70
 71    Returns:
 72        bool: 破棄可能なカードが存在すればTrue,そうでなければFalse
 73    """
 74    for (color,number) in possible:
 75      if board[color] < number: 
 76        return False
 77    #self.print_log("Discardable: ",possible)
 78    return True # ボード上のその色のカードよりも小さい数字なら破棄しても問題ない
 79
 80  def act(self, game_ins):
 81    """
 82    プレイヤーの次のアクションを決定する関数.
 83
 84    - プレイ可能なカードがあればプレイする.
 85    - 破棄可能なカードがあれば破棄する.
 86    - 相手がプレイ可能なカードを持っていればヒントを出す.
 87    - それ以外の場合は,相手が持つカードに対してランダムなヒントを提供する.
 88    - ヒントがない場合は,ランダムに手札を破棄する.
 89
 90    Args:
 91        game_ins (Game): 現在のゲームインスタンス
 92
 93    Returns:
 94        Action: 実行されるアクション
 95    """
 96    #===============================================================================================
 97    # もしプレイヤがプレイ可能カードを持っていれば,それをプレイする
 98    # 破棄可能カードを持っていたら,それを破棄する
 99    possible = []
100
101    # 己のknowledgeから,持ちうるカードの(色,数字)をリストアップ(枚数情報除く)
102    for k in game_ins.knowledge[self.player_number]:
103      possible.append(self.get_possible(k))
104      
105    # for idx, p in enumerate(possible):
106    #     self.print_log("Possible for Card {}: {}".format(idx + 1, p))
107
108    playable_cards= []
109    discardable_cards = []
110    for i, card in enumerate(possible):
111      # ボード上のその色のカードが次に必要な数字かどうかを確認
112      if self.playable(card,game_ins.board):
113        # possibleの中から,プレイ可能なカードが見つかったら、それを格納
114        playable_cards.append(i)
115        self.print_log("Internal-state:プレイ可能カードを持っていれるので,それをプレイします.")
116        return Action(game_ins.game_const.PLAY, card_position=i)
117      if self.discardable(card,game_ins.board):
118        discardable_cards.append(i)
119
120    #self.print_log(f"playable_cards:{playable_cards},discardable_cards:{discardable_cards}")
121      
122    if discardable_cards:
123      self.print_log("Internal-state:破棄可能カードを持っていれるので,それを捨てます.")
124      return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(discardable_cards))
125    #===============================================================================================
126    # もし相手がプレイ可能なカードを持っていれば,プレイヤはそのカードの色か数字に関するヒントを与える
127    opponent_playable_info = [] # (player_number,card_position)のタプルのリスト
128    ai_player_number = self.player_number
129
130    for i,(player_number,hand) in enumerate(game_ins.hands.items()):
131      if player_number != ai_player_number:
132        opponent_hand = hand
133        for card_position,(color,number) in enumerate(opponent_hand):
134          if game_ins.board[color] + 1 == number:
135            opponent_playable_info.append((player_number,card_position))
136    
137    self.print_log(f"opponent_playable_info:{opponent_playable_info}")
138    
139
140    if opponent_playable_info and game_ins.hints > 0:
141      random_index = game_ins.random.randint(0, len(opponent_playable_info) - 1)
142      player_number,card_position = opponent_playable_info[random_index] # プレイ可能情報の中からランダムに選択
143
144      if self.last_playable_hint_type is None:
145        if game_ins.random.random() < 0.5:
146          self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントがないので,半々の確率で色ヒントを出します.")
147          self.last_playable_hint_type = game_ins.game_const.HINT_COLOR
148          return Action(game_ins.game_const.HINT_COLOR, pnr=player_number, color=game_ins.hands[player_number][card_position][0])
149        else:
150          self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントがないので,半々の確率で数字ヒントを出します.")
151          self.last_playable_hint_type = game_ins.game_const.HINT_NUMBER
152          return Action(game_ins.game_const.HINT_NUMBER, pnr=player_number, number=game_ins.hands[player_number][card_position][1])
153      elif self.last_playable_hint_type == game_ins.game_const.HINT_COLOR:
154        self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントが色ヒントだったので,数字ヒントを出します.")
155        self.last_playable_hint_type = game_ins.game_const.HINT_NUMBER
156        return Action(game_ins.game_const.HINT_NUMBER, pnr=player_number, number=game_ins.hands[player_number][card_position][1])
157      else:
158        self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントが数字ヒントだったので,色ヒントを出します.")
159        self.last_playable_hint_type = game_ins.game_const.HINT_COLOR
160        return Action(game_ins.game_const.HINT_COLOR, pnr=player_number, color=game_ins.hands[player_number][card_position][0])
161    #===============================================================================================
162    # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手が情報を持っていないカードのうち1枚をランダムに選択してヒントを与える
163    ai_player_number = self.player_number
164    
165    for player in game_ins.players:
166      if player.player_number == ai_player_number:
167        continue # player_number == ai_player_numberの場合は自分自身であるため、ヒントを与える相手から除外される
168
169      # 相手の手札からランダムに1枚を選び、そのカードに対してヒントを与える準備
170      cards = list(range(len(opponent_hand)))
171      game_ins.random.shuffle(cards)
172      random_pick_card_position = cards[0] # ランダムにシャッフルして1枚目を選ぶ   
173      #self.print_log(f"random_pick_card:{random_pick_card}")
174
175      self.print_log(f"opponent_hand:{opponent_hand}")
176      self.print_log(f"cards:{cards}")
177      self.print_log(f"random_pick_card_position:{random_pick_card_position}")
178      
179      (color,number) = game_ins.hands[player.player_number][random_pick_card_position]
180      hint_type = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER]
181      if game_ins.hints > 0:
182        if game_ins.random.choice(hint_type) == game_ins.game_const.HINT_COLOR:
183          self.print_log("Internal-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち1枚をランダムに選択,色か数字,どちらかのヒントを与えます.")
184          return Action(game_ins.game_const.HINT_COLOR, pnr=player.player_number, color=color)
185        else:
186          self.print_log("Internal-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち1枚をランダムに選択,色か数字,どちらかのヒントを与えます.")
187          return Action(game_ins.game_const.HINT_NUMBER, pnr=player.player_number, number=number)
188      
189    #===============================================================================================
190    # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがない場合,自分のカードをランダムに選んで捨てる
191    
192    self.print_log("自分のカードをランダムに選んで捨てます.")
193    #print(f"random_pick_card_position:{random_pick_card_position}")
194    # c = [0,1,2,3,4]
195    # print("randomchoice:",game_ins.random.choice(c))
196    # l = [Action(game_ins.game_const.DISCARD, card_position=i) for i in range(len(game_ins.hands[player_number]))]
197    # for action in l:
198    #     print(action)
199    # return game_ins.random.choice([Action(game_ins.game_const.DISCARD, card_position=i) for i in range(len(game_ins.hands[player_number]))])
200    return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(range(game_ins.hand_size)))
class InternalStateAgent(hanabiapp.game.agent.agent.Agent):
  5class InternalStateAgent(Agent):
  6  """
  7  内部状態を考慮したエージェントを表現するクラス.
  8  
  9  エージェントは手札やボードの状態に基づいて,プレイ可能なカードの識別,破棄,
 10  そしてヒントの提供を戦略的に実施する.
 11  """
 12
 13  def __init__(self, name, player_number):
 14    """
 15    InternalStateAgent のコンストラクタ.
 16
 17    Args:
 18        name (str): エージェントの名前
 19        player_number (int): プレイヤーの番号
 20    """
 21    super().__init__(name, player_number)
 22    self.need_hle_convert= False
 23    self.last_playable_hint_type = None # 相手がプレイ可能カードを持っている際に数字か色のヒントを交互に出すために,前回に出したヒント(ランダムヒント除く)の種類を記憶する変数.
 24
 25  def get_possible(self,knowledge):
 26    """
 27    各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す.
 28
 29    Args:
 30        knowledge (dict): カードの知識情報
 31
 32    Returns:
 33        list: 可能性のあるカードの色とランクのリスト
 34    """
 35    possible = []
 36    for color in self.game.game_const.ALL_COLORS:
 37      for number, count in enumerate(knowledge[color]):
 38        if count > 0:
 39          possible.append((color, number + 1))  # 色と数字のペアを追加
 40    #check_type_and_dtype(possible)
 41    return possible
 42  
 43  def playable(self,possible, board):
 44    """
 45    プレイヤーの手札の中から,プレイ可能なカードがあるかを判定する関数.
 46
 47    Args:
 48        possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
 49        board (dict): 現在のボードの状態(各色ごとの進行状況)
 50
 51    Returns:
 52        bool: プレイ可能なカードが存在すればTrue,そうでなければFalse
 53    """
 54    #self.print_log("playable関数")
 55    for (color,number) in possible:
 56      #self.print_log(f"color:{color},number:{number}")
 57      #self.print_log(f"{color}色の最大値:{board[color]}")
 58      if board[color] + 1 != number:
 59        #self.print_log(f"Playable:{color,number} is False")
 60        return False # possibleのリスト内で、少なくとも1つでもplayableでないタプルが含まれていると、そのリスト全体に対してFalseが返されます
 61    #self.print_log(f"Playable:{possible} is True")
 62    return True 
 63  
 64  def discardable(self,possible, board):
 65    """
 66    プレイヤーの手札の中から,破棄可能なカードがあるかを判定する関数.
 67
 68    Args:
 69        possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
 70        board (dict): 現在のボードの状態(各色ごとの進行状況)
 71
 72    Returns:
 73        bool: 破棄可能なカードが存在すればTrue,そうでなければFalse
 74    """
 75    for (color,number) in possible:
 76      if board[color] < number: 
 77        return False
 78    #self.print_log("Discardable: ",possible)
 79    return True # ボード上のその色のカードよりも小さい数字なら破棄しても問題ない
 80
 81  def act(self, game_ins):
 82    """
 83    プレイヤーの次のアクションを決定する関数.
 84
 85    - プレイ可能なカードがあればプレイする.
 86    - 破棄可能なカードがあれば破棄する.
 87    - 相手がプレイ可能なカードを持っていればヒントを出す.
 88    - それ以外の場合は,相手が持つカードに対してランダムなヒントを提供する.
 89    - ヒントがない場合は,ランダムに手札を破棄する.
 90
 91    Args:
 92        game_ins (Game): 現在のゲームインスタンス
 93
 94    Returns:
 95        Action: 実行されるアクション
 96    """
 97    #===============================================================================================
 98    # もしプレイヤがプレイ可能カードを持っていれば,それをプレイする
 99    # 破棄可能カードを持っていたら,それを破棄する
100    possible = []
101
102    # 己のknowledgeから,持ちうるカードの(色,数字)をリストアップ(枚数情報除く)
103    for k in game_ins.knowledge[self.player_number]:
104      possible.append(self.get_possible(k))
105      
106    # for idx, p in enumerate(possible):
107    #     self.print_log("Possible for Card {}: {}".format(idx + 1, p))
108
109    playable_cards= []
110    discardable_cards = []
111    for i, card in enumerate(possible):
112      # ボード上のその色のカードが次に必要な数字かどうかを確認
113      if self.playable(card,game_ins.board):
114        # possibleの中から,プレイ可能なカードが見つかったら、それを格納
115        playable_cards.append(i)
116        self.print_log("Internal-state:プレイ可能カードを持っていれるので,それをプレイします.")
117        return Action(game_ins.game_const.PLAY, card_position=i)
118      if self.discardable(card,game_ins.board):
119        discardable_cards.append(i)
120
121    #self.print_log(f"playable_cards:{playable_cards},discardable_cards:{discardable_cards}")
122      
123    if discardable_cards:
124      self.print_log("Internal-state:破棄可能カードを持っていれるので,それを捨てます.")
125      return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(discardable_cards))
126    #===============================================================================================
127    # もし相手がプレイ可能なカードを持っていれば,プレイヤはそのカードの色か数字に関するヒントを与える
128    opponent_playable_info = [] # (player_number,card_position)のタプルのリスト
129    ai_player_number = self.player_number
130
131    for i,(player_number,hand) in enumerate(game_ins.hands.items()):
132      if player_number != ai_player_number:
133        opponent_hand = hand
134        for card_position,(color,number) in enumerate(opponent_hand):
135          if game_ins.board[color] + 1 == number:
136            opponent_playable_info.append((player_number,card_position))
137    
138    self.print_log(f"opponent_playable_info:{opponent_playable_info}")
139    
140
141    if opponent_playable_info and game_ins.hints > 0:
142      random_index = game_ins.random.randint(0, len(opponent_playable_info) - 1)
143      player_number,card_position = opponent_playable_info[random_index] # プレイ可能情報の中からランダムに選択
144
145      if self.last_playable_hint_type is None:
146        if game_ins.random.random() < 0.5:
147          self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントがないので,半々の確率で色ヒントを出します.")
148          self.last_playable_hint_type = game_ins.game_const.HINT_COLOR
149          return Action(game_ins.game_const.HINT_COLOR, pnr=player_number, color=game_ins.hands[player_number][card_position][0])
150        else:
151          self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントがないので,半々の確率で数字ヒントを出します.")
152          self.last_playable_hint_type = game_ins.game_const.HINT_NUMBER
153          return Action(game_ins.game_const.HINT_NUMBER, pnr=player_number, number=game_ins.hands[player_number][card_position][1])
154      elif self.last_playable_hint_type == game_ins.game_const.HINT_COLOR:
155        self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントが色ヒントだったので,数字ヒントを出します.")
156        self.last_playable_hint_type = game_ins.game_const.HINT_NUMBER
157        return Action(game_ins.game_const.HINT_NUMBER, pnr=player_number, number=game_ins.hands[player_number][card_position][1])
158      else:
159        self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントが数字ヒントだったので,色ヒントを出します.")
160        self.last_playable_hint_type = game_ins.game_const.HINT_COLOR
161        return Action(game_ins.game_const.HINT_COLOR, pnr=player_number, color=game_ins.hands[player_number][card_position][0])
162    #===============================================================================================
163    # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手が情報を持っていないカードのうち1枚をランダムに選択してヒントを与える
164    ai_player_number = self.player_number
165    
166    for player in game_ins.players:
167      if player.player_number == ai_player_number:
168        continue # player_number == ai_player_numberの場合は自分自身であるため、ヒントを与える相手から除外される
169
170      # 相手の手札からランダムに1枚を選び、そのカードに対してヒントを与える準備
171      cards = list(range(len(opponent_hand)))
172      game_ins.random.shuffle(cards)
173      random_pick_card_position = cards[0] # ランダムにシャッフルして1枚目を選ぶ   
174      #self.print_log(f"random_pick_card:{random_pick_card}")
175
176      self.print_log(f"opponent_hand:{opponent_hand}")
177      self.print_log(f"cards:{cards}")
178      self.print_log(f"random_pick_card_position:{random_pick_card_position}")
179      
180      (color,number) = game_ins.hands[player.player_number][random_pick_card_position]
181      hint_type = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER]
182      if game_ins.hints > 0:
183        if game_ins.random.choice(hint_type) == game_ins.game_const.HINT_COLOR:
184          self.print_log("Internal-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち1枚をランダムに選択,色か数字,どちらかのヒントを与えます.")
185          return Action(game_ins.game_const.HINT_COLOR, pnr=player.player_number, color=color)
186        else:
187          self.print_log("Internal-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち1枚をランダムに選択,色か数字,どちらかのヒントを与えます.")
188          return Action(game_ins.game_const.HINT_NUMBER, pnr=player.player_number, number=number)
189      
190    #===============================================================================================
191    # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがない場合,自分のカードをランダムに選んで捨てる
192    
193    self.print_log("自分のカードをランダムに選んで捨てます.")
194    #print(f"random_pick_card_position:{random_pick_card_position}")
195    # c = [0,1,2,3,4]
196    # print("randomchoice:",game_ins.random.choice(c))
197    # l = [Action(game_ins.game_const.DISCARD, card_position=i) for i in range(len(game_ins.hands[player_number]))]
198    # for action in l:
199    #     print(action)
200    # return game_ins.random.choice([Action(game_ins.game_const.DISCARD, card_position=i) for i in range(len(game_ins.hands[player_number]))])
201    return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(range(game_ins.hand_size)))

内部状態を考慮したエージェントを表現するクラス.

エージェントは手札やボードの状態に基づいて,プレイ可能なカードの識別,破棄, そしてヒントの提供を戦略的に実施する.

InternalStateAgent(name, player_number)
13  def __init__(self, name, player_number):
14    """
15    InternalStateAgent のコンストラクタ.
16
17    Args:
18        name (str): エージェントの名前
19        player_number (int): プレイヤーの番号
20    """
21    super().__init__(name, player_number)
22    self.need_hle_convert= False
23    self.last_playable_hint_type = None # 相手がプレイ可能カードを持っている際に数字か色のヒントを交互に出すために,前回に出したヒント(ランダムヒント除く)の種類を記憶する変数.

InternalStateAgent のコンストラクタ.

Arguments:
  • name (str): エージェントの名前
  • player_number (int): プレイヤーの番号
need_hle_convert
last_playable_hint_type
def get_possible(self, knowledge):
25  def get_possible(self,knowledge):
26    """
27    各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す.
28
29    Args:
30        knowledge (dict): カードの知識情報
31
32    Returns:
33        list: 可能性のあるカードの色とランクのリスト
34    """
35    possible = []
36    for color in self.game.game_const.ALL_COLORS:
37      for number, count in enumerate(knowledge[color]):
38        if count > 0:
39          possible.append((color, number + 1))  # 色と数字のペアを追加
40    #check_type_and_dtype(possible)
41    return possible

各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す.

Arguments:
  • knowledge (dict): カードの知識情報
Returns:

list: 可能性のあるカードの色とランクのリスト

def playable(self, possible, board):
43  def playable(self,possible, board):
44    """
45    プレイヤーの手札の中から,プレイ可能なカードがあるかを判定する関数.
46
47    Args:
48        possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
49        board (dict): 現在のボードの状態(各色ごとの進行状況)
50
51    Returns:
52        bool: プレイ可能なカードが存在すればTrue,そうでなければFalse
53    """
54    #self.print_log("playable関数")
55    for (color,number) in possible:
56      #self.print_log(f"color:{color},number:{number}")
57      #self.print_log(f"{color}色の最大値:{board[color]}")
58      if board[color] + 1 != number:
59        #self.print_log(f"Playable:{color,number} is False")
60        return False # possibleのリスト内で、少なくとも1つでもplayableでないタプルが含まれていると、そのリスト全体に対してFalseが返されます
61    #self.print_log(f"Playable:{possible} is True")
62    return True 

プレイヤーの手札の中から,プレイ可能なカードがあるかを判定する関数.

Arguments:
  • possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
  • board (dict): 現在のボードの状態(各色ごとの進行状況)
Returns:

bool: プレイ可能なカードが存在すればTrue,そうでなければFalse

def discardable(self, possible, board):
64  def discardable(self,possible, board):
65    """
66    プレイヤーの手札の中から,破棄可能なカードがあるかを判定する関数.
67
68    Args:
69        possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
70        board (dict): 現在のボードの状態(各色ごとの進行状況)
71
72    Returns:
73        bool: 破棄可能なカードが存在すればTrue,そうでなければFalse
74    """
75    for (color,number) in possible:
76      if board[color] < number: 
77        return False
78    #self.print_log("Discardable: ",possible)
79    return True # ボード上のその色のカードよりも小さい数字なら破棄しても問題ない

プレイヤーの手札の中から,破棄可能なカードがあるかを判定する関数.

Arguments:
  • possible (list): プレイヤーの知識から導出されたカードの可能性のリスト
  • board (dict): 現在のボードの状態(各色ごとの進行状況)
Returns:

bool: 破棄可能なカードが存在すればTrue,そうでなければFalse

def act(self, game_ins):
 81  def act(self, game_ins):
 82    """
 83    プレイヤーの次のアクションを決定する関数.
 84
 85    - プレイ可能なカードがあればプレイする.
 86    - 破棄可能なカードがあれば破棄する.
 87    - 相手がプレイ可能なカードを持っていればヒントを出す.
 88    - それ以外の場合は,相手が持つカードに対してランダムなヒントを提供する.
 89    - ヒントがない場合は,ランダムに手札を破棄する.
 90
 91    Args:
 92        game_ins (Game): 現在のゲームインスタンス
 93
 94    Returns:
 95        Action: 実行されるアクション
 96    """
 97    #===============================================================================================
 98    # もしプレイヤがプレイ可能カードを持っていれば,それをプレイする
 99    # 破棄可能カードを持っていたら,それを破棄する
100    possible = []
101
102    # 己のknowledgeから,持ちうるカードの(色,数字)をリストアップ(枚数情報除く)
103    for k in game_ins.knowledge[self.player_number]:
104      possible.append(self.get_possible(k))
105      
106    # for idx, p in enumerate(possible):
107    #     self.print_log("Possible for Card {}: {}".format(idx + 1, p))
108
109    playable_cards= []
110    discardable_cards = []
111    for i, card in enumerate(possible):
112      # ボード上のその色のカードが次に必要な数字かどうかを確認
113      if self.playable(card,game_ins.board):
114        # possibleの中から,プレイ可能なカードが見つかったら、それを格納
115        playable_cards.append(i)
116        self.print_log("Internal-state:プレイ可能カードを持っていれるので,それをプレイします.")
117        return Action(game_ins.game_const.PLAY, card_position=i)
118      if self.discardable(card,game_ins.board):
119        discardable_cards.append(i)
120
121    #self.print_log(f"playable_cards:{playable_cards},discardable_cards:{discardable_cards}")
122      
123    if discardable_cards:
124      self.print_log("Internal-state:破棄可能カードを持っていれるので,それを捨てます.")
125      return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(discardable_cards))
126    #===============================================================================================
127    # もし相手がプレイ可能なカードを持っていれば,プレイヤはそのカードの色か数字に関するヒントを与える
128    opponent_playable_info = [] # (player_number,card_position)のタプルのリスト
129    ai_player_number = self.player_number
130
131    for i,(player_number,hand) in enumerate(game_ins.hands.items()):
132      if player_number != ai_player_number:
133        opponent_hand = hand
134        for card_position,(color,number) in enumerate(opponent_hand):
135          if game_ins.board[color] + 1 == number:
136            opponent_playable_info.append((player_number,card_position))
137    
138    self.print_log(f"opponent_playable_info:{opponent_playable_info}")
139    
140
141    if opponent_playable_info and game_ins.hints > 0:
142      random_index = game_ins.random.randint(0, len(opponent_playable_info) - 1)
143      player_number,card_position = opponent_playable_info[random_index] # プレイ可能情報の中からランダムに選択
144
145      if self.last_playable_hint_type is None:
146        if game_ins.random.random() < 0.5:
147          self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントがないので,半々の確率で色ヒントを出します.")
148          self.last_playable_hint_type = game_ins.game_const.HINT_COLOR
149          return Action(game_ins.game_const.HINT_COLOR, pnr=player_number, color=game_ins.hands[player_number][card_position][0])
150        else:
151          self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントがないので,半々の確率で数字ヒントを出します.")
152          self.last_playable_hint_type = game_ins.game_const.HINT_NUMBER
153          return Action(game_ins.game_const.HINT_NUMBER, pnr=player_number, number=game_ins.hands[player_number][card_position][1])
154      elif self.last_playable_hint_type == game_ins.game_const.HINT_COLOR:
155        self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントが色ヒントだったので,数字ヒントを出します.")
156        self.last_playable_hint_type = game_ins.game_const.HINT_NUMBER
157        return Action(game_ins.game_const.HINT_NUMBER, pnr=player_number, number=game_ins.hands[player_number][card_position][1])
158      else:
159        self.print_log("Internal-state:相手がプレイ可能なカードを持っており,前回のヒントが数字ヒントだったので,色ヒントを出します.")
160        self.last_playable_hint_type = game_ins.game_const.HINT_COLOR
161        return Action(game_ins.game_const.HINT_COLOR, pnr=player_number, color=game_ins.hands[player_number][card_position][0])
162    #===============================================================================================
163    # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手が情報を持っていないカードのうち1枚をランダムに選択してヒントを与える
164    ai_player_number = self.player_number
165    
166    for player in game_ins.players:
167      if player.player_number == ai_player_number:
168        continue # player_number == ai_player_numberの場合は自分自身であるため、ヒントを与える相手から除外される
169
170      # 相手の手札からランダムに1枚を選び、そのカードに対してヒントを与える準備
171      cards = list(range(len(opponent_hand)))
172      game_ins.random.shuffle(cards)
173      random_pick_card_position = cards[0] # ランダムにシャッフルして1枚目を選ぶ   
174      #self.print_log(f"random_pick_card:{random_pick_card}")
175
176      self.print_log(f"opponent_hand:{opponent_hand}")
177      self.print_log(f"cards:{cards}")
178      self.print_log(f"random_pick_card_position:{random_pick_card_position}")
179      
180      (color,number) = game_ins.hands[player.player_number][random_pick_card_position]
181      hint_type = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER]
182      if game_ins.hints > 0:
183        if game_ins.random.choice(hint_type) == game_ins.game_const.HINT_COLOR:
184          self.print_log("Internal-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち1枚をランダムに選択,色か数字,どちらかのヒントを与えます.")
185          return Action(game_ins.game_const.HINT_COLOR, pnr=player.player_number, color=color)
186        else:
187          self.print_log("Internal-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち1枚をランダムに選択,色か数字,どちらかのヒントを与えます.")
188          return Action(game_ins.game_const.HINT_NUMBER, pnr=player.player_number, number=number)
189      
190    #===============================================================================================
191    # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがない場合,自分のカードをランダムに選んで捨てる
192    
193    self.print_log("自分のカードをランダムに選んで捨てます.")
194    #print(f"random_pick_card_position:{random_pick_card_position}")
195    # c = [0,1,2,3,4]
196    # print("randomchoice:",game_ins.random.choice(c))
197    # l = [Action(game_ins.game_const.DISCARD, card_position=i) for i in range(len(game_ins.hands[player_number]))]
198    # for action in l:
199    #     print(action)
200    # return game_ins.random.choice([Action(game_ins.game_const.DISCARD, card_position=i) for i in range(len(game_ins.hands[player_number]))])
201    return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(range(game_ins.hand_size)))

プレイヤーの次のアクションを決定する関数.

  • プレイ可能なカードがあればプレイする.
  • 破棄可能なカードがあれば破棄する.
  • 相手がプレイ可能なカードを持っていればヒントを出す.
  • それ以外の場合は,相手が持つカードに対してランダムなヒントを提供する.
  • ヒントがない場合は,ランダムに手札を破棄する.
Arguments:
  • game_ins (Game): 現在のゲームインスタンス
Returns:

Action: 実行されるアクション