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"
def aggregation(m: integrations.protocols.MessageParserProtocol) -> None:
 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: 出力データ