fix: code review — 修复4个问题

1. CardTracker.UnknownCount: 48→52 (硬编码修正)
2. IsmctsBot.GenerateDeck → 静态FullDeck池复用 (减少对象分配)
3. CardTracker: 删除3个死字段(_passStreak/_isNewRound/_bombCounts)
4. CardTracker.Update: 清理pass约束记录逻辑

验证: 100局0错误, 0.9s/局
This commit is contained in:
2026-07-13 00:21:15 +08:00
parent 7fdc45057c
commit 180be25ffa
8 changed files with 25 additions and 34 deletions

View File

@ -29,13 +29,6 @@ namespace PdkFriendServer.Logic
// 对手约束:[pos-2] = 该对手 pass 过的牌型列表
private readonly List<PassConstraint>[] _opponentConstraints;
// 当前轮次 pass 计数
private int _passStreak;
private bool _isNewRound;
// 每个位置的炸弹计数
private readonly int[] _bombCounts = new int[3];
public CardTracker()
{
_opponentConstraints = new List<PassConstraint>[3];
@ -64,33 +57,22 @@ namespace PdkFriendServer.Logic
var currentMax = view.MaxPlayCard;
if (currentMax.Ids != null && currentMax.Ids.Length > 0)
{
// 如果是新出牌(不是上一轮的)
// 新出牌 → 记录
if (_lastMaxPlay.Ids == null ||
!_lastMaxPlay.Ids.SequenceEqual(currentMax.Ids))
{
foreach (var id in currentMax.Ids) _seenCardIds.Add(id);
_passStreak = 0;
_isNewRound = false;
}
else if (_lastMaxPlay.Ids != null)
else
{
// 同一手牌还在桌上 → 有人 pass 了
_passStreak++;
// 记录 pass 约束(轮到谁 pass 了就是谁)
int passer = currentMax.Pos > 0
? (currentMax.Pos % 3 + 1) // 下一位
? (currentMax.Pos % 3 + 1)
: 0;
if (passer > 0 && passer != myPos)
{
RecordPassConstraint(passer, currentMax);
}
}
}
else
{
_isNewRound = true;
_passStreak = 0;
}
_lastMaxPlay = new PlayOutCardPdkF
{
@ -99,10 +81,6 @@ namespace PdkFriendServer.Logic
Type = currentMax.Type,
Ids = currentMax.Ids?.ToArray()
};
// 3. 追踪炸弹计数
for (int i = 0; i < 3; i++)
_bombCounts[i] = view.ZhaDans[i];
}
/// <summary>
@ -113,16 +91,13 @@ namespace PdkFriendServer.Logic
_seenCardIds.Clear();
_lastMyHandIds = null;
_lastMaxPlay = new PlayOutCardPdkF();
_passStreak = 0;
_isNewRound = true;
foreach (var c in _opponentConstraints) c.Clear();
Array.Clear(_bombCounts, 0, 3);
}
// ---- 查询接口 ----
/// <summary>返回外面还有多少未知卡</summary>
public int UnknownCount => 48 - _seenCardIds.Count;
public int UnknownCount => 52 - _seenCardIds.Count;
/// <summary>在外面可能存在的炸弹数(按 rank 计)</summary>
public int BombsOutside(TCardInfoPdkF[] myHand)

View File

@ -295,7 +295,7 @@ namespace PdkFriendServer.Logic
hands[nextPos - 1] = new List<TCardInfoPdkF>();
hands[oppPos - 1] = new List<TCardInfoPdkF>();
var allCards = GenerateDeck();
var allCards = GetDeckCopy();
var unknown = allCards.Where(c => !myHand.Any(h => h.ID == c.ID)).ToList();
// 使用 CardTracker 进行约束采样
@ -495,13 +495,29 @@ namespace PdkFriendServer.Logic
return best;
}
private static List<TCardInfoPdkF> GenerateDeck()
// 静态牌池52张牌只创建一次
private static readonly TCardInfoPdkF[] FullDeck;
static IsmctsBot()
{
var d = new List<TCardInfoPdkF>(); int id = 1;
FullDeck = new TCardInfoPdkF[52];
int id = 1;
foreach (int f in new[] { 1, 2, 3, 4 })
for (int n = 1; n <= 13; n++)
d.Add(new TCardInfoPdkF { ID = (byte)id++, Flower = (byte)f, GameNum = (byte)(n == 1 ? 14 : n == 2 ? 16 : n), GameState = 1 });
return d;
FullDeck[id - 1] = new TCardInfoPdkF
{
ID = (byte)id,
Flower = (byte)f,
GameNum = (byte)(n == 1 ? 14 : n == 2 ? 16 : n),
GameState = 1
};
}
private static List<TCardInfoPdkF> GetDeckCopy()
{
return FullDeck.Where(c => c.ID > 0).Select(c => new TCardInfoPdkF
{
ID = c.ID, Flower = c.Flower, GameNum = c.GameNum, GameState = 1
}).ToList();
}
private void Shuffle<T>(List<T> l) { for (int i = l.Count - 1; i > 0; i--) { int j = _rng.Next(i + 1); (l[i], l[j]) = (l[j], l[i]); } }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.