libs.commands.ranking.rating

libs/commands/ranking/rating.py

  1"""
  2libs/commands/ranking/rating.py
  3"""
  4
  5from typing import TYPE_CHECKING
  6
  7import pandas as pd
  8
  9import libs.global_value as g
 10from libs.domain import aggregate
 11from libs.domain.datamodels import GameInfo
 12from libs.functions import message
 13from libs.functions.compose import badge
 14from libs.types import CommandType, StyleOptions
 15from libs.utils import converter, formatter
 16
 17if TYPE_CHECKING:
 18    from integrations.protocols import MessageParserProtocol
 19    from libs.types import MessageType
 20
 21
 22def aggregation(m: "MessageParserProtocol") -> None:
 23    """
 24    レーティングを集計して返す
 25
 26    Args:
 27        m (MessageParserProtocol): メッセージデータ
 28
 29    """
 30    m.status.command_type = CommandType.RATING  # 更新
 31
 32    # 情報ヘッダ
 33    title: str = "レーティング"
 34    add_text: str = ""
 35
 36    if g.params.mode == 3 or g.params.target_mode == 3:  # todo: 未実装
 37        m.set_headline(message.random_reply(m, "not_implemented"), StyleOptions(title=title))
 38        m.status.result = False
 39        return
 40
 41    # データ収集
 42    game_info = GameInfo()
 43
 44    if not game_info.count:  # 検索結果が0件のとき
 45        m.set_headline(message.random_reply(m, "no_hits"), StyleOptions())
 46        m.status.result = False
 47        return
 48
 49    df_results = g.params.read_data("RANKING_RESULTS").set_index("name")
 50    df_ratings = aggregate.calculation_rating()
 51
 52    # 最終的なレーティング
 53    final = df_ratings.ffill().tail(1).transpose()
 54    final.columns = ["rate"]
 55    final["name"] = final.index
 56
 57    df = pd.merge(df_results, final, on=["name"]).sort_values(by="rate", ascending=False)
 58    df = df.query("count >= @g.params.stipulated")  # 足切り
 59    df["rank"] = 0  # 順位表示用カラム
 60
 61    # 集計対象外データの削除
 62    if g.params.unregistered_replace:  # 個人戦
 63        for player in df.itertuples():
 64            if player.name not in g.cfg.member.lists:
 65                df = df.drop(player.Index)
 66
 67    if not g.params.individual:  # チーム戦
 68        df = df.query("name != '未所属'")
 69
 70    # 順位偏差 / 得点偏差
 71    df["point_dev"] = round((df["rpoint_avg"] - df["rpoint_avg"].mean()) / df["rpoint_avg"].std(ddof=0) * 10 + 50, 1)
 72    df["rank_dev"] = round((df["rank_avg"] - df["rank_avg"].mean()) / df["rank_avg"].std(ddof=0) * -10 + 50, 1)
 73
 74    # 段位
 75    if g.adapter.conf.badge_grade:
 76        for idx in df.index:
 77            name = str(df.at[idx, "name"]).replace(f"({g.cfg.setting.guest_mark})", "")
 78            df.at[idx, "grade"] = badge.grade(name, False)
 79
 80    # 表示
 81    if g.params.anonymous:
 82        mapping_dict = formatter.anonymous_mapping(df["name"].unique().tolist())
 83        df["name"] = df["name"].replace(mapping_dict)
 84
 85    if df.empty:
 86        m.set_headline(message.random_reply(m, "no_target"), StyleOptions())
 87        m.status.result = False
 88        return
 89
 90    df["rank"] = df["rate"].rank(ascending=False, method="dense").astype("int")
 91    df["rate"] = df["rate"].map(lambda v: round(v, 1))
 92    df = df.query("rank <= @g.params.ranked").filter(
 93        items=["rank", "name", "rate", "rank_distr", "rank_avg", "rank_dev", "rpoint_avg", "point_dev", "grade"],
 94    )
 95
 96    # 非表示項目を削除
 97    df = formatter.df_drop(df, list(g.cfg.rule.dropitems(g.params.rule_version)))
 98
 99    m.set_headline(message.header(game_info, m, add_text, 1), StyleOptions(title=title))
