Files
hjha-server/hjha-console/Program.cs

147 lines
7.0 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
{
public static int RotateInterval = 0; // 0=disabled, N=rotate every N rounds
private static readonly string[][] Rotations = new[] { // 3种排列
new[] { "ISMCTS", "ISMCTS", "NEURAL" },
new[] { "NEURAL", "ISMCTS", "ISMCTS" },
new[] { "ISMCTS", "NEURAL", "ISMCTS" }
};
static void Main(string[] args)
{
if (args.Length > 0 && args[0] == "--eval") { PdkGameMain.BotTypes = new[] { "ISMCTS", "ISMCTS", "NEURAL" }; TrainingCollector.Enabled = false; args = new[] { "--stress", args.Length > 1 ? args[1] : "10" }; }
if (args.Length > 0 && args[0] == "--mix") { PdkGameMain.BotTypes = new[] { "ISMCTS", "ISMCTS", "NEURAL" }; TrainingCollector.Enabled = true; args = new[] { "--stress", args.Length > 1 ? args[1] : "10" }; }
if (args.Length > 0 && args[0] == "--mix-rotate") { PdkGameMain.BotTypes = new[] { "ISMCTS", "ISMCTS", "NEURAL" }; TrainingCollector.Enabled = true; Program.RotateInterval = 10; args = new[] { "--stress", args.Length > 1 ? args[1] : "10" }; }
if (args.Length > 0 && args[0] == "--mix-ismcts") { PdkGameMain.BotTypes = new[] { "ISMCTS", "ISMCTS", "ISMCTS" }; TrainingCollector.Enabled = true; args = new[] { "--stress", args.Length > 1 ? args[1] : "10" }; }
if (args.Length > 0 && args[0] == "--bots") { PdkGameMain.BotTypes = args[1].Split(','); TrainingCollector.Enabled = true; args = args.Length > 2 ? new[] { "--stress", args[2] } : new[] { "--stress", "10" }; }
if (args.Length > 0 && args[0] == "--n2h2v5") { PdkGameMain.BotTypes = new[] { "ISMCTS", "ISMCTS", "NEURAL_V5" }; TrainingCollector.Enabled = false; args = new[] { "--stress", args.Length > 1 ? args[1] : "10" }; }
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++)
{
// 位置轮换: 每N局切换排列
if (RotateInterval > 0 && (r - 1) % RotateInterval == 0)
{
int ri = ((r - 1) / RotateInterval) % Rotations.Length;
PdkGameMain.BotTypes = Rotations[ri];
}
var roundSw = Stopwatch.StartNew();
try
{
var main = new PdkGameMain(null);
main.BotMode = true;
// 本轮日志路径
var logPath = $"{logDir}/round_{r:D5}.txt";
if (File.Exists("output.txt")) File.Delete("output.txt");
// 重定向 Console stdout → 本轮 ISMCTS 日志
var ismctsLog = $"{logDir}/round_{r:D5}_ismcts.txt";
var oldOut = Console.Out;
var ismctsWriter = new StreamWriter(ismctsLog) { AutoFlush = true };
Console.SetOut(ismctsWriter);
main.Test("");
Console.SetOut(oldOut); // 先恢复再Close (macOS兼容)
ismctsWriter.Close();
// 合并 output.txt + ISMCTS 日志 → 本轮日志
using (var combined = new StreamWriter(logPath, false))
{
if (File.Exists(ismctsLog))
{
combined.Write(File.ReadAllText(ismctsLog));
combined.WriteLine();
File.Delete(ismctsLog);
}
if (File.Exists("output.txt"))
{
combined.Write(File.ReadAllText("output.txt"));
}
}
if (File.Exists("output.txt")) File.Delete("output.txt");
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");
}
}
}