using System;
using System.Collections.Generic;
using System.Linq;
using GameFix.PaoDeKuaiF;
using GameMessage;
using GameMessage.PaoDeKuaiF;
namespace PdkFriendServer.Logic
{
///
/// 终局精确求解器 — 手牌≤5张时,枚举所有对手手牌分布,每分布模拟到底。
/// 替代 ISMCTS 采样:残局决策更精确。
///
public static class EndgameSolver
{
private const int MaxDepth = 30;
public static PlayOutCardPdkF? Solve(
TCardInfoPdkF[] hand,
PdkBotView view,
CardTracker tracker,
Random rng)
{
if (hand.Length > 5) return null;
if (tracker.UnknownCount(hand) > 15) return null;
int myPos = view.MyPos;
int opp1 = myPos % 3;
int opp2 = (myPos + 1) % 3;
int o1c = view.ShenYuCard[opp1];
int o2c = view.ShenYuCard[opp2];
var pool = GeneratePool(hand, tracker);
if (pool.Count < o1c + o2c) return null;
bool isFirstPlay = view.MaxPlayCard.GameNum <= 0;
var tips = PdkCardAlgorithm.GetTipCard(view.MaxPlayCard, hand, null, view.Rule.AAAIsZhaDan);
var candidates = new List>();
if (tips != null) foreach (var t in tips) candidates.Add(t);
if (!isFirstPlay) candidates.Add(new List());
if (candidates.Count == 0) return null;
int samples = Math.Min(100, ComputeCombinations(pool.Count, o1c + o2c));
var bestPlay = candidates[0]; // safe default
int bestWins = -1;
for (int ci = 0; ci < candidates.Count; ci++)
{
var play = candidates[ci];
int wins = 0;
var myRem = hand.Where(c => c.GameState == 1).ToList();
if (play.Count > 0)
foreach (var p in play) myRem.RemoveAll(h => h.ID == p.ID);
if (myRem.Count == 0) { bestPlay = play; break; }
for (int s = 0; s < samples; s++)
{
var shuf = new List(pool);
Shuffle(shuf, rng);
var o1 = shuf.Take(o1c).ToList();
var o2 = shuf.Skip(o1c).Take(o2c).ToList();
PlayOutCardPdkF maxPlay;
int maxPlayer;
int current;
if (play.Count == 0) // pass
{
maxPlay = Clone(view.MaxPlayCard);
maxPlayer = view.MaxPlayCard.Pos > 0 ? view.MaxPlayCard.Pos - 1 : myPos - 1;
current = myPos % 3;
}
else
{
maxPlay = new PlayOutCardPdkF { GameNum = play[0].GameNum, Type = CardType1.DanZhang };
maxPlayer = myPos - 1;
current = myPos % 3;
}
if (Simulate(o1, o2, myRem, current, maxPlay, maxPlayer, 0))
wins++;
}
if (wins > bestWins) { bestWins = wins; bestPlay = play; }
}
if (bestPlay.Count == 0)
return new PlayOutCardPdkF { Pos = (byte)myPos, Type = CardType1.None };
return new PlayOutCardPdkF
{
Pos = (byte)myPos,
GameNum = bestPlay[0].GameNum,
Ids = bestPlay.Select(c => c.ID).ToArray(),
Type = CardType1.None
};
}
// 简化模拟:给定对手手牌,模拟到终局
private static bool Simulate(
List h1, List h2, List myHand,
int current, // 0=h1, 1=h2, 2=me
PlayOutCardPdkF maxPlay, int maxPlayer, int depth)
{
if (depth > MaxDepth) return myHand.Count <= Math.Min(h1.Count, h2.Count);
if (h1.Count == 0) return false;
if (h2.Count == 0) return false;
if (myHand.Count == 0) return true;
var cur = current == 0 ? h1 : current == 1 ? h2 : myHand;
bool isNewRound = maxPlayer == current || maxPlay.GameNum <= 0;
int next = (current + 1) % 3;
var tips = PdkCardAlgorithm.GetTipCard(
isNewRound ? new PlayOutCardPdkF() : maxPlay,
cur.ToArray(), null, false);
if (tips != null && tips.Count > 0)
{
var pick = tips[tips.Count - 1]; // 贪心:出最大的
foreach (var c in pick) cur.RemoveAll(h => h.ID == c.ID);
var newMax = new PlayOutCardPdkF { GameNum = pick[0].GameNum, Type = CardType1.DanZhang };
return Simulate(h1, h2, myHand, next, newMax, current, depth + 1);
}
// pass
return Simulate(h1, h2, myHand, next, maxPlay, isNewRound ? current : maxPlayer, depth + 1);
}
private static List GeneratePool(TCardInfoPdkF[] hand, CardTracker tracker)
{
return tracker.GetUnknownPool(hand);
}
private static int ComputeCombinations(int n, int k)
{
if (k > n) return 0;
long result = 1;
for (int i = 1; i <= k; i++) result = result * (n - i + 1) / i;
return (int)Math.Min(result, 100);
}
private static void Shuffle(List l, Random rng)
{
for (int i = l.Count - 1; i > 0; i--)
{ int j = rng.Next(i + 1); (l[i], l[j]) = (l[j], l[i]); }
}
private static PlayOutCardPdkF Clone(PlayOutCardPdkF s)
=> new PlayOutCardPdkF { Pos = s.Pos, GameNum = s.GameNum, Type = s.Type, Ids = s.Ids?.ToArray() };
}
}