100    options: StyleOptions = StyleOptions(
101        title=title,
102        data_kind=StyleOptions.DataKind.RATING,
103        rename_type=StyleOptions.RenameType.SHORT,
104        base_name="rating",
105        format_type="default",
106        summarize=False,
107        codeblock=True,
108    )
109
110    data: "MessageType"
111    match g.params.format.lower():
112        case "csv":
113            options.format_type = "csv"
114            data = converter.save_output(df, options, m.post.headline)
115        case "text" | "txt":
116            options.format_type = "txt"
117            data = converter.save_output(df, options, m.post.headline)
118        case _:
119            options.key_title = False
120            data = df
121
122    m.set_message(data, options)
def aggregation(m: integrations.protocols.MessageParserProtocol) -> None:
 23def aggregation(m: "MessageParserProtocol") -> None:
 24    """
 25    レーティングを集計して返す
 26
 27    Args:
 28        m (MessageParserProtocol): メッセージデータ
 29
 30    """
 31    m.status.command_type = CommandType.RATING  # 更新
 32
 33    # 情報ヘッダ
 34    title: str = "レーティング"
 35    add_text: str = ""
 36
 37    if g.params.mode == 3 or g.params.target_mode == 3:  # todo: 未実装
 38        m.set_headline(message.random_reply(m, "not_implemented"), StyleOptions(title=title))
 39        m.status.result = False
 40        return
 41
 42    # データ収集
 43    game_info = GameInfo()
 44
 45    if not game_info.count:  # 検索結果が0件のとき
 46        m.set_headline(message.random_reply(m, "no_hits"), StyleOptions())
 47        m.status.result = False
 48        return
 49
 50    df_results = g.params.read_data("RANKING_RESULTS").set_index("name")
 51    df_ratings = aggregate.calculation_rating()
 52
 53    # 最終的なレーティング
 54    final = df_ratings.ffill().tail(1).transpose()
 55    final.columns = ["rate"]
 56    final["name"] = final.index
 57
 58    df = pd.merge(df_results, final, on=["name"]).sort_values(by="rate", ascending=False)
 59    df = df.query("count >= @g.params.stipulated")  # 足切り
 60    df["rank"] = 0  # 順位表示用カラム
 61
 62    # 集計対象外データの削除
 63    if g.params.unregistered_replace:  # 個人戦
 64        for player in df.itertuples():
 65            if player.name not in g.cfg.member.lists:
 66                df = df.drop(player.Index)
 67
 68    if not g.params.individual:  # チーム戦
 69        df = df.query("name != '未所属'")
 70
 71    # 順位偏差 / 得点偏差
 72    df["point_dev"] = round((df["rpoint_avg"] - df["rpoint_avg"].mean()) / df["rpoint_avg"].std(ddof=0) * 10 + 50, 1)
 73    df["rank_dev"] = round((df["rank_avg"] - df["rank_avg"].mean()) / df["rank_avg"].std(ddof=0) * -10 + 50, 1)
 74
 75    # 段位
 76    if g.adapter.conf.badge_grade:
 77        for idx in df.index:
 78            name = str(df.at[idx, "name"]).replace(f"({g.cfg.setting.guest_mark})", "")
 79            df.at[idx, "grade"] = badge.grade(name, False)
 80
 81    # 表示
 82    if g.params.anonymous:
 83        mapping_dict = formatter.anonymous_mapping(df["name"].unique().tolist())
 84        df["name"] = df["name"].replace(mapping_dict)
 85
 86    if df.empty:
 87        m.set_headline(message.random_reply(m, "no_target"), StyleOptions())
 88        m.status.result = False
 89        return
 90
 91    df["rank"] = df["rate"].rank(ascending=False, method="dense").astype("int")
 92    df["rate"] = df["rate"].map(lambda v: round(v, 1))
 93    df = df.query("rank <= @g.params.ranked").filter(
 94        items=["rank", "name", "rate", "rank_distr", "rank_avg", "rank_dev", "rpoint_avg", "point_dev", "grade"],
 95    )
 96
 97    # 非表示項目を削除
 98    df = formatter.df_drop(df, list(g.cfg.rule.dropitems(g.params.rule_version)))
 99
100    m.set_headline(message.header(game_info, m, add_text, 1), StyleOptions(title=title))
101    options: StyleOptions = StyleOptions(
102        title=title,
103        data_kind=StyleOptions.DataKind.RATING,
104        rename_type=StyleOptions.RenameType.SHORT,
105        base_name="rating",
106        format_type="default",
107        summarize=False,
108        codeblock=True,
109    )
110
111    data: "MessageType"
112    match g.params.format.lower():
113        case "csv":
114            options.format_type = "csv"
115            data = converter.save_output(df, options, m.post.headline)
116        case "text" | "txt":
117            options.format_type = "txt"
118            data = converter.save_output(df, options, m.post.headline)
119        case _:
120            options.key_title = False
121            data = df
122
123    m.set_message(data, options)

レーティングを集計して返す

Arguments:
  • m (MessageParserProtocol): メッセージデータ