Files
hjha-server/hjha-console/Program.cs
xiaoou 4a3fbec057 test: 1000轮 ISMCTS 压测 + 完整分析报告
新增:
- hjha-console/Program.cs: --stress N 压测模式
  - 每局独立日志 stress_logs/round_NNNNN.txt
  - 每 50 局进度汇报 + 异常捕获
- docs/stress-test-report.md: 完整分析报告
  - P0: 包庄严重高估(5.2%成功) → 需校准阈值
  - P1: 75 moves 异常局 → 疑似死循环
  - P2: 只出单张不组合 → rollout 优化
  - P3: 性能瓶颈分析
- .gitignore: stress_logs/, analyze_stress.py

压测结果: 12.8min, 0 crashes, 1000/1000通过
2026-07-07 13:53:46 +08:00

108 lines
4.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using PdkFriendServer.Logic;
using System;
using System.Diagnostics;
using System.IO;
namespace hjha_console
{
class Program
{
static void Main(string[] args)
{
if (args.Length > 0 && args[0] == "--stress")
{
int rounds = args.Length > 1 ? int.Parse(args[1]) : 100;
RunStressTest(rounds);
return;
}
Console.WriteLine("=== HJHA Console Mode - 跑得快 Bot对局 (3人自动) ===");
Console.WriteLine("牌型:关牌玩法 16张/人 | 策略ISMCTS 800sims");
Console.WriteLine("压测: dotnet run --project hjha-console -- --stress 1000");
Console.WriteLine();
var main = new PdkGameMain(null);
main.BotMode = true;
main.Test(args.Length > 0 ? args[0] : "");
}
static void RunStressTest(int totalRounds)
{
var logDir = "stress_logs";
if (!Directory.Exists(logDir)) Directory.CreateDirectory(logDir);
// 清理旧日志
foreach (var f in Directory.GetFiles(logDir, "round_*.txt"))
File.Delete(f);
File.Delete("stress_errors.txt");
File.Delete("stress_summary.txt");
Console.WriteLine($"=== PdkBot Stress Test: {totalRounds} rounds ===");
Console.WriteLine($"Logs: {logDir}/");
Console.WriteLine($"Start: {DateTime.Now:HH:mm:ss}");
Console.WriteLine();
int completed = 0, errors = 0;
var totalSw = Stopwatch.StartNew();
var errorLog = new StreamWriter("stress_errors.txt", true) { AutoFlush = true };
for (int r = 1; r <= totalRounds; r++)
{
var roundSw = Stopwatch.StartNew();
try
{
var main = new PdkGameMain(null);
main.BotMode = true;
// 重定向 output.txt 到本轮日志
var logPath = $"{logDir}/round_{r:D5}.txt";
if (File.Exists("output.txt")) File.Delete("output.txt");
main.Test("");
// 移动 output.txt → 本轮日志
if (File.Exists("output.txt"))
File.Move("output.txt", logPath);
completed++;
roundSw.Stop();
if (r % 50 == 0 || r == totalRounds)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {r}/{totalRounds} rounds | " +
$"{errors} errors | avg {totalSw.Elapsed.TotalSeconds / r:F1}s/round | " +
$"last {roundSw.ElapsedMilliseconds}ms");
}
}
catch (Exception ex)
{
errors++;
errorLog.WriteLine($"Round {r}: {ex.GetType().Name}: {ex.Message}");
errorLog.WriteLine(ex.StackTrace);
errorLog.WriteLine("---");
Console.WriteLine($" R{r} ERROR: {ex.GetType().Name}: {ex.Message}");
// 保存本轮部分日志
if (File.Exists("output.txt"))
File.Move("output.txt", $"{logDir}/round_{r:D5}_ERROR.txt");
}
}
totalSw.Stop();
errorLog.Close();
// 汇总
Console.WriteLine();
Console.WriteLine($"=== Stress Test Complete ===");
Console.WriteLine($"Rounds: {completed}/{totalRounds} completed, {errors} errors");
Console.WriteLine($"Total time: {totalSw.Elapsed.TotalMinutes:F1} min");
Console.WriteLine($"Avg per round: {totalSw.Elapsed.TotalSeconds / totalRounds:F1}s");
File.WriteAllText("stress_summary.txt",
$"Rounds: {completed}/{totalRounds}\n" +
$"Errors: {errors}\n" +
$"Total: {totalSw.Elapsed.TotalMinutes:F1}min\n" +
$"Avg: {totalSw.Elapsed.TotalSeconds / totalRounds:F1}s/round\n");
}
}
}