Beispiel #1
0
def query_card_info():
    # 读取配置信息
    cfg = config()

    # init_pool(cfg.get_pool_size())
    # check_all_skey_and_pskey(cfg, check_skey_only=True)

    # 12.30 送卡片次数(re:好像送给别人没有上限?)
    indexes = list(range(len(cfg.account_configs), 0, -1))

    # 展示卡仓信息
    lottery_zzconfig = zzconfig()
    card_info_map = parse_card_group_info_map(lottery_zzconfig)
    order_map = {}
    # 卡片编码 => 名称
    for name, card_info in card_info_map.items():
        order_map[card_info.index] = name

    heads = []
    colSizes = []

    card_indexes = [
        "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "2-4", "3-1", "3-2",
        "3-3", "3-4"
    ]
    card_width = 3
    heads.extend(card_indexes)
    colSizes.extend([card_width for i in card_indexes])

    summaryCols = [*[0 for card in card_indexes]]

    for idx in indexes:  # 从1开始,第i个
        account_config = cfg.account_configs[idx - 1]

        djcHelper = DjcHelper(account_config, cfg.common)
        lr = djcHelper.fetch_pskey()
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list()
        qa = QzoneActivity(djcHelper, lr)

        card_counts = qa.get_card_counts()

        # 处理各个卡片数目
        for card_position, card_index in enumerate(card_indexes):
            card_count = card_counts[order_map[card_index]]

            # 更新统计信息
            summaryCols[card_position] += card_count

    msg = "\n卡片详情如下"
    msg += "\n "
    for col in range(4):
        msg += f" {col + 1:3d}"
    for row in range(3):
        msg += f"\n{row + 1}"
        for col in range(4):
            msg += f" {summaryCols[row * 4 + col]:3d}"
    msg += "\n"

    return msg
Beispiel #2
0
def query_lottery_status(idx: int, account_config: AccountConfig, common_config: CommonConfig, card_indexes: List[str], prize_indexes: List[str], order_map: Dict[str, str]) -> Optional[List]:
    if not account_config.ark_lottery.show_status:
        return

    djcHelper = DjcHelper(account_config, common_config)
    lr = djcHelper.fetch_pskey()
    if lr is None:
        return
    djcHelper.check_skey_expired()
    djcHelper.get_bind_role_list(print_warning=False)

    qa = QzoneActivity(djcHelper, lr)

    card_counts = qa.get_card_counts()
    prize_counts = qa.get_prize_counts()

    cols = [idx, account_config.name]
    # 处理各个卡片数目
    for card_position, card_index in enumerate(card_indexes):
        card_count = card_counts[order_map[card_index]]

        cols.append(card_count)

    # 处理各个奖励剩余领取次数
    for prize_index in prize_indexes:
        prize_count = prize_counts[order_map[prize_index]]
        cols.append(prize_count)

    return cols
Beispiel #3
0
def auto_send_cards(cfg):
    if not has_any_account_in_normal_run(cfg):
        return
    _show_head_line("运行完毕自动赠送卡片")

    target_qqs = cfg.common.auto_send_card_target_qqs
    if len(target_qqs) == 0:
        logger.warning("未定义自动赠送卡片的对象QQ数组,将跳过本阶段")
        return

    # 统计各账号卡片数目
    logger.info("拉取各账号的卡片数据中,请耐心等待...")
    qq_to_card_name_to_counts = {}
    qq_to_prize_counts = {}
    qq_to_djcHelper = {}
    for _idx, account_config in enumerate(cfg.account_configs):
        idx = _idx + 1
        if not account_config.is_enabled():
            # 未启用的账户的账户不走该流程
            continue

        djcHelper = DjcHelper(account_config, cfg.common)
        lr = djcHelper.fetch_pskey()
        if lr is None:
            continue
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list(print_warning=False)

        qq = uin2qq(lr.uin)
        qa = QzoneActivity(djcHelper, lr)

        qq_to_card_name_to_counts[qq] = qa.get_card_counts()
        qq_to_prize_counts[qq] = qa.get_prize_counts()
        qq_to_djcHelper[qq] = djcHelper

        logger.info(f"{idx:2d}/{len(cfg.account_configs)} 账号 {padLeftRight(account_config.name, 12)} 的数据拉取完毕")

    # 赠送卡片
    for idx, target_qq in enumerate(target_qqs):
        if target_qq in qq_to_djcHelper:
            left_times = qq_to_djcHelper[target_qq].ark_lottery_query_left_times(target_qq)
            name = qq_to_djcHelper[target_qq].cfg.name
            logger.warning(color("fg_bold_green") + f"第{idx + 1}/{len(target_qqs)}个赠送目标账号 {name}({target_qq}) 今日仍可被赠送 {left_times} 次卡片")
            # 最多赠送目标账号今日仍可接收的卡片数
            for i in range(left_times):
                send_card(target_qq, qq_to_card_name_to_counts, qq_to_prize_counts, qq_to_djcHelper, target_qqs)

            # 赠送卡片完毕后尝试领取奖励和抽奖
            djcHelper = qq_to_djcHelper[target_qq]
            lr = djcHelper.fetch_pskey()
            if lr is not None:
                logger.info("赠送完毕,尝试领取奖励和抽奖")
                qa = QzoneActivity(djcHelper, lr)
                qa.take_ark_lottery_awards(print_warning=False)
                qa.try_lottery_using_cards(print_warning=False)
