feat: 对手牌型预测 — PredictOpponent + ISMCTS 候选加权
CardTracker: - 新增 OpponentPrediction 类: RankProbabilities/MaxRank/BombProbability/LikelyPairs/LikelyTriples/MaxStraightLength - 新增 PredictOpponent: 基于剩余rank计数+对手手牌数计算期望持有量 核心公式: expected = remainingCount × (oppNeed / totalUnknown) 推断: 对子(>=1.5期望)/三张(>=2.5)/炸弹概率/顺子长度/MaxRank - Pass约束强化: 对手pass过某单张 → 降低MaxRank IsmctsBot: - 新增步骤5.7 对手牌型预测加权: 我的出牌rank > 对手MaxRank → +8-13% 我的出牌rank < 对手MaxRank → -5% 对手可能有炸弹 → 大牌型-3% 验证: 100局0错误 0.8s/局
This commit is contained in:
@ -278,6 +278,40 @@ namespace PdkFriendServer.Logic
|
||||
}
|
||||
}
|
||||
|
||||
// 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++)
|
||||
{
|
||||
var (p, wr, am, m) = scoredCandidates[i];
|
||||
if (p.Type == CardType1.None || p.Ids == null || p.Ids.Length == 0)
|
||||
continue;
|
||||
|
||||
int myRank = p.GameNum;
|
||||
|
||||
// 我的出牌 rank 高于两对手最高牌 → 他们很可能压不了
|
||||
if (myRank > oppMaxRank && oppMaxRank > 0)
|
||||
{
|
||||
wr += 0.08;
|
||||
if (opp1Pred.LikelyNoHigherThan(myRank) && opp2Pred.LikelyNoHigherThan(myRank))
|
||||
wr += 0.05; // 两个对手都可能压不了 → 更像无敌
|
||||
}
|
||||
// 我的出牌低于对手最高牌 → 容易被压制
|
||||
else if (myRank < oppMaxRank && oppMaxRank > 0)
|
||||
{
|
||||
wr -= 0.05;
|
||||
}
|
||||
|
||||
// 对手可能有炸弹 → 大牌型谨慎
|
||||
double maxBombProb = Math.Max(opp1Pred.BombProbability, opp2Pred.BombProbability);
|
||||
if (maxBombProb > 0.3 && (p.Type == CardType1.ZhaDan || p.Type == CardType1.ShunZi))
|
||||
wr -= 0.03;
|
||||
|
||||
scoredCandidates[i] = (p, wr, am, m);
|
||||
}
|
||||
|
||||
// 6. 两阶段选择:多牌优先
|
||||
scoredCandidates.Sort((a, b) => b.winRate.CompareTo(a.winRate));
|
||||
var best = scoredCandidates[0];
|
||||
|
||||
Reference in New Issue
Block a user