libs.commands.results.versus
libs/commands/results/versus.py
1""" 2libs/commands/results/versus.py 3""" 4 5import textwrap 6from typing import TYPE_CHECKING, Any 7 8import pandas as pd 9 10import libs.global_value as g 11from libs.functions.compose import text_item 12from libs.types import StyleOptions 13from libs.utils import converter, formatter 14 15if TYPE_CHECKING: 16 from integrations.protocols import MessageParserProtocol 17 from libs.types import MessageType 18 19 20def aggregation(m: "MessageParserProtocol") -> None: 21 """ 22 直接対戦結果を集計して返す 23 24 Args: 25 m (MessageParserProtocol): メッセージデータ 26 27 """ 28 # 検索動作を合わせる 29 g.params.guest_skip = g.params.guest_skip2 30 31 # --- データ収集 32 data: "MessageType" 33 df_vs = g.params.read_data("SUMMARY_VERSUS_MATRIX") 34 df_game = g.params.read_data("SUMMARY_DETAILS").fillna(value="") 35 df_data = pd.DataFrame(columns=df_game.columns) # ファイル出力用 36 37 my_name = formatter.name_replace(g.params.player_name, add_mark=True) 38 vs_list = [formatter.name_replace(x, add_mark=True) for x in g.params.competition_list] 39 40 # --- 匿名化 41 if g.params.anonymous: 42 mapping_dict = formatter.anonymous_mapping([my_name] + vs_list) 43 my_name = mapping_dict[my_name] 44 vs_list = [mapping_dict[name] for name in vs_list] 45 df_vs["my_name"] = df_vs["my_name"].replace(mapping_dict) 46 df_vs["vs_name"] = df_vs["vs_name"].replace(mapping_dict) 47 48 # --- 表示内容 49 if g.params.all_player: 50 vs = "全員" 51 else: 52 vs = ",".join(vs_list) 53 54 game_result: dict[Any, Any] = {} # 対戦結果格納用 55 drop_name: list[str] = [] # 対戦記録なしプレイヤー 56 57 if len(df_vs) == 0: # 検索結果なし 58 m.set_headline("対戦記録が見つかりません。", StyleOptions(title="直接対戦")) 59 m.status.result = False 60 return 61 62 m.set_headline(tmpl_header(my_name, vs), StyleOptions(title="直接対戦")) 63 for vs_name in vs_list: 64 title = f"{my_name} vs {vs_name}" 65 if vs_name in vs_list: 66 data = df_vs.query("my_name == @my_name and vs_name == @vs_name") 67 if data.empty: 68 if len(vs_list) <= 5 and not g.params.all_player: 69 drop_name.append(vs_name) 70 game_result[title] = "対戦記録はありません。" 71 continue 72 73 game_result[title] = tmpl_vs_table(data.to_dict(orient="records")[0]) 74 75 # ゲーム結果 76 if g.params.game_results: 77 count = 0 78 my_score = df_game.query("name == @my_name") 79 vs_score = df_game.query("name == @vs_name") 80 my_playtime = my_score["playtime"].to_list() 81 vs_playtime = vs_score["playtime"].to_list() 82 83 for playtime in sorted(set(my_playtime + vs_playtime)): 84 if playtime in my_playtime and playtime in vs_playtime: 85 current_game = df_game.query("playtime == @playtime") 86 df_data = current_game if df_data.empty else pd.concat([df_data, current_game]) 87 count += 1 88 else: # 対戦記録なし 89 game_result[title] = "\t対戦相手が見つかりません。\n\n" 90 # 結果 91 if len(game_result): 92 for k, v in game_result.items(): 93 m.set_message(v, StyleOptions(title=k)) 94 else: 95 m.set_message("対戦記録が見つかりません。", StyleOptions(title="対戦記録が見つかりません。", key_title=False)) 96 m.status.result = False 97 return 98 99 # --- ファイル出力 100 if len(df_data) != 0: 101 df_data["座席"] = df_data["seat"].apply(lambda x: ["東家", "南家", "西家", "北家"][x - 1]) 102 df_data["rpoint"] = df_data["rpoint"] * 100 103 df_data = formatter.df_rename( 104 df_data.filter(items=["playtime", "座席", "name", "rank", "rpoint", "point", "yakuman"]).drop_duplicates(), 105 StyleOptions(), 106 ) 107 108 df_vs["対戦相手"] = df_vs["vs_name"].apply(lambda x: str(x).strip()) 109 df_vs["my_rpoint_avg"] = (df_vs["my_rpoint_avg"] * 100).astype("int") 110 df_vs["vs_rpoint_avg"] = (df_vs["vs_rpoint_avg"] * 100).astype("int") 111 df_vs = formatter.df_rename(df_vs, StyleOptions()) 112 df_vs2 = ( 113 df_vs.query("vs_name == @g.params.competition_list") 114 .filter( 115 items=[ 116 "対戦相手", 117 "対戦結果", 118 "勝率", 119 "獲得ポイント(自分)", 120 "平均ポイント(自分)", 121 "平均素点(自分)", 122 "順位分布(自分)", 123 "平均順位(自分)", 124 "獲得ポイント(相手)", 125 "平均ポイント(相手)", 126 "平均素点(相手)", 127 "順位分布(相手)", 128 "平均順位(相手)", 129 ] 130 ) 131 .drop_duplicates() 132 ) 133 134 match g.params.format.lower(): 135 case "csv": 136 m.set_message(converter.save_output(df_data, StyleOptions(format_type="csv", base_name="result")), StyleOptions(title="対戦結果")) 137 m.set_message(converter.save_output(df_vs2, StyleOptions(format_type="csv", base_name="versus")), StyleOptions(title="成績")) 138 case "text" | "txt": 139 m.set_message(converter.save_output(df_data, StyleOptions(format_type="txt", base_name="result")), StyleOptions(title="対戦結果")) 140 m.set_message(converter.save_output(df_vs2, StyleOptions(format_type="txt", base_name="versus")), StyleOptions(title="成績")) 141 case _: 142 pass 143 144 145def tmpl_header(my_name: str, vs_name: str) -> str: 146 """ 147 ヘッダテンプレート 148 149 Args: 150 my_name (str): 自分の名前 151 vs_name (str): 相手の名前 152 153 Returns: 154 str: 出力データ 155 156 """ 157 ret = textwrap.dedent( 158 f"""\ 159 \tプレイヤー名:{my_name} 160 \t対戦相手:{vs_name} 161 \t集計範囲:{text_item.search_range()} 162 \t{text_item.remarks(True)} 163 """ 164 ).rstrip() 165 166 return ret 167 168 169def tmpl_vs_table(data: dict[Any, Any]) -> str: 170 """ 171 直接対決結果表示テンプレート 172 173 Args: 174 data (dict[Any, Any]): 結果データ 175 176 Returns: 177 str: 出力データ 178 179 """ 180 ret = textwrap.indent( 181 "".join( 182 [ 183 textwrap.dedent( 184 f"""\ 185 対戦数:{data["game"]} 戦 {data["win"]} 勝 {data["lose"]} 敗 ({data["win%"]:.2f}%) 186 平均素点差:{(data["my_rpoint_avg"] - data["vs_rpoint_avg"]) * 100:+.0f} 点 187 獲得ポイント合計(自分):{data["my_point_sum"]:+.1f}pt 188 獲得ポイント合計(相手):{data["vs_point_sum"]:+.1f}pt 189 """.replace("-", "▲") 190 ), 191 textwrap.dedent( 192 f"""\ 193 順位分布(自分):{data["my_1st"]}-{data["my_2nd"]}-{data["my_3rd"]}-{data["my_4th"]} ({data["my_rank_avg"]:1.2f}) 194 順位分布(相手):{data["vs_1st"]}-{data["vs_2nd"]}-{data["vs_3rd"]}-{data["vs_4th"]} ({data["vs_rank_avg"]:1.2f}) 195 """ # noqa: E501 196 ), 197 ] 198 ), 199 "\t", 200 ) 201 202 return ret.rstrip() + "\n"
21def aggregation(m: "MessageParserProtocol") -> None: 22 """ 23 直接対戦結果を集計して返す 24 25 Args: 26 m (MessageParserProtocol): メッセージデータ 27 28 """ 29 # 検索動作を合わせる 30 g.params.guest_skip = g.params.guest_skip2 31 32 # --- データ収集 33 data: "MessageType" 34 df_vs = g.params.read_data("SUMMARY_VERSUS_MATRIX") 35 df_game = g.params.read_data("SUMMARY_DETAILS").fillna(value="") 36 df_data = pd.DataFrame(columns=df_game.columns) # ファイル出力用 37 38 my_name = formatter.name_replace(g.params.player_name, add_mark=True) 39 vs_list = [formatter.name_replace(x, add_mark=True) for x in g.params.competition_list] 40 41 # --- 匿名化 42 if g.params.anonymous: 43 mapping_dict = formatter.anonymous_mapping([my_name] + vs_list) 44 my_name = mapping_dict[my_name] 45 vs_list = [mapping_dict[name] for name in vs_list] 46 df_vs["my_name"] = df_vs["my_name"].replace(mapping_dict) 47 df_vs["vs_name"] = df_vs["vs_name"].replace(mapping_dict) 48 49 # --- 表示内容 50 if g.params.all_player: 51 vs = "全員" 52 else: 53 vs = ",".join(vs_list) 54 55 game_result: dict[Any, Any] = {} # 対戦結果格納用 56 drop_name: list[str] = [] # 対戦記録なしプレイヤー 57 58 if len(df_vs) == 0: # 検索結果なし 59 m.set_headline("対戦記録が見つかりません。", StyleOptions(title="直接対戦")) 60 m.status.result = False 61 return 62 63 m.set_headline(tmpl_header(my_name, vs), StyleOptions(title="直接対戦")) 64 for vs_name in vs_list: 65 title = f"{my_name} vs {vs_name}" 66 if vs_name in vs_list: 67 data = df_vs.query("my_name == @my_name and vs_name == @vs_name") 68 if data.empty: 69 if len(vs_list) <= 5 and not g.params.all_player: 70 drop_name.append(vs_name) 71 game_result[title] = "対戦記録はありません。" 72 continue 73 74 game_result[title] = tmpl_vs_table(data.to_dict(orient="records")[0]) 75 76 # ゲーム結果 77 if g.params.game_results: 78 count = 0 79 my_score = df_game.query("name == @my_name") 80 vs_score = df_game.query("name == @vs_name") 81 my_playtime = my_score["playtime"].to_list() 82 vs_playtime = vs_score["playtime"].to_list() 83 84 for playtime in sorted(set(my_playtime + vs_playtime)): 85 if playtime in my_playtime and playtime in vs_playtime: 86 current_game = df_game.query("playtime == @playtime") 87 df_data = current_game if df_data.empty else pd.concat([df_data, current_game]) 88 count += 1 89 else: # 対戦記録なし 90 game_result[title] = "\t対戦相手が見つかりません。\n\n" 91 # 結果 92 if len(game_result): 93 for k, v in game_result.items(): 94 m.set_message(v, StyleOptions(title=k)) 95 else: 96 m.set_message("対戦記録が見つかりません。", StyleOptions(title="対戦記録が見つかりません。", key_title=False)) 97 m.status.result = False 98 return 99 100 # --- ファイル出力 101 if len(df_data) != 0: 102 df_data["座席"] = df_data["seat"].apply(lambda x: ["東家", "南家", "西家", "北家"][x - 1]) 103 df_data["rpoint"] = df_data["rpoint"] * 100 104 df_data = formatter.df_rename( 105 df_data.filter(items=["playtime", "座席", "name", "rank", "rpoint", "point", "yakuman"]).drop_duplicates(), 106 StyleOptions(), 107 ) 108 109 df_vs["対戦相手"] = df_vs["vs_name"].apply(lambda x: str(x).strip()) 110 df_vs["my_rpoint_avg"] = (df_vs["my_rpoint_avg"] * 100).astype("int") 111 df_vs["vs_rpoint_avg"] = (df_vs["vs_rpoint_avg"] * 100).astype("int") 112 df_vs = formatter.df_rename(df_vs, StyleOptions()) 113 df_vs2 = ( 114 df_vs.query("vs_name == @g.params.competition_list") 115 .filter( 116 items=[ 117 "対戦相手", 118 "対戦結果", 119 "勝率", 120 "獲得ポイント(自分)", 121 "平均ポイント(自分)", 122 "平均素点(自分)", 123 "順位分布(自分)", 124 "平均順位(自分)", 125 "獲得ポイント(相手)", 126 "平均ポイント(相手)", 127 "平均素点(相手)", 128 "順位分布(相手)", 129 "平均順位(相手)", 130 ] 131 ) 132 .drop_duplicates() 133 ) 134 135 match g.params.format.lower(): 136 case "csv": 137 m.set_message(converter.save_output(df_data, StyleOptions(format_type="csv", base_name="result")), StyleOptions(title="対戦結果")) 138 m.set_message(converter.save_output(df_vs2, StyleOptions(format_type="csv", base_name="versus")), StyleOptions(title="成績")) 139 case "text" | "txt": 140 m.set_message(converter.save_output(df_data, StyleOptions(format_type="txt", base_name="result")), StyleOptions(title="対戦結果")) 141 m.set_message(converter.save_output(df_vs2, StyleOptions(format_type="txt", base_name="versus")), StyleOptions(title="成績")) 142 case _: 143 pass
直接対戦結果を集計して返す
Arguments:
- m (MessageParserProtocol): メッセージデータ
def
tmpl_header(my_name: str, vs_name: str) -> str:
146def tmpl_header(my_name: str, vs_name: str) -> str: 147 """ 148 ヘッダテンプレート 149 150 Args: 151 my_name (str): 自分の名前 152 vs_name (str): 相手の名前 153 154 Returns: 155 str: 出力データ 156 157 """ 158 ret = textwrap.dedent( 159 f"""\ 160 \tプレイヤー名:{my_name} 161 \t対戦相手:{vs_name} 162 \t集計範囲:{text_item.search_range()} 163 \t{text_item.remarks(True)} 164 """ 165 ).rstrip() 166 167 return ret
ヘッダテンプレート
Arguments:
- my_name (str): 自分の名前
- vs_name (str): 相手の名前
Returns:
str: 出力データ
def
tmpl_vs_table(data: dict[typing.Any, typing.Any]) -> str:
170def tmpl_vs_table(data: dict[Any, Any]) -> str: 171 """ 172 直接対決結果表示テンプレート 173 174 Args: 175 data (dict[Any, Any]): 結果データ 176 177 Returns: 178 str: 出力データ 179 180 """ 181 ret = textwrap.indent( 182 "".join( 183 [ 184 textwrap.dedent( 185 f"""\ 186 対戦数:{data["game"]} 戦 {data["win"]} 勝 {data["lose"]} 敗 ({data["win%"]:.2f}%) 187 平均素点差:{(data["my_rpoint_avg"] - data["vs_rpoint_avg"]) * 100:+.0f} 点 188 獲得ポイント合計(自分):{data["my_point_sum"]:+.1f}pt 189 獲得ポイント合計(相手):{data["vs_point_sum"]:+.1f}pt 190 """.replace("-", "▲") 191 ), 192 textwrap.dedent( 193 f"""\ 194 順位分布(自分):{data["my_1st"]}-{data["my_2nd"]}-{data["my_3rd"]}-{data["my_4th"]} ({data["my_rank_avg"]:1.2f}) 195 順位分布(相手):{data["vs_1st"]}-{data["vs_2nd"]}-{data["vs_3rd"]}-{data["vs_4th"]} ({data["vs_rank_avg"]:1.2f}) 196 """ # noqa: E501 197 ), 198 ] 199 ), 200 "\t", 201 ) 202 203 return ret.rstrip() + "\n"
直接対決結果表示テンプレート
Arguments:
- data (dict[Any, Any]): 結果データ
Returns:
str: 出力データ