Beispiel #4
0
def query_account_ark_lottery_info(idx: int, total_account: int, account_config: AccountConfig, common_config: CommonConfig) -> (Dict[str, int], Dict[str, int], DjcHelper):
    djcHelper = DjcHelper(account_config, common_config)
    lr = djcHelper.fetch_pskey()
    if lr is None:
        return
    djcHelper.check_skey_expired()
    djcHelper.get_bind_role_list(print_warning=False)

    qa = QzoneActivity(djcHelper, lr)

    card_name_to_counts = qa.get_card_counts()
    prize_counts = qa.get_prize_counts()

    logger.info(f"{idx:2d}/{total_account} 账号 {padLeftRight(account_config.name, 12)} 的数据拉取完毕")

    return card_name_to_counts, prize_counts, djcHelper
Beispiel #5
0
def auto_send_cards(cfg: Config):
    if not has_any_account_in_normal_run(cfg):
        return
    _show_head_line("运行完毕自动赠送卡片")

    target_qqs = cfg.common.auto_send_card_target_qqs
    if len(target_qqs) == 0:
        logger.warning("未定义自动赠送卡片的对象QQ数组,将跳过本阶段")
        return

    # 统计各账号卡片数目
    logger.info("拉取各账号的卡片数据中,请耐心等待...")
    account_data = []
    if cfg.common.enable_multiprocessing:
        logger.info(f"已开启多进程模式({cfg.get_pool_size()}),将并行拉取数据~")
        for data in get_pool().starmap(query_account_ark_lottery_info, [(_idx + 1, len(cfg.account_configs), account_config, cfg.common)
                                                                        for _idx, account_config in enumerate(cfg.account_configs) if account_config.is_enabled()]):
            account_data.append(data)
    else:
        for _idx, account_config in enumerate(cfg.account_configs):
            idx = _idx + 1
            if not account_config.is_enabled():
                # 未启用的账户的账户不走该流程
                continue

            account_data.append(query_account_ark_lottery_info(idx, len(cfg.account_configs), account_config, cfg.common))

    account_data = remove_none_from_list(account_data)

    qq_to_card_name_to_counts = {}
    qq_to_prize_counts = {}
    qq_to_djcHelper = {}
    for card_name_to_counts, prize_counts, djcHelper in account_data:
        qq = uin2qq(djcHelper.cfg.account_info.uin)

        qq_to_card_name_to_counts[qq] = card_name_to_counts
        qq_to_prize_counts[qq] = prize_counts
        qq_to_djcHelper[qq] = djcHelper

    # 赠送卡片
    for idx, target_qq in enumerate(target_qqs):
        if target_qq in qq_to_djcHelper:
            left_times = qq_to_djcHelper[target_qq].ark_lottery_query_left_times(target_qq)
            name = qq_to_djcHelper[target_qq].cfg.name
            logger.warning(color("fg_bold_green") + f"第{idx + 1}/{len(target_qqs)}个赠送目标账号 {name}({target_qq}) 今日仍可被赠送 {left_times} 次卡片")
            # 最多赠送目标账号今日仍可接收的卡片数
            for i in range(left_times):
                send_card(target_qq, qq_to_card_name_to_counts, qq_to_prize_counts, qq_to_djcHelper, target_qqs)

            # 赠送卡片完毕后尝试领取奖励和抽奖
            djcHelper = qq_to_djcHelper[target_qq]
            lr = djcHelper.fetch_pskey()
            if lr is not None:
                logger.info("赠送完毕,尝试领取奖励和抽奖")
                qa = QzoneActivity(djcHelper, lr)
                qa.take_ark_lottery_awards(print_warning=False)
                qa.try_lottery_using_cards(print_warning=False)
