fix: InferType — ISMCTS模拟Type不再为None,所有牌型正确推演

根因: MakePlay/AddCandidate设Type=None,导致SimulateOneGame中
myPlay.Type=None, GetTipCard不匹配任何case→对手全员pass→评估失真

修复:
- 新增 InferType(): 根据牌数和面值分布推断牌型
  1张→DanZhang 2张→DuiZi 4同→ZhaDan 4+2→SiDai2
  4+3→SiDai3 3+2→SanDai2 ≥5→顺子/连对
- AddCandidate+MakePlay 均使用 InferType 替代 CardType1.None
- ISMCTS模拟中对手能正确识别我的出牌类型并跟牌

10局验证: FeiJi首次出现(2次), 全牌型:
  DanZhang 72 | DuiZi 47 | ShunZi 11 | SanDai2 10 | LianDui 5 | FeiJi 2 | ZhaDan 1
多牌比例: 51%
This commit is contained in:
2026-07-07 14:32:13 +08:00
parent 6299e4e580
commit d520534b5b
7 changed files with 29 additions and 12 deletions

View File

@ -400,12 +400,39 @@ namespace PdkFriendServer.Logic
{
Pos = (byte)pos, GameNum = cards[0].GameNum,
Ids = cards.Select(c => c.ID).ToArray(),
Type = CardType1.None
Type = InferType(cards)
}, true));
multiCount++;
}
/// <summary>获取指定数量的同面值组合(对子=2三张=3</summary>
/// <summary>根据牌数和面值推断牌型——ISMCTS模拟需要正确Type</summary>
private static CardType1 InferType(List<TCardInfoPdkF> cards)
{
int n = cards.Count;
if (n == 1) return CardType1.DanZhang;
if (n == 2) return CardType1.DuiZi;
var counts = cards.GroupBy(c => c.GameNum).Select(g => g.Count()).OrderByDescending(x => x).ToList();
if (counts[0] == 4)
{
if (n == 4) return CardType1.ZhaDan;
if (n == 6) return CardType1.SiDai2;
if (n == 7) return CardType1.SiDai3;
}
if (counts[0] >= 3) return n == counts[0] + 2 ? CardType1.SanDai2 : CardType1.SanDai2;
return n >= 5 ? CardType1.ShunZi : CardType1.DuiZi;
}
private static PlayOutCardPdkF MakePlay(List<TCardInfoPdkF> cards, int pos)
{
return new PlayOutCardPdkF
{
Pos = (byte)pos, GameNum = cards[0].GameNum,
Ids = cards.Select(x => x.ID).ToArray(),
Type = InferType(cards)
};
}
/// <summary>获取指定数量的同面值组合</summary>
private static List<List<TCardInfoPdkF>> GetMultiGroups(TCardInfoPdkF[] hand, int count)
{
var result = new List<List<TCardInfoPdkF>>();
@ -537,16 +564,6 @@ namespace PdkFriendServer.Logic
};
}
private static PlayOutCardPdkF MakePlay(List<TCardInfoPdkF> cards, int pos)
{
return new PlayOutCardPdkF
{
Pos = (byte)pos, GameNum = cards[0].GameNum,
Ids = cards.Select(x => x.ID).ToArray(),
Type = CardType1.None // 不给假类型让引擎GetOutCard赋予真值
};
}
private static PlayOutCardPdkF Pass(PdkBotView view)
{
return new PlayOutCardPdkF { Pos = (byte)view.MyPos, Type = CardType1.None };