perf: FastSim rollout 支持对子 (DuiZi) — 模拟更真实

FastSim改进:
- 新轮次: 优先找最大对子 → 再出最大单张
- 跟牌: 对子跟牌→找≥2张同rank且大于对手
- 单张跟牌: 找最小可压牌

效果: 多牌29%, ShunZi 8.8%, DuiZi 19.0%, 0.8s/局

已知局限: 贪婪rollout低估清牌效率, 后续需全局序列优化
This commit is contained in:
2026-07-12 23:31:11 +08:00
parent 30a4d06b33
commit 8b30caff1a
7 changed files with 24 additions and 3 deletions

View File

@ -190,7 +190,7 @@ namespace PdkFriendServer.Logic
return FastSim(o1g, o2g, mg, current, myGameNum, CardType1.DanZhang, myPos - 1, 0);
}
// 快速模拟核心:全部用 byte[]
// 快速模拟核心:全部用 byte[]。支持单张+对子。
private bool FastSim(List<byte> h1, List<byte> h2, List<byte> my,
int current, byte maxGameNum, CardType1 maxType, int maxPlayer, int depth)
{
@ -202,10 +202,19 @@ namespace PdkFriendServer.Logic
var cur = current == 0 ? h1 : current == 1 ? h2 : my;
bool isNewRound = maxPlayer == current || maxGameNum == 0;
// 贪心:找最大可出牌
if (isNewRound)
{
if (cur.Count == 0) return false;
// 找对子(贪心:出最大的对子)
var groups = cur.GroupBy(g => g).Where(g => g.Count() >= 2).OrderByDescending(g => g.Key).ToList();
if (groups.Count > 0)
{
var pair = groups[0];
var toRemove = pair.Take(2).ToList();
foreach (var g in toRemove) cur.Remove(g);
return FastSim(h1, h2, my, (current + 1) % 3, pair.Key, CardType1.DuiZi, current, depth + 1);
}
// 单张
var sorted = cur.OrderByDescending(g => g).ToList();
byte play = sorted[0];
cur.Remove(play);
@ -213,8 +222,20 @@ namespace PdkFriendServer.Logic
}
else
{
// 找能压制的最大
// 跟牌:找能压制的同类型
var bigger = cur.Where(g => g > maxGameNum).OrderBy(g => g).ToList();
if (maxType == CardType1.DuiZi)
{
// 对子:找 ≥2 张且大于 maxGameNum
var pairGroups = cur.GroupBy(g => g).Where(g => g.Count() >= 2 && g.Key > maxGameNum).OrderBy(g => g.Key).ToList();
if (pairGroups.Count > 0)
{
var pair = pairGroups[0];
var toRemove = pair.Take(2).ToList();
foreach (var g in toRemove) cur.Remove(g);
return FastSim(h1, h2, my, (current + 1) % 3, pair.Key, CardType1.DuiZi, current, depth + 1);
}
}
if (bigger.Count > 0)
{
byte play = bigger[0];