Beispiel #6
0
def show_lottery_status(ctx, cfg, need_show_tips=False):
    if not has_any_account_in_normal_run(cfg):
        return
    _show_head_line(ctx)

    logger.info(get_not_ams_act_desc("集卡"))

    lottery_zzconfig = zzconfig()
    card_info_map = parse_card_group_info_map(lottery_zzconfig)
    order_map = {}
    # 卡片编码 => 名称
    for name, card_info in card_info_map.items():
        order_map[card_info.index] = name

    # 奖励展示名称 => 实际名称
    groups = [
        lottery_zzconfig.prizeGroups.group1,
        lottery_zzconfig.prizeGroups.group2,
        lottery_zzconfig.prizeGroups.group3,
        lottery_zzconfig.prizeGroups.group4,
    ]
    prizeDisplayTitles = []
    for group in groups:
        displayTitle = group.title
        if len(displayTitle) > 4 and "礼包" in displayTitle:
            # 将 全民竞速礼包 这种名称替换为 全民竞速
            displayTitle = displayTitle.replace("礼包", "")

        order_map[displayTitle] = group.title
        prizeDisplayTitles.append(displayTitle)

    heads = []
    colSizes = []

    baseHeads = ["序号", "账号名"]
    baseColSizes = [4, 12]
    heads.extend(baseHeads)
    colSizes.extend(baseColSizes)

    card_indexes = ["1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "2-4", "3-1", "3-2", "3-3", "3-4"]
    card_width = 3
    heads.extend(card_indexes)
    colSizes.extend([card_width for i in card_indexes])

    prize_indexes = [*prizeDisplayTitles]
    heads.extend(prize_indexes)
    colSizes.extend([printed_width(name) for name in prize_indexes])

    accounts_that_should_enable_cost_card_to_lottery = []

    logger.info(tableify(heads, colSizes))
    summaryCols = [1, "总计", *[0 for card in card_indexes], *[count_with_color(0, "bold_green", show_width=printed_width(prize_index)) for prize_index in prize_indexes]]
    for _idx, account_config in enumerate(cfg.account_configs):
        idx = _idx + 1
        if not account_config.is_enabled():
            # 未启用的账户的账户不走该流程
            continue

        if not account_config.ark_lottery.show_status:
            continue

        djcHelper = DjcHelper(account_config, cfg.common)
        lr = djcHelper.fetch_pskey()
        if lr is None:
            continue
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list(print_warning=False)

        qa = QzoneActivity(djcHelper, lr)

        card_counts = qa.get_card_counts()
        prize_counts = qa.get_prize_counts()

        summaryCols[0] += 1

        cols = [idx, account_config.name]
        has_any_card = False
        has_any_left_gift = False
        # 处理各个卡片数目
        for card_position, card_index in enumerate(card_indexes):
            card_count = card_counts[order_map[card_index]]

            cols.append(colored_count(idx, card_count, account_config.ark_lottery.show_color))

            # 更新统计信息
            summaryCols[len(baseHeads) + card_position] += card_count

            if card_count > 0:
                has_any_card = True

        # 处理各个奖励剩余领取次数
        for prize_index in prize_indexes:
            prize_count = prize_counts[order_map[prize_index]]
            cols.append(count_with_color(prize_count, "bold_green", show_width=printed_width(prize_index)))

            if prize_count > 0:
                has_any_left_gift = True

        logger.info(tableify(cols, colSizes))

        if has_any_card and not has_any_left_gift:
            accounts_that_should_enable_cost_card_to_lottery.append(account_config.name)

    for cardIdx in range(len(card_indexes)):
        idx = len(baseHeads) + cardIdx
        summaryCols[idx] = colored_count(len(cfg.account_configs), summaryCols[idx], cfg.common.ark_lottery_summary_show_color or "fg_thin_cyan")

    logger.info(tableify(summaryCols, colSizes))

    if need_show_tips and len(accounts_that_should_enable_cost_card_to_lottery) > 0:
        accounts = ', '.join(accounts_that_should_enable_cost_card_to_lottery)
        msg = f"账户({accounts})仍有剩余卡片,但已无任何可领取礼包,建议开启消耗卡片来抽奖的功能"
        logger.warning(color("fg_bold_yellow") + msg)
Beispiel #7
0
def show_lottery_status(ctx, cfg, need_show_tips=False):
    if not has_any_account_in_normal_run(cfg):
        return
    _show_head_line(ctx)

    order_map = {
        "1-1": "多人配合新挑战",
        "1-2": "丰富机制闯难关",
        "1-3": "新剧情视听盛宴",
        "1-4": "单人成团战不停",
        "2-1": "回归奖励大升级",
        "2-2": "秒升Lv96刷深渊",
        "2-3": "灿烂自选回归领",
        "2-4": "告别酱油变大佬",
        "3-1": "单人爽刷新玩法",
        "3-2": "独立成团打副本",
        "3-3": "海量福利金秋享",
        "3-4": "超强奖励等你拿",
        "全新团本": "勇士归来礼包",
        "超低门槛": "超低门槛",
        "人人可玩": "人人可玩",
        "幸运礼包": "幸运礼包",
    }

    heads = ["序号", "账号名"]
    colSizes = [4, 12]

    card_indexes = [
        "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "2-4", "3-1", "3-2",
        "3-3", "3-4"
    ]
    card_width = 3
    heads.extend(card_indexes)
    colSizes.extend([card_width for i in card_indexes])

    prize_indexes = ["全新团本", "超低门槛", "人人可玩", "幸运礼包"]
    heads.extend(prize_indexes)
    colSizes.extend([printed_width(name) for name in prize_indexes])

    accounts_that_should_enable_cost_card_to_lottery = []

    logger.info(tableify(heads, colSizes))
    for _idx, account_config in enumerate(cfg.account_configs):
        idx = _idx + 1
        if not account_config.is_enabled():
            # 未启用的账户的账户不走该流程
            continue

        if not account_config.ark_lottery.show_status:
            continue

        djcHelper = DjcHelper(account_config, cfg.common)
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list(print_warning=False)

        lr = djcHelper.fetch_pskey()
        if lr is None:
            continue

        qa = QzoneActivity(djcHelper, lr)

        card_counts = qa.get_card_counts()
        prize_counts = qa.get_prize_counts()

        cols = [idx, account_config.name]
        has_any_card = False
        has_any_left_gift = False
        # 处理各个卡片数目
        for card_index in card_indexes:
            card_count = card_counts[order_map[card_index]]

            show_count = card_count
            # 特殊处理色彩
            if card_count == 0:
                if idx == 1:
                    # 突出显示大号没有的卡片
                    show_count = color("fg_bold_cyan") + padLeftRight(
                        card_count, 3) + color("INFO")
                else:
                    # 小号没有的卡片直接不显示,避免信息干扰
                    show_count = ""
            else:
                if idx == 1:
                    if card_count == 1:
                        # 大号只有一张的卡片也特殊处理
                        show_count = color("fg_bold_blue") + padLeftRight(
                            card_count, 3) + color("INFO")
                    else:
                        # 大号其余卡片亮绿色
                        show_count = color("fg_bold_green") + padLeftRight(
                            card_count, 3) + color("INFO")
                else:
                    # 小号拥有的卡片淡化处理,方便辨识
                    show_color = account_config.ark_lottery.show_color or "fg_bold_black"
                    show_count = color(show_color) + padLeftRight(
                        card_count, 3) + color("INFO")

            cols.append(show_count)

            if card_count > 0:
                has_any_card = True

        # 处理各个奖励剩余领取次数
        for prize_index in prize_indexes:
            prize_count = prize_counts[order_map[prize_index]]
            cols.append(prize_count)

            if prize_count > 0:
                has_any_left_gift = True

        logger.info(tableify(cols, colSizes))

        if has_any_card and not has_any_left_gift:
            accounts_that_should_enable_cost_card_to_lottery.append(
                account_config.name)

    if need_show_tips and len(
            accounts_that_should_enable_cost_card_to_lottery) > 0:
        msg = "账户({})仍有剩余卡片,但已无任何可领取礼包,建议开启消耗卡片来抽奖的功能".format(
            ', '.join(accounts_that_should_enable_cost_card_to_lottery))
        logger.warning(color("fg_bold_yellow") + msg)
Beispiel #8
0
def show_lottery_status(ctx, cfg, need_show_tips=False):
    if not has_any_account_in_normal_run(cfg):
        return
    _show_head_line(ctx)

    show_end_time("2021-02-28 23:59:59")

    lottery_zzconfig = zzconfig()
    card_info_map = parse_card_group_info_map(lottery_zzconfig)
    order_map = {}
    # 卡片编码 => 名称
    for name, card_info in card_info_map.items():
        order_map[card_info.index] = name

    # 奖励展示名称 => 实际名称
    groups = [
        lottery_zzconfig.prizeGroups.group1,
        lottery_zzconfig.prizeGroups.group2,
        lottery_zzconfig.prizeGroups.group3,
        lottery_zzconfig.prizeGroups.group4,
    ]
    prizeDisplayTitles = []
    for group in groups:
        displayTitle = group.title
        if len(displayTitle) > 4 and "礼包" in displayTitle:
            # 将 全民竞速礼包 这种名称替换为 全民竞速
            displayTitle = displayTitle.replace("礼包", "")

        order_map[displayTitle] = group.title
        prizeDisplayTitles.append(displayTitle)

    heads = []
    colSizes = []

    baseHeads = ["序号", "账号名"]
    baseColSizes = [4, 12]
    heads.extend(baseHeads)
    colSizes.extend(baseColSizes)

    card_indexes = ["1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "2-4", "3-1", "3-2", "3-3", "3-4"]
    card_width = 3
    heads.extend(card_indexes)
    colSizes.extend([card_width for i in card_indexes])

    prize_indexes = [*prizeDisplayTitles]
    heads.extend(prize_indexes)
    colSizes.extend([printed_width(name) for name in prize_indexes])

    accounts_that_should_enable_cost_card_to_lottery = []

    logger.info(tableify(heads, colSizes))
    summaryCols = [1, "总计", *[0 for card in card_indexes], *[count_with_color(0, "bold_green", show_width=printed_width(prize_index)) for prize_index in prize_indexes]]
    for _idx, account_config in enumerate(cfg.account_configs):
        idx = _idx + 1
        if not account_config.is_enabled():
            # 未启用的账户的账户不走该流程
            continue

        if not account_config.ark_lottery.show_status:
            continue

        djcHelper = DjcHelper(account_config, cfg.common)
        lr = djcHelper.fetch_pskey()
        if lr is None:
            continue
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list(print_warning=False)

        qa = QzoneActivity(djcHelper, lr)

        card_counts = qa.get_card_counts()
        prize_counts = qa.get_prize_counts()

        summaryCols[0] += 1

        cols = [idx, account_config.name]
        has_any_card = False
        has_any_left_gift = False
        # 处理各个卡片数目
        for card_position, card_index in enumerate(card_indexes):
            card_count = card_counts[order_map[card_index]]

            cols.append(colored_count(idx, card_count, account_config.ark_lottery.show_color))

            # 更新统计信息
            summaryCols[len(baseHeads) + card_position] += card_count

            if card_count > 0:
                has_any_card = True

        # 处理各个奖励剩余领取次数
        for prize_index in prize_indexes:
            prize_count = prize_counts[order_map[prize_index]]
            cols.append(count_with_color(prize_count, "bold_green", show_width=printed_width(prize_index)))

            if prize_count > 0:
                has_any_left_gift = True

        logger.info(tableify(cols, colSizes))

        if has_any_card and not has_any_left_gift:
            accounts_that_should_enable_cost_card_to_lottery.append(account_config.name)

    for cardIdx in range(len(card_indexes)):
        idx = len(baseHeads) + cardIdx
        summaryCols[idx] = colored_count(len(cfg.account_configs), summaryCols[idx], cfg.common.ark_lottery_summary_show_color or "fg_thin_cyan")

    logger.info(tableify(summaryCols, colSizes))

    if need_show_tips and len(accounts_that_should_enable_cost_card_to_lottery) > 0:
        accounts = ', '.join(accounts_that_should_enable_cost_card_to_lottery)
        msg = f"账户({accounts})仍有剩余卡片,但已无任何可领取礼包,建议开启消耗卡片来抽奖的功能"
        logger.warning(color("fg_bold_yellow") + msg)

    if not os.path.exists("DNF蚊子腿小助手_集卡特别版.exe"):
        logger.warning(color("bold_cyan") + (
            "以下为广告时间0-0\n"
            "如果只需要集卡功能,可以联系我购买集卡特别版哦,特别版仅包含集卡相关功能(集卡、送卡、展示卡片信息、兑换卡片奖励、使用卡片抽奖),供某些只需要集卡的朋友使用\n"
            "演示地址:https://www.bilibili.com/video/BV1zA411H7mP\n"
            "价格:6.66元\n"
            "购买方式:加小助手群后QQ私聊我付款截图,我确认无误后会将DLC以及用法发给你,并拉到一个无法主动加入的专用群,通过群文件分发该DLC的后续更新版本~\n"
            "PS:这个DLC相当于是小助手的子集,用于仅处理集卡相关内容,之前听到有的朋友有这样的需求,所以特地制作的,是否购买自行考量哈。\n"
            "如果购买的话能鼓励我花更多时间来维护小助手,支持新的蚊子腿以及优化使用体验(o゚▽゚)o  \n"
            "\n"
            "2021.2.2 update: 本轮集卡我又换完啦,有需要买卡的朋友可以加群私聊我购买哦~依旧是一元一张任意卡。先问下有没有卡,得到确定回复后直接发付款截图和要收卡片的QQ号码即可(不需要加好友)"
        ))
Beispiel #9
0
def query_card_info():
    # 读取配置信息
    cfg = config()

    # init_pool(cfg.get_pool_size())
    # check_all_skey_and_pskey(cfg, check_skey_only=True)

    # 12.30 送卡片次数(re:好像送给别人没有上限?)
    indexes = list(range(len(cfg.account_configs), 0, -1))

    order_map, _ = make_ark_lottery_card_and_award_info()

    heads = []
    colSizes = []

    card_indexes = ["1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "2-4", "3-1", "3-2", "3-3", "3-4"]
    card_width = 3
    heads.extend(card_indexes)
    colSizes.extend([card_width for i in card_indexes])

    summaryCols = [*[0 for card in card_indexes]]

    for idx in indexes:  # 从1开始,第i个
        account_config = cfg.account_configs[idx - 1]
        if not account_config.function_switches.get_ark_lottery or not account_config.is_enabled():
            continue

        djcHelper = DjcHelper(account_config, cfg.common)
        lr = djcHelper.fetch_pskey()
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list()
        qa = QzoneActivity(djcHelper, lr)

        # 获取卡片和奖励数目,其中新版本卡片为 id=>count ,旧版本卡片为 name=>count
        card_counts: Dict[str, int]

        if is_new_version_ark_lottery():
            card_counts = djcHelper.dnf_ark_lottery_get_card_counts()
        else:
            qa = QzoneActivity(djcHelper, lr)

            card_counts = qa.get_card_counts()

        # 处理各个卡片数目
        for card_position, card_index in enumerate(card_indexes):
            card_count = card_counts[order_map[card_index]]

            # 更新统计信息
            summaryCols[card_position] += card_count

    msg = "\n卡片详情如下"
    msg += "\n "
    for col in range(4):
        msg += f" {col + 1:3d}"
    for row in range(3):
        msg += f"\n{row + 1}"
        for col in range(4):
            msg += f" {summaryCols[row * 4 + col]:3d}"
    msg += "\n"

    return msg