排位匹配算法测试
做赛事系统的时候推出一个赛制叫自由排位赛制即参赛选手随意匹配对手然后自身的rank分、胜率等也会变化再根据这些变化的影响因子再去匹配对手后端会出一个算法文档测试需要验证一下这个算法的基本准确性。一、系统要求大概的要求是这些1.对局体验玩家参赛前几局要匹配实力相近的队友和对手避免被虐2.公平性赛事最终排名应该与选手真实实力匹配3.匹配时长玩家参赛初期匹配时长15s30s玩家场数较多且排名较高时匹配时长1min二、测试方案经过和开发讨论之后纯手工测试执行难度比较大才用测试脚本测试基本思路1、开发测试环境模拟匹配池海量匹配并且把每一个匹配对局的队伍信息、匹配时长、rank匹配范围等信息打出日志然后确定格式转化成excel表格2、测试编写脚本来验证每一行数据的准确性取一定样本量数据来进行数据校对测试比如1000条3、最后确定一个合格的通过率比如90%、85%作为测试通过标准三、测试准备测试数据表格准备示例测试结果由测试给出前面的数据由开发日志提出测试脚本import openpyxl import math # 前三场球员, 轮数与标准差 is_first_three_match_list { 1: 0.10, 2: 0.20, 3: 0.25, 4: 0.30, 5: 0.35, 6: 0.40, 7: 0.45, 8: 0.50 } # 非前三场球员, 轮数与标准差 is_not_first_three_match_list { 1: 0.10, 2: 0.20, 3: 0.30, 4: 0.40, 5: 0.50, 6: 0.60, 7: 0.60, 8: 0.70, 9: 0.70, 10: 0.80, 11: 0.80, 12: 0.80, 13: 0.90, 14: 0.90, 15: 0.90, 16: 1.00 } # 读取excel表格数据 def read_data(file_path, sheet_name): # 打开excel表格 workbook None try: workbook openpyxl.load_workbook(file_path) # 获取工作表对象 sheet workbook[sheet_name] test_data [] # 逐行读取数据存入列表 for i in range(2, sheet.max_row 1): test_dict dict() test_dict[队伍A名称] sheet.cell(i, 1).value test_dict[队伍B名称] sheet.cell(i, 2).value test_dict[队伍A匹配前隐藏分] sheet.cell(i, 3).value test_dict[队伍B匹配前隐藏分] sheet.cell(i, 4).value test_dict[匹配轮数] sheet.cell(i, 5).value test_dict[匹配时长] sheet.cell(i, 6).value test_dict[匹配成功时A的隐藏分匹配范围] sheet.cell(i, 7).value test_dict[匹配成功时B的隐藏分匹配范围] sheet.cell(i, 8).value test_dict[队伍A是否含有前3场球员] sheet.cell(i, 9).value test_dict[队伍B是否含有前3场球员] sheet.cell(i, 10).value test_dict[测试结果1] sheet.cell(i, 11).value test_dict[测试结果2] sheet.cell(i, 12).value test_dict[测试结果3] sheet.cell(i, 13).value test_dict[整体结果] sheet.cell(i, 14).value test_data.append(test_dict) return test_data except Exception as e: raise e finally: if workbook: workbook.close() # 写入excel表格数据 def write_data(row, file_path, sheet_name, column, value): workbook None try: workbook openpyxl.load_workbook(file_path) sheet workbook[sheet_name] sheet.cell(rowrow, columncolumn).value value workbook.save(file_path) except Exception as e: raise e finally: if workbook: workbook.close() # 测试轮次与时长 def test_round_time(match_round, time): return int(time / match_round) 2 # 测试分数范围重合 def test_rank_score_intersect(match_success_a, match_success_b): return max(match_success_a[0], match_success_b[0]) min(match_success_a[1], match_success_b[1]) # 测试分数范围扩散 def test_increase_score(score, increase_score_list, is_contain_first_three, match_round): s is_first_three_match_list[match_round] if is_contain_first_three else is_not_first_three_match_list[match_round] increase_score_min score - score * s increase_score_max score score * s print(increase_score_min, increase_score_max) num_min min(increase_score_list) num_max max(increase_score_list) print(num_min, num_max) return math.fabs(int(num_max) - int(increase_score_max)) 1 and math.fabs(int(num_min) - int(increase_score_min)) 1 if __name__ __main__: # 测试数据路径, 可修改 path rC:\Users\xxx\Desktop\匹配测试数据.xlsx sheet_name 测试 data_list read_data(path, sheet_name) for i in range(len(data_list)): match_round data_list[i][匹配轮数] score_a int(data_list[i][队伍A匹配前隐藏分]) increase_score_a eval(data_list[i][匹配成功时A的隐藏分匹配范围]) is_contain_first_three_a int(data_list[i][队伍A是否含有前3场球员]) score_b int(data_list[i][队伍B匹配前隐藏分]) increase_score_b eval(data_list[i][匹配成功时B的隐藏分匹配范围]) is_contain_first_three_b int(data_list[i][队伍B是否含有前3场球员]) if test_round_time(data_list[i][匹配轮数], data_list[i][匹配时长]): write_data(i 2, path, sheet_name, 11, 匹配轮次与时长正确) else: write_data(i 2, path, sheet_name, 11, 匹配轮次与时长错误) write_data(i 2, path, sheet_name, 14, FAIL) if test_rank_score_intersect(increase_score_a, increase_score_b): write_data(i 2, path, sheet_name, 12, 匹配范围重合, 正确) else: write_data(i 2, path, sheet_name, 12, 匹配范围不重合, 错误) write_data(i 2, path, sheet_name, 14, FAIL) if (test_increase_score(score_a, increase_score_a, is_contain_first_three_a, match_round) and test_increase_score(score_b, increase_score_b, is_contain_first_three_b, match_round)): write_data(i 2, path, sheet_name, 13, 匹配范围扩散, 正确) else: write_data(i 2, path, sheet_name, 13, 匹配范围扩散, 错误) write_data(i 2, path, sheet_name, 14, FAIL) if 错误 not in data_list[i][测试结果1] and 错误 not in data_list[i][测试结果2] and 错误 not in data_list[i][测试结果3]: write_data(i 2, path, sheet_name, 14, PASS)上面是我自己写的看下ai优化后的import openpyxl import math from typing import List, Dict, Tuple, Union # 前三场球员, 轮数与标准差 IS_FIRST_THREE_MATCH_LIST { 1: 0.10, 2: 0.20, 3: 0.25, 4: 0.30, 5: 0.35, 6: 0.40, 7: 0.45, 8: 0.50 } # 非前三场球员, 轮数与标准差 IS_NOT_FIRST_THREE_MATCH_LIST { 1: 0.10, 2: 0.20, 3: 0.30, 4: 0.40, 5: 0.50, 6: 0.60, 7: 0.60, 8: 0.70, 9: 0.70, 10: 0.80, 11: 0.80, 12: 0.80, 13: 0.90, 14: 0.90, 15: 0.90, 16: 1.00 } def read_data(file_path: str, sheet_name: str) - List[Dict[str, Union[str, int]]]: 读取excel表格数据 Args: file_path: Excel文件路径 sheet_name: 工作表名称 Returns: 测试数据列表每个元素为包含测试数据的字典 try: workbook openpyxl.load_workbook(file_path) sheet workbook[sheet_name] test_data [] for i in range(2, sheet.max_row 1): test_dict { 队伍A名称: sheet.cell(i, 1).value, 队伍B名称: sheet.cell(i, 2).value, 队伍A匹配前隐藏分: sheet.cell(i, 3).value, 队伍B匹配前隐藏分: sheet.cell(i, 4).value, 匹配轮数: sheet.cell(i, 5).value, 匹配时长: sheet.cell(i, 6).value, 匹配成功时A的隐藏分匹配范围: sheet.cell(i, 7).value, 匹配成功时B的隐藏分匹配范围: sheet.cell(i, 8).value, 队伍A是否含有前3场球员: sheet.cell(i, 9).value, 队伍B是否含有前3场球员: sheet.cell(i, 10).value, 测试结果1: sheet.cell(i, 11).value, 测试结果2: sheet.cell(i, 12).value, 测试结果3: sheet.cell(i, 13).value, 整体结果: sheet.cell(i, 14).value } test_data.append(test_dict) return test_data except FileNotFoundError: raise FileNotFoundError(f文件 {file_path} 不存在) except KeyError: raise KeyError(f工作表 {sheet_name} 不存在) except Exception as e: raise Exception(f读取Excel文件时发生错误: {str(e)}) finally: if workbook in locals(): workbook.close() def write_data(row: int, file_path: str, sheet_name: str, column: int, value: str) - None: 写入excel表格数据 Args: row: 行号 file_path: 文件路径 sheet_name: 工作表名称 column: 列号 value: 要写入的值 try: workbook openpyxl.load_workbook(file_path) sheet workbook[sheet_name] sheet.cell(rowrow, columncolumn).value value workbook.save(file_path) except FileNotFoundError: raise FileNotFoundError(f文件 {file_path} 不存在) except KeyError: raise KeyError(f工作表 {sheet_name} 不存在) except PermissionError: raise PermissionError(f文件 {file_path} 可能被其他程序占用) except Exception as e: raise Exception(f写入Excel文件时发生错误: {str(e)}) finally: if workbook in locals(): workbook.close() def test_round_time(match_round: int, time: int) - bool: 测试轮次与时长 Args: match_round: 匹配轮数 time: 匹配时长 Returns: 测试结果布尔值 return int(time / match_round) 2 def test_rank_score_intersect(match_success_a: Tuple[int, int], match_success_b: Tuple[int, int]) - bool: 测试分数范围重合 Args: match_success_a: 队伍A的匹配范围元组 (min, max) match_success_b: 队伍B的匹配范围元组 (min, max) Returns: 范围是否重合的布尔值 return max(match_success_a[0], match_success_b[0]) min(match_success_a[1], match_success_b[1]) def test_increase_score(score: int, increase_score_list: List[int], is_contain_first_three: bool, match_round: int) - bool: 测试分数范围扩散 Args: score: 原始分数 increase_score_list: 扩散后的分数范围列表 is_contain_first_three: 是否包含前三场球员 match_round: 匹配轮数 Returns: 测试结果布尔值 std_dev IS_FIRST_THREE_MATCH_LIST.get(match_round) if is_contain_first_three else IS_NOT_FIRST_THREE_MATCH_LIST.get(match_round) if std_dev is None: return False increase_score_min score - score * std_dev increase_score_max score score * std_dev num_min min(increase_score_list) num_max max(increase_score_list) return (abs(int(num_max) - int(increase_score_max)) 1 and abs(int(num_min) - int(increase_score_min)) 1) def safe_eval_range_string(range_str: str) - List[int]: 安全地解析范围字符串避免使用eval的安全风险 Args: range_str: 格式如 [1000, 1200] 的字符串 Returns: 解析后的整数列表 if not range_str or not isinstance(range_str, str): return [] # 移除方括号和空格 cleaned_str range_str.strip().replace([, ).replace(], ).replace( , ) if , in cleaned_str: parts cleaned_str.split(,) try: return [int(part) for part in parts if part.strip()] except ValueError: return [] return [] def run_tests(data_list: List[Dict], path: str, sheet_name: str) - None: 执行所有测试并写入结果 Args: data_list: 测试数据列表 path: Excel文件路径 sheet_name: 工作表名称 for i, data in enumerate(data_list, start2): match_round data[匹配轮数] score_a int(data[队伍A匹配前隐藏分]) increase_score_a safe_eval_range_string(data[匹配成功时A的隐藏分匹配范围]) is_contain_first_three_a int(data[队伍A是否含有前3场球员]) score_b int(data[队伍B匹配前隐藏分]) increase_score_b safe_eval_range_string(data[匹配成功时B的隐藏分匹配范围]) is_contain_first_three_b int(data[队伍B是否含有前3场球员]) # 检查数据有效性 if not increase_score_a or not increase_score_b: write_data(i, path, sheet_name, 14, FAIL - 数据格式错误) continue # 测试1: 匹配轮次与时长 if test_round_time(data[匹配轮数], data[匹配时长]): write_data(i, path, sheet_name, 11, 匹配轮次与时长正确) else: write_data(i, path, sheet_name, 11, 匹配轮次与时长错误) write_data(i, path, sheet_name, 14, FAIL) # 测试2: 匹配范围重合 if test_rank_score_intersect((increase_score_a[0], increase_score_a[1]), (increase_score_b[0], increase_score_b[1])): write_data(i, path, sheet_name, 12, 匹配范围重合, 正确) else: write_data(i, path, sheet_name, 12, 匹配范围不重合, 错误) write_data(i, path, sheet_name, 14, FAIL) # 测试3: 匹配范围扩散 if (test_increase_score(score_a, increase_score_a, is_contain_first_three_a, match_round) and test_increase_score(score_b, increase_score_b, is_contain_first_three_b, match_round)): write_data(i, path, sheet_name, 13, 匹配范围扩散, 正确) else: write_data(i, path, sheet_name, 13, 匹配范围扩散, 错误) write_data(i, path, sheet_name, 14, FAIL) # 检查最终结果 if (错误 not in data[测试结果1] and 错误 not in data[测试结果2] and 错误 not in data[测试结果3]): write_data(i, path, sheet_name, 14, PASS) if __name__ __main__: # 测试数据路径, 可修改 path rC:\Users\xxx\Desktop\匹配测试数据.xlsx sheet_name 测试 try: data_list read_data(path, sheet_name) print(f成功读取 {len(data_list)} 条测试数据) run_tests(data_list, path, sheet_name) print(测试完成结果已写入Excel文件) except Exception as e: print(f执行测试时发生错误: {e}) raise测试脚本主要做了啥1、数据读取从Excel文件中读取测试数据包括队伍名称和隐藏分匹配轮数和时长匹配范围数据是否包含前三场球员的标记2、三种核心测试匹配轮次与时长测试验证匹配时长是否等于匹配轮数的2倍匹配范围重合测试检查两队匹配范围是否有交集匹配范围扩散测试根据配置的标准差验证分数扩散范围是否正确3、结果写入将测试结果写回Excel文件的对应列中四、测试结果统计准确率可以自行统计