hanabiapp.game.agent.(inbug)outer_state_agent
1from .agent import Agent 2from ..action import Action 3 4class OuterStateAgent(Agent): 5 def __init__(self, name, player_number): 6 super().__init__(name, player_number) 7 self.need_hle_convert= False 8 self.already_hints = {} 9 10 def get_possible(self,knowledge): 11 """ 12 各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す。 13 """ 14 possible = [] 15 for color in self.game.game_const.ALL_COLORS: 16 for number, count in enumerate(knowledge[color]): 17 if count > 0: 18 possible.append((color, number + 1)) # 色と数字のペアを追加 19 #check_type_and_dtype(possible) 20 return possible 21 22 def playable(self,possible, board): 23 #print("playable関数") 24 for (color,number) in possible: 25 #print(f"color:{color},number:{number}") #print(f"{color}色の最大値:{board[color]}") 26 if board[color] + 1 != number: 27 #print(f"Playable:{color,number} is False") 28 return False # possibleのリスト内で、少なくとも1つでもplayableでないタプルが含まれていると、そのリスト全体に対してFalseが返されます 29 #print(f"Playable:{possible} is True") 30 return True 31 32 def discardable(self,possible, board): 33 for (color,number) in possible: 34 if board[color] < number: 35 return False 36 #print("Discardable: ",possible) 37 return True # ボード上のその色のカードよりも小さい数字なら破棄しても問題ない 38 39 def act(self, game_ins): 40 """ 41 プレイヤーの次のアクションを決定するメソッド 42 valid_actions: 現在のターンでプレイヤーが取ることのできる有効なアクションのリスト 43 """ 44 #=============================================================================================== 45 # もしプレイヤがプレイ可能カードを持っていれば,それをプレイする 46 # 破棄可能カードを持っていたら,それを破棄する 47 possible = [] 48 49 # 己のknowledgeから,持ちうるカードの(色,数字)をリストアップ(枚数情報除く) 50 for k in game_ins.knowledge[self.player_number]: 51 possible.append(self.get_possible(k)) 52 53 # for idx, p in enumerate(possible): 54 # print("Possible for Card {}: {}".format(idx + 1, p)) 55 56 playable_cards= [] 57 discardable_cards = [] 58 for i, card in enumerate(possible): 59 # ボード上のその色のカードが次に必要な数字かどうかを確認 60 if self.playable(card,game_ins.board): 61 # possibleの中から,プレイ可能なカードが見つかったら、それを格納 62 playable_cards.append(i) 63 if self.discardable(card,game_ins.board): 64 discardable_cards.append(i) 65 66 #print(f"playable_cards:{playable_cards},discardable_cards:{discardable_cards}") 67 if playable_cards: 68 print("outer-state:プレイ可能カードを持っていれるので,それをプレイします.") 69 return Action(game_ins.game_const.PLAY, card_position=game_ins.random.choice(playable_cards)) 70 if discardable_cards: 71 print("outer-state:破棄可能カードを持っていれるので,それを捨てます.") 72 return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(discardable_cards)) 73 #=============================================================================================== 74 # もし相手がプレイ可能なカードを持っていれば,プレイヤはそのカードの色か数字に関するヒントを与える 75 # すでに出したヒントは出さない 76 77 opponent_playable_info = [] # (player_number,card_position)のタプルのリスト 78 ai_player_number = self.player_number 79 80 for i,(player_number,opponent_hand) in enumerate(game_ins.hands.items()): 81 if player_number != ai_player_number: 82 for card_position,(color,number) in enumerate(opponent_hand): 83 if game_ins.board[color] + 1 == number: 84 opponent_playable_info.append((player_number,card_position)) 85 86 opponent_playable_info.sort(key=lambda x: x[1]) # card_positionでソート 87 print(f"opponent_playable_info:{opponent_playable_info}") 88 89 while opponent_playable_info and game_ins.hints > 0: 90 player_number,card_position = opponent_playable_info[0] # 一個目のプレイ可能な情報を選択 91 92 hinttype = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER] 93 94 if (card_position, player_number) not in self.already_hints: 95 self.already_hints[(card_position, player_number)] = [] # ヒントを与えたことを記録するための枠を作る 96 97 # print(f"self.already_hints:{self.already_hints}") 98 99 for h in self.already_hints[(card_position, player_number)]: 100 hinttype.remove(h) # 既に数字,色ヒントを出した状態であれば,それを出さないようにhinttypeから除外する 101 102 # print(f"hinttype:{hinttype}") 103 t = None 104 if hinttype: 105 t = game_ins.random.choice(hinttype) 106 107 108 if t == game_ins.game_const.HINT_NUMBER: 109 self.already_hints[(card_position, player_number)].append(game_ins.game_const.HINT_NUMBER) 110 print("outer-state:相手がプレイ可能なカードを持っているので,半々の確率で色ヒントか数字ヒントを出します.(ただし,すでに出したヒントは出さない)") 111 return Action(t, pnr=player_number, number=game_ins.hands[player_number][card_position][1]) 112 elif t == game_ins.game_const.HINT_COLOR: 113 self.already_hints[(card_position, player_number)].append(game_ins.game_const.HINT_COLOR) 114 print("outer-state:相手がプレイ可能なカードを持っているので,半々の確率で色ヒントか数字ヒントを出します.(ただし,すでに出したヒントは出さない)") 115 return Action(t, pnr=player_number, color=game_ins.hands[player_number][card_position][0]) 116 117 opponent_playable_info = opponent_playable_info[1:] # 一個目のプレイ可能な情報を削除 118 119 #=============================================================================================== 120 # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手が情報を持っていないカードのうち1枚をランダムに選択してヒントを与える 121 ai_player_number = self.player_number 122 for player in game_ins.players: 123 if player.player_number == ai_player_number: 124 continue 125 126 cards = list(range(game_ins.hand_size)) 127 game_ins.random.shuffle(cards) 128 random_pick_card_position = cards[0] 129 130 (color,number) = game_ins.hands[player.player_number][random_pick_card_position] 131 132 133 hinttype = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER] 134 135 if (random_pick_card_position,player.player_number) not in self.already_hints: 136 self.already_hints[(random_pick_card_position,player.player_number)] = [] 137 138 for h in self.already_hints[(random_pick_card_position,player.player_number)]: 139 hinttype.remove(h) 140 141 print(f"self.already_hints:{self.already_hints}") 142 print(f"hinttype:{hinttype}") 143 144 if hinttype and game_ins.hints > 0: 145 if game_ins.random.choice(hinttype) == game_ins.game_const.HINT_COLOR: 146 self.already_hints[(random_pick_card_position,player.player_number)].append(game_ins.game_const.HINT_COLOR) 147 print("outer-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち,情報を持っていないカードをランダムに選択,ヒントを与えます.") 148 return Action(game_ins.game_const.HINT_COLOR, pnr=i, color=color) 149 else: 150 self.already_hints[(random_pick_card_position,player.player_number)].append(game_ins.game_const.HINT_NUMBER) 151 print("outer-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち,情報を持っていないカードをランダムに選択,ヒントを与えます.") 152 return Action(game_ins.game_const.HINT_NUMBER, pnr=i, number=number) 153 154 #=============================================================================================== 155 # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがない場合,自分のカードをランダムに選んで捨てる 156 157 print("自分のカードをランダムに選んで捨てます.") 158 #print(f"random_pick_card_position:{random_pick_card_position}") 159 return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(range(game_ins.hand_size)))
5class OuterStateAgent(Agent): 6 def __init__(self, name, player_number): 7 super().__init__(name, player_number) 8 self.need_hle_convert= False 9 self.already_hints = {} 10 11 def get_possible(self,knowledge): 12 """ 13 各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す。 14 """ 15 possible = [] 16 for color in self.game.game_const.ALL_COLORS: 17 for number, count in enumerate(knowledge[color]): 18 if count > 0: 19 possible.append((color, number + 1)) # 色と数字のペアを追加 20 #check_type_and_dtype(possible) 21 return possible 22 23 def playable(self,possible, board): 24 #print("playable関数") 25 for (color,number) in possible: 26 #print(f"color:{color},number:{number}") #print(f"{color}色の最大値:{board[color]}") 27 if board[color] + 1 != number: 28 #print(f"Playable:{color,number} is False") 29 return False # possibleのリスト内で、少なくとも1つでもplayableでないタプルが含まれていると、そのリスト全体に対してFalseが返されます 30 #print(f"Playable:{possible} is True") 31 return True 32 33 def discardable(self,possible, board): 34 for (color,number) in possible: 35 if board[color] < number: 36 return False 37 #print("Discardable: ",possible) 38 return True # ボード上のその色のカードよりも小さい数字なら破棄しても問題ない 39 40 def act(self, game_ins): 41 """ 42 プレイヤーの次のアクションを決定するメソッド 43 valid_actions: 現在のターンでプレイヤーが取ることのできる有効なアクションのリスト 44 """ 45 #=============================================================================================== 46 # もしプレイヤがプレイ可能カードを持っていれば,それをプレイする 47 # 破棄可能カードを持っていたら,それを破棄する 48 possible = [] 49 50 # 己のknowledgeから,持ちうるカードの(色,数字)をリストアップ(枚数情報除く) 51 for k in game_ins.knowledge[self.player_number]: 52 possible.append(self.get_possible(k)) 53 54 # for idx, p in enumerate(possible): 55 # print("Possible for Card {}: {}".format(idx + 1, p)) 56 57 playable_cards= [] 58 discardable_cards = [] 59 for i, card in enumerate(possible): 60 # ボード上のその色のカードが次に必要な数字かどうかを確認 61 if self.playable(card,game_ins.board): 62 # possibleの中から,プレイ可能なカードが見つかったら、それを格納 63 playable_cards.append(i) 64 if self.discardable(card,game_ins.board): 65 discardable_cards.append(i) 66 67 #print(f"playable_cards:{playable_cards},discardable_cards:{discardable_cards}") 68 if playable_cards: 69 print("outer-state:プレイ可能カードを持っていれるので,それをプレイします.") 70 return Action(game_ins.game_const.PLAY, card_position=game_ins.random.choice(playable_cards)) 71 if discardable_cards: 72 print("outer-state:破棄可能カードを持っていれるので,それを捨てます.") 73 return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(discardable_cards)) 74 #=============================================================================================== 75 # もし相手がプレイ可能なカードを持っていれば,プレイヤはそのカードの色か数字に関するヒントを与える 76 # すでに出したヒントは出さない 77 78 opponent_playable_info = [] # (player_number,card_position)のタプルのリスト 79 ai_player_number = self.player_number 80 81 for i,(player_number,opponent_hand) in enumerate(game_ins.hands.items()): 82 if player_number != ai_player_number: 83 for card_position,(color,number) in enumerate(opponent_hand): 84 if game_ins.board[color] + 1 == number: 85 opponent_playable_info.append((player_number,card_position)) 86 87 opponent_playable_info.sort(key=lambda x: x[1]) # card_positionでソート 88 print(f"opponent_playable_info:{opponent_playable_info}") 89 90 while opponent_playable_info and game_ins.hints > 0: 91 player_number,card_position = opponent_playable_info[0] # 一個目のプレイ可能な情報を選択 92 93 hinttype = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER] 94 95 if (card_position, player_number) not in self.already_hints: 96 self.already_hints[(card_position, player_number)] = [] # ヒントを与えたことを記録するための枠を作る 97 98 # print(f"self.already_hints:{self.already_hints}") 99 100 for h in self.already_hints[(card_position, player_number)]: 101 hinttype.remove(h) # 既に数字,色ヒントを出した状態であれば,それを出さないようにhinttypeから除外する 102 103 # print(f"hinttype:{hinttype}") 104 t = None 105 if hinttype: 106 t = game_ins.random.choice(hinttype) 107 108 109 if t == game_ins.game_const.HINT_NUMBER: 110 self.already_hints[(card_position, player_number)].append(game_ins.game_const.HINT_NUMBER) 111 print("outer-state:相手がプレイ可能なカードを持っているので,半々の確率で色ヒントか数字ヒントを出します.(ただし,すでに出したヒントは出さない)") 112 return Action(t, pnr=player_number, number=game_ins.hands[player_number][card_position][1]) 113 elif t == game_ins.game_const.HINT_COLOR: 114 self.already_hints[(card_position, player_number)].append(game_ins.game_const.HINT_COLOR) 115 print("outer-state:相手がプレイ可能なカードを持っているので,半々の確率で色ヒントか数字ヒントを出します.(ただし,すでに出したヒントは出さない)") 116 return Action(t, pnr=player_number, color=game_ins.hands[player_number][card_position][0]) 117 118 opponent_playable_info = opponent_playable_info[1:] # 一個目のプレイ可能な情報を削除 119 120 #=============================================================================================== 121 # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手が情報を持っていないカードのうち1枚をランダムに選択してヒントを与える 122 ai_player_number = self.player_number 123 for player in game_ins.players: 124 if player.player_number == ai_player_number: 125 continue 126 127 cards = list(range(game_ins.hand_size)) 128 game_ins.random.shuffle(cards) 129 random_pick_card_position = cards[0] 130 131 (color,number) = game_ins.hands[player.player_number][random_pick_card_position] 132 133 134 hinttype = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER] 135 136 if (random_pick_card_position,player.player_number) not in self.already_hints: 137 self.already_hints[(random_pick_card_position,player.player_number)] = [] 138 139 for h in self.already_hints[(random_pick_card_position,player.player_number)]: 140 hinttype.remove(h) 141 142 print(f"self.already_hints:{self.already_hints}") 143 print(f"hinttype:{hinttype}") 144 145 if hinttype and game_ins.hints > 0: 146 if game_ins.random.choice(hinttype) == game_ins.game_const.HINT_COLOR: 147 self.already_hints[(random_pick_card_position,player.player_number)].append(game_ins.game_const.HINT_COLOR) 148 print("outer-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち,情報を持っていないカードをランダムに選択,ヒントを与えます.") 149 return Action(game_ins.game_const.HINT_COLOR, pnr=i, color=color) 150 else: 151 self.already_hints[(random_pick_card_position,player.player_number)].append(game_ins.game_const.HINT_NUMBER) 152 print("outer-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち,情報を持っていないカードをランダムに選択,ヒントを与えます.") 153 return Action(game_ins.game_const.HINT_NUMBER, pnr=i, number=number) 154 155 #=============================================================================================== 156 # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがない場合,自分のカードをランダムに選んで捨てる 157 158 print("自分のカードをランダムに選んで捨てます.") 159 #print(f"random_pick_card_position:{random_pick_card_position}") 160 return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(range(game_ins.hand_size)))
エージェントを表現する抽象クラス.
ゲームのプレイヤーとして動作するエージェントの基底クラスであり, すべてのエージェントが共通して持つべきインターフェースを定義する.
Attributes:
- game_const (GameConst): ゲームの定数
- name (str): エージェントの名前
- player_number (int): エージェントの番号
- need_hle_convert (bool): HLE形式の変換が必要かどうか
- game (Game): ゲームのインスタンス(後で設定される)
- is_cui (bool): CUIモードかどうか
OuterStateAgent(name, player_number)
6 def __init__(self, name, player_number): 7 super().__init__(name, player_number) 8 self.need_hle_convert= False 9 self.already_hints = {}
エージェントの初期化.
Arguments:
- name (str): エージェントの名前
- player_number (int): エージェントの番号
- need_hle_convert (bool, optional): HLE形式の変換が必要かどうか(デフォルトはTrue)
def
get_possible(self, knowledge):
11 def get_possible(self,knowledge): 12 """ 13 各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す。 14 """ 15 possible = [] 16 for color in self.game.game_const.ALL_COLORS: 17 for number, count in enumerate(knowledge[color]): 18 if count > 0: 19 possible.append((color, number + 1)) # 色と数字のペアを追加 20 #check_type_and_dtype(possible) 21 return possible
各カードに対する知識に基づいて、プレイヤーが持っている可能性があるカードのリストを返す。
def
playable(self, possible, board):
23 def playable(self,possible, board): 24 #print("playable関数") 25 for (color,number) in possible: 26 #print(f"color:{color},number:{number}") #print(f"{color}色の最大値:{board[color]}") 27 if board[color] + 1 != number: 28 #print(f"Playable:{color,number} is False") 29 return False # possibleのリスト内で、少なくとも1つでもplayableでないタプルが含まれていると、そのリスト全体に対してFalseが返されます 30 #print(f"Playable:{possible} is True") 31 return True
def
act(self, game_ins):
40 def act(self, game_ins): 41 """ 42 プレイヤーの次のアクションを決定するメソッド 43 valid_actions: 現在のターンでプレイヤーが取ることのできる有効なアクションのリスト 44 """ 45 #=============================================================================================== 46 # もしプレイヤがプレイ可能カードを持っていれば,それをプレイする 47 # 破棄可能カードを持っていたら,それを破棄する 48 possible = [] 49 50 # 己のknowledgeから,持ちうるカードの(色,数字)をリストアップ(枚数情報除く) 51 for k in game_ins.knowledge[self.player_number]: 52 possible.append(self.get_possible(k)) 53 54 # for idx, p in enumerate(possible): 55 # print("Possible for Card {}: {}".format(idx + 1, p)) 56 57 playable_cards= [] 58 discardable_cards = [] 59 for i, card in enumerate(possible): 60 # ボード上のその色のカードが次に必要な数字かどうかを確認 61 if self.playable(card,game_ins.board): 62 # possibleの中から,プレイ可能なカードが見つかったら、それを格納 63 playable_cards.append(i) 64 if self.discardable(card,game_ins.board): 65 discardable_cards.append(i) 66 67 #print(f"playable_cards:{playable_cards},discardable_cards:{discardable_cards}") 68 if playable_cards: 69 print("outer-state:プレイ可能カードを持っていれるので,それをプレイします.") 70 return Action(game_ins.game_const.PLAY, card_position=game_ins.random.choice(playable_cards)) 71 if discardable_cards: 72 print("outer-state:破棄可能カードを持っていれるので,それを捨てます.") 73 return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(discardable_cards)) 74 #=============================================================================================== 75 # もし相手がプレイ可能なカードを持っていれば,プレイヤはそのカードの色か数字に関するヒントを与える 76 # すでに出したヒントは出さない 77 78 opponent_playable_info = [] # (player_number,card_position)のタプルのリスト 79 ai_player_number = self.player_number 80 81 for i,(player_number,opponent_hand) in enumerate(game_ins.hands.items()): 82 if player_number != ai_player_number: 83 for card_position,(color,number) in enumerate(opponent_hand): 84 if game_ins.board[color] + 1 == number: 85 opponent_playable_info.append((player_number,card_position)) 86 87 opponent_playable_info.sort(key=lambda x: x[1]) # card_positionでソート 88 print(f"opponent_playable_info:{opponent_playable_info}") 89 90 while opponent_playable_info and game_ins.hints > 0: 91 player_number,card_position = opponent_playable_info[0] # 一個目のプレイ可能な情報を選択 92 93 hinttype = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER] 94 95 if (card_position, player_number) not in self.already_hints: 96 self.already_hints[(card_position, player_number)] = [] # ヒントを与えたことを記録するための枠を作る 97 98 # print(f"self.already_hints:{self.already_hints}") 99 100 for h in self.already_hints[(card_position, player_number)]: 101 hinttype.remove(h) # 既に数字,色ヒントを出した状態であれば,それを出さないようにhinttypeから除外する 102 103 # print(f"hinttype:{hinttype}") 104 t = None 105 if hinttype: 106 t = game_ins.random.choice(hinttype) 107 108 109 if t == game_ins.game_const.HINT_NUMBER: 110 self.already_hints[(card_position, player_number)].append(game_ins.game_const.HINT_NUMBER) 111 print("outer-state:相手がプレイ可能なカードを持っているので,半々の確率で色ヒントか数字ヒントを出します.(ただし,すでに出したヒントは出さない)") 112 return Action(t, pnr=player_number, number=game_ins.hands[player_number][card_position][1]) 113 elif t == game_ins.game_const.HINT_COLOR: 114 self.already_hints[(card_position, player_number)].append(game_ins.game_const.HINT_COLOR) 115 print("outer-state:相手がプレイ可能なカードを持っているので,半々の確率で色ヒントか数字ヒントを出します.(ただし,すでに出したヒントは出さない)") 116 return Action(t, pnr=player_number, color=game_ins.hands[player_number][card_position][0]) 117 118 opponent_playable_info = opponent_playable_info[1:] # 一個目のプレイ可能な情報を削除 119 120 #=============================================================================================== 121 # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手が情報を持っていないカードのうち1枚をランダムに選択してヒントを与える 122 ai_player_number = self.player_number 123 for player in game_ins.players: 124 if player.player_number == ai_player_number: 125 continue 126 127 cards = list(range(game_ins.hand_size)) 128 game_ins.random.shuffle(cards) 129 random_pick_card_position = cards[0] 130 131 (color,number) = game_ins.hands[player.player_number][random_pick_card_position] 132 133 134 hinttype = [game_ins.game_const.HINT_COLOR, game_ins.game_const.HINT_NUMBER] 135 136 if (random_pick_card_position,player.player_number) not in self.already_hints: 137 self.already_hints[(random_pick_card_position,player.player_number)] = [] 138 139 for h in self.already_hints[(random_pick_card_position,player.player_number)]: 140 hinttype.remove(h) 141 142 print(f"self.already_hints:{self.already_hints}") 143 print(f"hinttype:{hinttype}") 144 145 if hinttype and game_ins.hints > 0: 146 if game_ins.random.choice(hinttype) == game_ins.game_const.HINT_COLOR: 147 self.already_hints[(random_pick_card_position,player.player_number)].append(game_ins.game_const.HINT_COLOR) 148 print("outer-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち,情報を持っていないカードをランダムに選択,ヒントを与えます.") 149 return Action(game_ins.game_const.HINT_COLOR, pnr=i, color=color) 150 else: 151 self.already_hints[(random_pick_card_position,player.player_number)].append(game_ins.game_const.HINT_NUMBER) 152 print("outer-state:相手がプレイ可能なカードを持っておらず,ヒントトークンがある場合は,相手カードのうち,情報を持っていないカードをランダムに選択,ヒントを与えます.") 153 return Action(game_ins.game_const.HINT_NUMBER, pnr=i, number=number) 154 155 #=============================================================================================== 156 # もし相手がプレイ可能なカードを持っておらず,ヒントトークンがない場合,自分のカードをランダムに選んで捨てる 157 158 print("自分のカードをランダムに選んで捨てます.") 159 #print(f"random_pick_card_position:{random_pick_card_position}") 160 return Action(game_ins.game_const.DISCARD, card_position=game_ins.random.choice(range(game_ins.hand_size)))
プレイヤーの次のアクションを決定するメソッド valid_actions: 現在のターンでプレイヤーが取ることのできる有効なアクションのリスト