libs.commands.results.versus

libs/commands/results/versus.py

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

直接対戦結果を集計して返す

Returns:

tuple[str, dict, dict]

  • str: ヘッダ情報
  • dict: 集計データ
  • dict: 生成ファイル情報
def tmpl_header(my_name: str, vs_name: str) -> str:
135def tmpl_header(my_name: str, vs_name: str) -> str:
136    """ヘッダテンプレート
137
138    Args:
139        my_name (str): 自分の名前
140        vs_name (str): 相手の名前
141
142    Returns:
143        str: 出力データ
144    """
145    ret = textwrap.dedent(
146        f"""\
147        *【直接対戦結果】*
148        \tプレイヤー名:{my_name}
149        \t対戦相手:{vs_name}
150        \t{message.item_search_range()}
151        \t{message.remarks(True)}
152        """
153    ).strip()
154
155    return message.del_blank_line(ret)

ヘッダテンプレート

Arguments:
  • my_name (str): 自分の名前
  • vs_name (str): 相手の名前
Returns:

str: 出力データ

def tmpl_vs_table(data: dict) -> str:
158def tmpl_vs_table(data: dict) -> str:
159    """直接対決結果表示テンプレート
160
161    Args:
162        data (dict): 結果データ
163
164    Returns:
165        str: 出力データ
166    """
167
168    ret = f"*【{data["my_name"].strip()} vs {data["vs_name"].strip()}】*\n"
169    ret += textwrap.indent(
170        "".join([
171            textwrap.dedent(
172                f"""\
173                対戦数:{data["game"]}{data["win"]}{data["lose"]} 敗 ({data["win%"]:.2f}%)
174                平均素点差:{(data["my_rpoint_avg"] - data["vs_rpoint_avg"]) * 100:+.0f}
175                獲得ポイント合計(自分):{data["my_point_sum"]:+.1f}pt
176                獲得ポイント合計(相手):{data["vs_point_sum"]:+.1f}pt
177                """.replace("-", "▲")
178            ),
179            textwrap.dedent(
180                f"""\
181                順位分布(自分):{data["my_1st"]}-{data["my_2nd"]}-{data["my_3rd"]}-{data["my_4th"]} ({data["my_rank_avg"]:1.2f})
182                順位分布(相手):{data["vs_1st"]}-{data["vs_2nd"]}-{data["vs_3rd"]}-{data["vs_4th"]} ({data["vs_rank_avg"]:1.2f})
183                """
184            )
185        ]),
186        "\t"
187    )
188
189    return ret.strip() + "\n"

直接対決結果表示テンプレート

Arguments:
  • data (dict): 結果データ
Returns:

str: 出力データ