fix: 预测加权按牌型区分压制条件 — 修复SanDai2误杀
根因: oppMaxRank仅代表「对手有单牌」,但用单牌概率惩罚对子/三带二 → 三带二需要对手有3张同rank才能压制,不是1张 修复: 按牌型分别判断 - DanZhang: 用 MaxRank (单牌条件) - DuiZi: 用 LikelyPairs (对手是否有更高对子) - SanZhang/SanDai2: 用 LikelyTriples (对手是否有更高三张) - ShunZi: 用 MaxStraightLength + MaxRank - 其他: 默认 MaxRank 效果: SanDai2 52→75/30局 (+44%), 多牌比例 25.4%→26.1% 验证: 100局0错误 0.8s/局
This commit is contained in:
@ -278,10 +278,9 @@ namespace PdkFriendServer.Logic
|
||||
}
|
||||
}
|
||||
|
||||
// 5.7. 对手牌型预测加权:基于剩余牌计数推断对手能压制我的概率
|
||||
// 5.7. 对手牌型预测加权:按牌型区分压制条件
|
||||
var opp1Pred = _tracker.PredictOpponent(view.MyPos % 3, hand, view);
|
||||
var opp2Pred = _tracker.PredictOpponent((view.MyPos + 1) % 3, hand, view);
|
||||
int oppMaxRank = Math.Max(opp1Pred.MaxRank, opp2Pred.MaxRank);
|
||||
|
||||
for (int i = 0; i < scoredCandidates.Count; i++)
|
||||
{
|
||||
@ -291,22 +290,60 @@ namespace PdkFriendServer.Logic
|
||||
|
||||
int myRank = p.GameNum;
|
||||
|
||||
// 我的出牌 rank 高于两对手最高牌 → 他们很可能压不了
|
||||
if (myRank > oppMaxRank && oppMaxRank > 0)
|
||||
// 按牌型判定:对手是否有能力压制
|
||||
bool oppLikelyCanBeat = false;
|
||||
bool oppLikelyCantBeat = false;
|
||||
|
||||
switch (p.Type)
|
||||
{
|
||||
wr += 0.08;
|
||||
if (opp1Pred.LikelyNoHigherThan(myRank) && opp2Pred.LikelyNoHigherThan(myRank))
|
||||
wr += 0.05; // 两个对手都可能压不了 → 更像无敌
|
||||
}
|
||||
// 我的出牌低于对手最高牌 → 容易被压制
|
||||
else if (myRank < oppMaxRank && oppMaxRank > 0)
|
||||
{
|
||||
wr -= 0.05;
|
||||
case CardType1.DanZhang:
|
||||
// 单张:对手有更高 rank 的单张就能压制
|
||||
oppLikelyCanBeat = opp1Pred.MaxRank > myRank || opp2Pred.MaxRank > myRank;
|
||||
oppLikelyCantBeat = opp1Pred.MaxRank > 0 && opp2Pred.MaxRank > 0
|
||||
&& opp1Pred.MaxRank <= myRank && opp2Pred.MaxRank <= myRank;
|
||||
break;
|
||||
case CardType1.DuiZi:
|
||||
// 对子:对手需要有更高的对子(LikelyPairs ≥ 2张同rank)
|
||||
oppLikelyCanBeat = opp1Pred.LikelyPairs.Any(r => r > myRank)
|
||||
|| opp2Pred.LikelyPairs.Any(r => r > myRank);
|
||||
oppLikelyCantBeat = opp1Pred.LikelyNoPairHigherThan(myRank)
|
||||
&& opp2Pred.LikelyNoPairHigherThan(myRank)
|
||||
&& opp1Pred.MaxRank > 0 && opp2Pred.MaxRank > 0;
|
||||
break;
|
||||
case CardType1.SanZhang:
|
||||
case CardType1.SanDai2:
|
||||
// 三张/三带二:对手需要有更高的三张(LikelyTriples ≥ 3张同rank)
|
||||
oppLikelyCanBeat = opp1Pred.LikelyTriples.Any(r => r > myRank)
|
||||
|| opp2Pred.LikelyTriples.Any(r => r > myRank);
|
||||
oppLikelyCantBeat = opp1Pred.LikelyTriples.Count == 0
|
||||
&& opp2Pred.LikelyTriples.Count == 0
|
||||
&& opp1Pred.MaxRank > 0 && opp2Pred.MaxRank > 0;
|
||||
break;
|
||||
case CardType1.ShunZi:
|
||||
// 顺子:对手需要有更长的同长顺子
|
||||
int myLen = p.Ids.Length;
|
||||
oppLikelyCanBeat = (opp1Pred.MaxStraightLength >= myLen
|
||||
&& opp1Pred.MaxRank > myRank)
|
||||
|| (opp2Pred.MaxStraightLength >= myLen
|
||||
&& opp2Pred.MaxRank > myRank);
|
||||
break;
|
||||
default:
|
||||
// 连对/飞机/炸弹:用 rank 近似
|
||||
oppLikelyCanBeat = opp1Pred.MaxRank > myRank || opp2Pred.MaxRank > myRank;
|
||||
oppLikelyCantBeat = opp1Pred.MaxRank > 0 && opp2Pred.MaxRank > 0
|
||||
&& opp1Pred.MaxRank <= myRank && opp2Pred.MaxRank <= myRank;
|
||||
break;
|
||||
}
|
||||
|
||||
if (oppLikelyCantBeat)
|
||||
wr += 0.10; // 两个对手都可能压不了 → 近似无敌
|
||||
else if (oppLikelyCanBeat)
|
||||
wr -= 0.04; // 对手大概率能压制 → 轻微惩罚
|
||||
|
||||
// 对手可能有炸弹 → 大牌型谨慎
|
||||
double maxBombProb = Math.Max(opp1Pred.BombProbability, opp2Pred.BombProbability);
|
||||
if (maxBombProb > 0.3 && (p.Type == CardType1.ZhaDan || p.Type == CardType1.ShunZi))
|
||||
if (maxBombProb > 0.3 && (p.Type == CardType1.ZhaDan || p.Type == CardType1.ShunZi
|
||||
|| p.Type == CardType1.SanDai2 || p.Type == CardType1.LianDui))
|
||||
wr -= 0.03;
|
||||
|
||||
scoredCandidates[i] = (p, wr, am, m);
|
||||
|
||||
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