fix: FastSim清牌效率优先 — 领牌出多牌+最小rank, 跟牌出最小压制
核心改动: 从'出最大的看谁能压'改为'出最省的清牌快' 领牌(新轮): - 三张 > 对子 > 单张 (多牌优先) - 始终用最小rank (保留大牌给跟牌阶段) 跟牌: - 三张/对子: 找最小rank能压制的同类型 - 单张: 出最小的压制牌(保留大牌) 效果: 多牌29%→34% (+5%), 单张-4.4%, 0.7s/局 vs IsmctsBot: 34% vs 53%, 差距来自straight/飞机等复杂牌型在rollout中缺失
This commit is contained in:
@ -190,7 +190,9 @@ namespace PdkFriendServer.Logic
|
|||||||
return FastSim(o1g, o2g, mg, current, myGameNum, CardType1.DanZhang, myPos - 1, 0);
|
return FastSim(o1g, o2g, mg, current, myGameNum, CardType1.DanZhang, myPos - 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 快速模拟核心:全部用 byte[]。支持单张+对子。
|
// 快速模拟核心:清牌效率优先。
|
||||||
|
// 领牌:优先出多牌组合(3张>2张>1张),用最小的 rank 保留大牌
|
||||||
|
// 跟牌:出最小的能压制的牌,保留大牌
|
||||||
private bool FastSim(List<byte> h1, List<byte> h2, List<byte> my,
|
private bool FastSim(List<byte> h1, List<byte> h2, List<byte> my,
|
||||||
int current, byte maxGameNum, CardType1 maxType, int maxPlayer, int depth)
|
int current, byte maxGameNum, CardType1 maxType, int maxPlayer, int depth)
|
||||||
{
|
{
|
||||||
@ -201,44 +203,63 @@ namespace PdkFriendServer.Logic
|
|||||||
|
|
||||||
var cur = current == 0 ? h1 : current == 1 ? h2 : my;
|
var cur = current == 0 ? h1 : current == 1 ? h2 : my;
|
||||||
bool isNewRound = maxPlayer == current || maxGameNum == 0;
|
bool isNewRound = maxPlayer == current || maxGameNum == 0;
|
||||||
|
bool isMe = (current == 2);
|
||||||
|
|
||||||
if (isNewRound)
|
if (isNewRound)
|
||||||
{
|
{
|
||||||
if (cur.Count == 0) return false;
|
if (cur.Count == 0) return false;
|
||||||
// 找对子(贪心:出最大的对子)
|
|
||||||
var groups = cur.GroupBy(g => g).Where(g => g.Count() >= 2).OrderByDescending(g => g.Key).ToList();
|
// 清牌效率排序: 三张 > 对子 > 单张。始终用最小的 rank
|
||||||
if (groups.Count > 0)
|
var groups = cur.GroupBy(g => g).OrderBy(g => g.Key).ToList();
|
||||||
|
|
||||||
|
// 三张(清 3 张)
|
||||||
|
var triples = groups.Where(g => g.Count() >= 3).ToList();
|
||||||
|
if (triples.Count > 0)
|
||||||
{
|
{
|
||||||
var pair = groups[0];
|
var t = triples[0];
|
||||||
var toRemove = pair.Take(2).ToList();
|
var toRemove = t.Take(3).ToList();
|
||||||
foreach (var g in toRemove) cur.Remove(g);
|
foreach (var g in toRemove) cur.Remove(g);
|
||||||
return FastSim(h1, h2, my, (current + 1) % 3, pair.Key, CardType1.DuiZi, current, depth + 1);
|
return FastSim(h1, h2, my, (current + 1) % 3, t.Key, CardType1.SanZhang, current, depth + 1);
|
||||||
}
|
}
|
||||||
// 单张
|
|
||||||
var sorted = cur.OrderByDescending(g => g).ToList();
|
// 对子(清 2 张)
|
||||||
byte play = sorted[0];
|
var pairs = groups.Where(g => g.Count() >= 2).ToList();
|
||||||
|
if (pairs.Count > 0)
|
||||||
|
{
|
||||||
|
var p = pairs[0];
|
||||||
|
var toRemove = p.Take(2).ToList();
|
||||||
|
foreach (var g in toRemove) cur.Remove(g);
|
||||||
|
return FastSim(h1, h2, my, (current + 1) % 3, p.Key, CardType1.DuiZi, current, depth + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单张:出最小的
|
||||||
|
byte play = groups[0].Key;
|
||||||
cur.Remove(play);
|
cur.Remove(play);
|
||||||
return FastSim(h1, h2, my, (current + 1) % 3, play, CardType1.DanZhang, current, depth + 1);
|
return FastSim(h1, h2, my, (current + 1) % 3, play, CardType1.DanZhang, current, depth + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 跟牌:找能压制的同类型牌
|
// 跟牌:有牌能压 → 出最小的压制牌
|
||||||
|
if (maxType == CardType1.DuiZi || maxType == CardType1.SanZhang)
|
||||||
|
{
|
||||||
|
int need = maxType == CardType1.SanZhang ? 3 : 2;
|
||||||
|
var groups = cur.GroupBy(g => g)
|
||||||
|
.Where(g => g.Count() >= need && g.Key > maxGameNum)
|
||||||
|
.OrderBy(g => g.Key).ToList();
|
||||||
|
if (groups.Count > 0)
|
||||||
|
{
|
||||||
|
var g = groups[0];
|
||||||
|
var toRemove = g.Take(need).ToList();
|
||||||
|
foreach (var x in toRemove) cur.Remove(x);
|
||||||
|
return FastSim(h1, h2, my, (current + 1) % 3, g.Key, maxType, current, depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单张跟牌:出最小的可压牌
|
||||||
var bigger = cur.Where(g => g > maxGameNum).OrderBy(g => g).ToList();
|
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)
|
if (bigger.Count > 0)
|
||||||
{
|
{
|
||||||
byte play = bigger[0];
|
byte play = bigger[0]; // 最小压制
|
||||||
cur.Remove(play);
|
cur.Remove(play);
|
||||||
return FastSim(h1, h2, my, (current + 1) % 3, play, CardType1.DanZhang, current, depth + 1);
|
return FastSim(h1, h2, my, (current + 1) % 3, play, CardType1.DanZhang, current, depth + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user