libs.commands.results.summary

libs/commands/results/summary.py

  1"""
  2libs/commands/results/summary.py
  3"""
  4
  5import re
  6
  7import pandas as pd
  8
  9import libs.global_value as g
 10from cls.types import GameInfoDict
 11from libs.data import aggregate, loader
 12from libs.functions import message
 13from libs.utils import formatter
 14
 15
 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    game_info: GameInfoDict = aggregate.game_info()
 28    df_summary = aggregate.game_summary(drop_items=["rank_distr2"])
 29    df_game = loader.read_data("summary/details.sql")
 30    df_grandslam = df_game.query("grandslam == grandslam")
 31
 32    if g.params.get("anonymous"):
 33        col = "team"
 34        if g.params.get("individual"):
 35            col = "name"
 36        mapping_dict = formatter.anonymous_mapping(df_game["name"].unique().tolist())
 37        df_game["name"] = df_game["name"].replace(mapping_dict)
 38        df_summary[col] = df_summary[col].replace(mapping_dict)
 39        df_grandslam["name"] = df_grandslam["name"].replace(mapping_dict)
 40
 41    df_summary = formatter.df_rename(df_summary)
 42
 43    # 表示
 44    # --- 情報ヘッダ
 45    add_text = ""
 46    if g.params.get("individual"):  # 個人集計
 47        headline = "*【成績サマリ】*\n"
 48        column_name = "名前"
 49    else:  # チーム集計
 50        headline = "*【チーム成績サマリ】*\n"
 51        column_name = "チーム"
 52
 53    if not g.cfg.mahjong.ignore_flying:
 54        add_text = f" / トバされた人(延べ):{df_summary["トビ"].sum()} 人"
 55
 56    headline += message.header(game_info, add_text, 1)
 57
 58    if df_summary.empty:
 59        return (headline, {}, {})
 60
 61    # --- 集計結果
 62    msg: dict = {}
 63    msg_memo: str = memo_count(df_game)
 64
 65    if not g.params.get("score_comparisons"):  # 通常表示
 66        header_list: list = [column_name, "通算", "平均", "順位分布", "トビ"]
 67        filter_list: list = [column_name, "ゲーム数", "通算", "平均", "差分", "1位", "2位", "3位", "4位", "平順", "トビ"]
 68        if g.cfg.mahjong.ignore_flying:  # トビカウントなし
 69            header_list.remove("トビ")
 70            filter_list.remove("トビ")
 71    else:  # 差分表示
 72        df_grandslam = df_grandslam[:0]  # 非表示のため破棄
 73        msg_memo = ""  # 非表示のため破棄
 74        header_list = ["#", column_name, "通算", "順位差", "トップ差"]
 75        filter_list = [column_name, "ゲーム数", "通算", "順位差", "トップ差"]
 76
 77    # --- メッセージ整形
 78    step: int = 40
 79    step_count: list = []
 80    print_df = df_summary.filter(items=header_list)
 81    floatfmt = formatter.floatfmt_adjust(print_df)
 82    last_line = len(print_df)
 83
 84    for i in range(int(last_line / step + 1)):  # step行毎に分割
 85        s_line = i * step
 86        e_line = (i + 1) * step
 87
 88        if last_line - e_line < step / 2:  # 最終ブロックがstep/2で収まるならまとめる
 89            step_count.append((s_line, last_line))
 90            break
 91        step_count.append((s_line, e_line))
 92
 93    for s_line, e_line in step_count:
 94        t = print_df[s_line:e_line].to_markdown(
 95            index=False,
 96            tablefmt="simple",
 97            numalign="right",
 98            maxheadercolwidths=8,
 99            floatfmt=floatfmt,
100        ).replace("   nan", "******")
101        msg[s_line] = "```\n" + re.sub(r"  -([0-9]+)", r" ▲\1", t) + "\n```\n"  # マイナスを記号に置換
102
103    # メモ追加
104    if msg_memo:
105        msg["メモ"] = msg_memo
106
107    # --- ファイル出力
108    df_summary = df_summary.filter(items=filter_list).fillna("*****")
109    df_grandslam = df_grandslam.filter(
110        items=["playtime", "grandslam", "name"]
111    ).rename(
112        columns={
113            "playtime": "日時",
114            "grandslam": "和了役",
115            "name": "和了者",
116        }
117    )
118
119    prefix_summary = "summary"
120    prefix_yakuman = "yakuman"
121    if g.params.get("filename"):
122        prefix_summary = f"{g.params["filename"]}"
123        prefix_yakuman = f"{g.params["filename"]}_yakuman"
124
125    match g.params.get("format", "default").lower().lower():
126        case "csv":
127            file_list = {
128                "集計結果": formatter.save_output(df_summary, "csv", f"{prefix_summary}.csv", headline),
129                "役満和了": formatter.save_output(df_grandslam, "csv", f"{prefix_yakuman}.csv", headline),
130            }
131        case "text" | "txt":
132            file_list = {
133                "集計結果": formatter.save_output(df_summary, "txt", f"{prefix_summary}.txt", headline),
134                "役満和了": formatter.save_output(df_grandslam, "txt", f"{prefix_yakuman}.txt", headline),
135            }
136        case _:
137            file_list = {}
138
139    return (headline, msg, file_list)
140
141
142def memo_count(df_game: pd.DataFrame) -> str:
143    """メモ集計
144
145    Args:
146        df_game (pd.DataFrame): ゲーム情報
147
148    Returns:
149        str: 集計結果
150    """
151
152    # データ収集
153    df_grandslam = df_game.query("grandslam == grandslam")
154    match g.cfg.undefined_word:
155        case 1:
156            df_regulations = df_game.query("regulation == regulation and (type == 1 or type != type)")
157            df_wordcount = df_game.query("regulation == regulation and (type == 2 or type == type)")
158        case 2:
159            df_regulations = df_game.query("regulation == regulation and (type == 1 or type == type)")
160            df_wordcount = df_game.query("regulation == regulation and (type == 2 or type != type)")
161        case _:
162            df_regulations = df_game.query("regulation == regulation and type == 1")
163            df_wordcount = df_game.query("regulation == regulation and type == 2")
164
165    # メモ表示
166    memo_grandslam = ""
167    if not df_grandslam.empty:
168        for _, v in df_grandslam.iterrows():
169            if not g.params.get("guest_skip") and v["name"] == g.cfg.member.guest_name:  # ゲストなし
170                continue
171            memo_grandslam += f"\t{str(v["playtime"]).replace("-", "/")}{v["grandslam"]}{v["name"]}\n"
172    if memo_grandslam:
173        memo_grandslam = f"\n*【役満和了】*\n{memo_grandslam}"
174
175    memo_regulation = ""
176    if not df_regulations.empty:
177        for _, v in df_regulations.iterrows():
178            if not g.params.get("guest_skip") and v["name"] == g.cfg.member.guest_name:  # ゲストなし
179                continue
180            memo_regulation += f"\t{str(v["playtime"]).replace("-", "/")}{v["regulation"]} {str(v["ex_point"]).replace("-", "▲")}pt({v["name"]}\n"
181    if memo_regulation:
182        memo_regulation = f"\n*【卓外ポイント】*\n{memo_regulation}"
183
184    memo_wordcount = ""
185    if not df_wordcount.empty:
186        for _, v in df_wordcount.iterrows():
187            if not g.params.get("guest_skip") and v["name"] == g.cfg.member.guest_name:  # ゲストなし
188                continue
189            memo_wordcount += f"\t{str(v["playtime"]).replace("-", "/")}{v["regulation"]}{v["name"]}\n"
190    if memo_wordcount:
191        memo_wordcount = f"\n*【その他】*\n{memo_wordcount}"
192
193    return (memo_grandslam + memo_regulation + memo_wordcount).strip()
def aggregation() -> tuple[str, dict, dict]:
 17def aggregation() -> tuple[str, dict, dict]:
 18    """各プレイヤーの通算ポイントを表示
 19
 20    Returns:
 21        tuple[str, dict, dict]
 22        - str: ヘッダ情報
 23        - dict: 集計データ
 24        - dict: 生成ファイル情報
 25    """
 26
 27    # --- データ収集
 28    game_info: GameInfoDict = aggregate.game_info()
 29    df_summary = aggregate.game_summary(drop_items=["rank_distr2"])
 30    df_game = loader.read_data("summary/details.sql")
 31    df_grandslam = df_game.query("grandslam == grandslam")
 32
 33    if g.params.get("anonymous"):
 34        col = "team"
 35        if g.params.get("individual"):
 36            col = "name"
 37        mapping_dict = formatter.anonymous_mapping(df_game["name"].unique().tolist())
 38        df_game["name"] = df_game["name"].replace(mapping_dict)
 39        df_summary[col] = df_summary[col].replace(mapping_dict)
 40        df_grandslam["name"] = df_grandslam["name"].replace(mapping_dict)
 41
 42    df_summary = formatter.df_rename(df_summary)
 43
 44    # 表示
 45    # --- 情報ヘッダ
 46    add_text = ""
 47    if g.params.get("individual"):  # 個人集計
 48        headline = "*【成績サマリ】*\n"
 49        column_name = "名前"
 50    else:  # チーム集計
 51        headline = "*【チーム成績サマリ】*\n"
 52        column_name = "チーム"
 53
 54    if not g.cfg.mahjong.ignore_flying:
 55        add_text = f" / トバされた人(延べ):{df_summary["トビ"].sum()} 人"
 56
 57    headline += message.header(game_info, add_text, 1)
 58
 59    if df_summary.empty:
 60        return (headline, {}, {})
 61
 62    # --- 集計結果
 63    msg: dict = {}
 64    msg_memo: str = memo_count(df_game)
 65
 66    if not g.params.get("score_comparisons"):  # 通常表示
 67        header_list: list = [column_name, "通算", "平均", "順位分布", "トビ"]
 68        filter_list: list = [column_name, "ゲーム数", "通算", "平均", "差分", "1位", "2位", "3位", "4位", "平順", "トビ"]
 69        if g.cfg.mahjong.ignore_flying:  # トビカウントなし
 70            header_list.remove("トビ")
 71            filter_list.remove("トビ")
 72    else:  # 差分表示
 73        df_grandslam = df_grandslam[:0]  # 非表示のため破棄
 74        msg_memo = ""  # 非表示のため破棄
 75        header_list = ["#", column_name, "通算", "順位差", "トップ差"]
 76        filter_list = [column_name, "ゲーム数", "通算", "順位差", "トップ差"]
 77
 78    # --- メッセージ整形
 79    step: int = 40
 80    step_count: list = []
 81    print_df = df_summary.filter(items=header_list)
 82    floatfmt = formatter.floatfmt_adjust(print_df)
 83    last_line = len(print_df)
 84
 85    for i in range(int(last_line / step + 1)):  # step行毎に分割
 86        s_line = i * step
 87        e_line = (i + 1) * step
 88
 89        if last_line - e_line < step / 2:  # 最終ブロックがstep/2で収まるならまとめる
 90            step_count.append((s_line, last_line))
 91            break
 92        step_count.append((s_line, e_line))
 93
 94    for s_line, e_line in step_count:
 95        t = print_df[s_line:e_line].to_markdown(
 96            index=False,
 97            tablefmt="simple",
 98            numalign="right",
 99            maxheadercolwidths=8,
100            floatfmt=floatfmt,
101        ).replace("   nan", "******")
102        msg[s_line] = "```\n" + re.sub(r"  -([0-9]+)", r" ▲\1", t) + "\n```\n"  # マイナスを記号に置換
103
104    # メモ追加
105    if msg_memo:
106        msg["メモ"] = msg_memo
107
108    # --- ファイル出力
109    df_summary = df_summary.filter(items=filter_list).fillna("*****")
110    df_grandslam = df_grandslam.filter(
111        items=["playtime", "grandslam", "name"]
112    ).rename(
113        columns={
114            "playtime": "日時",
115            "grandslam": "和了役",
116            "name": "和了者",
117        }
118    )
119
120    prefix_summary = "summary"
121    prefix_yakuman = "yakuman"
122    if g.params.get("filename"):
123        prefix_summary = f"{g.params["filename"]}"
124        prefix_yakuman = f"{g.params["filename"]}_yakuman"
125
126    match g.params.get("format", "default").lower().lower():
127        case "csv":
128            file_list = {
129                "集計結果": formatter.save_output(df_summary, "csv", f"{prefix_summary}.csv", headline),
130                "役満和了": formatter.save_output(df_grandslam, "csv", f"{prefix_yakuman}.csv", headline),
131            }
132        case "text" | "txt":
133            file_list = {
134                "集計結果": formatter.save_output(df_summary, "txt", f"{prefix_summary}.txt", headline),
135                "役満和了": formatter.save_output(df_grandslam, "txt", f"{prefix_yakuman}.txt", headline),
136            }
137        case _:
138            file_list = {}
139
140    return (headline, msg, file_list)

