# -*- coding: utf-8 -*- """build_moves / apply_move 的正确性自测(无需 pytest): python tests/test_moves.py""" import os import random import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.stdout.reconfigure(encoding="utf-8") from favsort import apply_move, build_moves, lcs_keep # noqa: E402 def run_case(cur, tgt, label): moves = build_moves(cur, tgt) work = list(cur) for m in moves: assert m["pred"] is not None, f"{label}: pred 为空" work = apply_move(work, m) assert work == tgt, f"{label}: 结果不符\n cur={cur}\n tgt={tgt}\n got={work}" lower = len(lcs_keep(cur, tgt)) # 不追求严格最优(多轮 LCS 会略多于下界),但不能出现病态膨胀 assert len(moves) <= len(cur) + 8, ( f"{label}: 步数异常 {len(moves)} (n={len(cur)}, 下界={len(cur) - lower})" ) return len(moves) def main(): random.seed(20261031) total = 0 for n in range(1, 13): ids = [1000 + i for i in range(n)] for _ in range(200): cur = ids[:] tgt = ids[:] random.shuffle(cur) random.shuffle(tgt) run_case(cur, tgt, f"n={n}") total += 1 # 头部必须换人的用例 cases = [ ([3, 2, 1], [1, 2, 3]), ([5, 4, 3, 2, 1], [1, 2, 3, 4, 5]), ([2, 3, 1], [1, 2, 3]), ([4, 1, 2, 3], [1, 2, 3, 4]), ] for cur, tgt in cases: run_case(cur, tgt, f"head {cur}->{tgt}") # 已排序不应产生移动 assert build_moves([1, 2, 3], [1, 2, 3]) == [] print(f"OK: {total} 个随机用例 + {len(cases)} 个头部用例全部通过") if __name__ == "__main__": main()