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)))
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): プレイヤーの番号
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: 実行されるアクション