各プレイヤーの通算ポイントを表示

Returns:

tuple[str, dict, dict]

  • str: ヘッダ情報
  • dict: 集計データ
  • dict: 生成ファイル情報
def memo_count(df_game: pandas.core.frame.DataFrame) -> str:
143def memo_count(df_game: pd.DataFrame) -> str:
144    """メモ集計
145
146    Args:
147        df_game (pd.DataFrame): ゲーム情報
148
149    Returns:
150        str: 集計結果
151    """
152
153    # データ収集
154    df_grandslam = df_game.query("grandslam == grandslam")
155    match g.cfg.undefined_word:
156        case 1:
157            df_regulations = df_game.query("regulation == regulation and (type == 1 or type != type)")
158            df_wordcount = df_game.query("regulation == regulation and (type == 2 or type == type)")
159        case 2:
160            df_regulations = df_game.query("regulation == regulation and (type == 1 or type == type)")
161            df_wordcount = df_game.query("regulation == regulation and (type == 2 or type != type)")
162        case _:
163            df_regulations = df_game.query("regulation == regulation and type == 1")
164            df_wordcount = df_game.query("regulation == regulation and type == 2")
165
166    # メモ表示
167    memo_grandslam = ""
168    if not df_grandslam.empty:
169        for _, v in df_grandslam.iterrows():
170            if not g.params.get("guest_skip") and v["name"] == g.cfg.member.guest_name:  # ゲストなし
171                continue
172            memo_grandslam += f"\t{str(v["playtime"]).replace("-", "/")}{v["grandslam"]}{v["name"]}\n"
173    if memo_grandslam:
174        memo_grandslam = f"\n*【役満和了】*\n{memo_grandslam}"
175
176    memo_regulation = ""
177    if not df_regulations.empty:
178        for _, v in df_regulations.iterrows():
179            if not g.params.get("guest_skip") and v["name"] == g.cfg.member.guest_name:  # ゲストなし
180                continue
181            memo_regulation += f"\t{str(v["playtime"]).replace("-", "/")}{v["regulation"]} {str(v["ex_point"]).replace("-", "▲")}pt({v["name"]}\n"
182    if memo_regulation:
183        memo_regulation = f"\n*【卓外ポイント】*\n{memo_regulation}"
184
185    memo_wordcount = ""
186    if not df_wordcount.empty:
187        for _, v in df_wordcount.iterrows():
188            if not g.params.get("guest_skip") and v["name"] == g.cfg.member.guest_name:  # ゲストなし
189                continue
190            memo_wordcount += f"\t{str(v["playtime"]).replace("-", "/")}{v["regulation"]}{v["name"]}\n"
191    if memo_wordcount:
192        memo_wordcount = f"\n*【その他】*\n{memo_wordcount}"
193
194    return (memo_grandslam + memo_regulation + memo_wordcount).strip()

メモ集計

Arguments:
  • df_game (pd.DataFrame): ゲーム情報
Returns:

str: 集計結果