Files
hjha-server/PdkFriendServer/GameFix/PdkCardAlgorithm.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
2026-07-07 12:02:15 +08:00

624 lines
24 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using System.Linq;
using GameFix.Poker;
using GameMessage;
using GameMessage.PaoDeKuaiF;
namespace GameFix.PaoDeKuaiF
{
/// <summary>
/// 跑得快牌运算逻辑
/// </summary>
public class PdkCardAlgorithm
{
/// <summary>
/// 获取提示的牌
/// </summary>
/// <param name="outCard">当前出的牌</param>
/// <param name="shoupai">玩家在手里的牌,没有出下去的牌</param>
/// <param name="maxShouPai">当前出牌人的手牌</param>
/// <param name="aaaIsZhaDan">3A是不是炸弹默认不是</param>
/// <param name="isOne">只要一种提示 true是 false不是</param>
/// <returns></returns>
public static List<List<TCardInfoPdkF>> GetTipCardByBtn(PlayOutCardPdkF outCard, TCardInfoPdkF[] shoupai,
TCardInfoPdkF[] maxShouPai, bool aaaIsZhaDan = false, bool isOne = false)
{
if (shoupai == null || shoupai.Length <= 0) return null;
List<List<TCardInfoPdkF>> result = new List<List<TCardInfoPdkF>>();
if (outCard.GameNum <= 0)
{
//如果是自己先出的话, 就从尾部一张一张提示过去
for (int i = shoupai.Length - 1; i >= 0; i--)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF>();
chu.Add(shoupai[i]);
result.Add(chu);
}
return result;
}
switch (outCard.Type)
{
case CardType1.DanZhang:
var danzhangs = PokerLogic.GetDanZhang(outCard, shoupai);
if (danzhangs == null || danzhangs.Count <= 0)
{
danzhangs = PokerLogic.GetDanZhang(outCard, shoupai, true);
}
if (danzhangs != null && danzhangs.Count > 0)
{
danzhangs.Sort((x, y) => x.GameNum.CompareTo(y.GameNum));
foreach (var item in danzhangs)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF> { item };
result.Add(chu);
}
}
break;
case CardType1.DuiZi:
result = PokerLogic.GetCountCard(outCard, shoupai, 2);
if (result == null || result.Count <= 0)
{
result = PokerLogic.GetCountCard(outCard, shoupai, 2, true);
}
if (result != null)
{
result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
}
break;
case CardType1.SanDai2:
result = PokerLogic.GetCountCard(outCard, shoupai, 3, true);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.ShunZi:
result = PokerLogic.GetShunZi(outCard, shoupai);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.LianDui:
result = PokerLogic.GetLianCount(outCard, shoupai, 2, null);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.FeiJi:
result = PokerLogic.GetLianCount(outCard, shoupai, 3, maxShouPai);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.ZhaDan:
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards.Count > 4)
{
int c = cards.Count / 4;
for (int i = 0; i < c; i++)
{
var tx = cards.Skip(i * 4).Take(4).ToList();
if (tx != null && tx[0].GameNum > outCard.GameNum)
{
result.Add(tx);
}
}
}
else
{
if (cards != null && cards.Count > 0 && cards[0].GameNum > outCard.GameNum)
{
result.Add(cards);
}
}
break;
}
if (isOne && result != null && result.Count > 0)
{
//只要一种提示
}
else
{
if (result == null) result = new List<List<TCardInfoPdkF>>();
if (aaaIsZhaDan)
{
var aaa = GetAAAZhaDan(shoupai);
if (aaa != null && aaa.Count >= 3)
{
result.Add(aaa);
}
}
if (outCard.Type != CardType1.ZhaDan)
{
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards != null && cards.Count > 0)
{
int c = cards.Count / 4;
if (c <= 0)
{
result.Add(cards);
}
else
{
for (int i = 0; i < c; i++)
{
result.Add(cards.Skip(i * 4).Take(4).ToList());
}
}
}
}
}
return result;
}
/// <summary>
/// 获取提示的牌
/// </summary>
/// <param name="outCard">当前出的牌</param>
/// <param name="shoupai">玩家在手里的牌,没有出下去的牌</param>
/// <param name="maxShouPai">当前出牌人的手牌</param>
/// <param name="aaaIsZhaDan">3A是不是炸弹默认不是</param>
/// <param name="isOne">只要一种提示 true是 false不是</param>
/// <returns></returns>
public static List<List<TCardInfoPdkF>> GetTipCard(PlayOutCardPdkF outCard, TCardInfoPdkF[] shoupai, TCardInfoPdkF[] maxShouPai,
bool aaaIsZhaDan = false, bool isOne = false)
{
if (shoupai == null || shoupai.Length <= 0) return null;
List<List<TCardInfoPdkF>> result = new List<List<TCardInfoPdkF>>();
if (outCard.GameNum <= 0)
{
//如果是自己先出的话, 就从尾部一张一张提示过去
for (int i = shoupai.Length - 1; i >= 0; i--)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF>();
chu.Add(shoupai[i]);
result.Add(chu);
}
return result;
}
switch (outCard.Type)
{
//飞机带翅膀、炸弹,四带三、四带二
case CardType1.DanZhang:
var danzhangs = shoupai.Where(x => x.GameNum > outCard.GameNum);
if (danzhangs.Count() > 0)
{
foreach (var item in danzhangs)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF>();
chu.Add(item);
result.Add(chu);
}
}
break;
case CardType1.DuiZi:
result = PokerLogic.GetCountCard(outCard, shoupai, 2, true);
break;
case CardType1.SanDai2:
result = PokerLogic.GetCountCard(outCard, shoupai, 3, true);
break;
case CardType1.ShunZi:
result = PokerLogic.GetShunZi(outCard, shoupai);
break;
case CardType1.LianDui:
result = PokerLogic.GetLianCount(outCard, shoupai, 2, null);
break;
case CardType1.FeiJi:
result = PokerLogic.GetLianCount(outCard, shoupai, 3, maxShouPai);
break;
case CardType1.ZhaDan:
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards != null && cards.Count > 0 && cards[0].GameNum > outCard.GameNum)
{
result.Add(cards);
}
break;
}
if (result == null) result = new List<List<TCardInfoPdkF>>();
if (isOne && result != null && result.Count > 0)
{
//只要一种提示
}
else
{
if (aaaIsZhaDan)
{
var aaa = GetAAAZhaDan(shoupai);
if (aaa != null && aaa.Count >= 3)
{
result.Add(aaa);
}
}
if (outCard.Type != CardType1.ZhaDan)
{
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards != null && cards.Count > 0)
{
result.Add(cards);
}
}
}
return result;
}
/// <summary>
/// 判断是否是炸弹
/// </summary>
/// <param name="cards"></param>
/// <param name="aaaIsZhaDan"></param>
/// <param name="isCheckPaiCount"></param>
/// <returns></returns>
public static bool IsZhaDan(TCardInfoPdkF[] cards, bool aaaIsZhaDan, bool isCheckPaiCount = true)
{
if (cards == null || cards.Length < 3 || cards.Length > 4) return false;
if (aaaIsZhaDan && cards.Length == 3)
{
return Is3A(cards);
}
if (cards.Length == 4)
{
return IsZhaDan(cards, isCheckPaiCount);
}
return false;
}
/// <summary>
/// 检查玩家是否有比出的牌更大的牌
/// </summary>
/// <param name="outCard">玩家出的牌</param>
/// <param name="shouPai">自己的手牌-在手里的牌,并且是排序过的。</param>
/// <param name="maxShouPai">出牌人的手牌</param>
/// <param name="aaaIsZhaDan">3A是不是炸弹默认不是</param>
/// <returns>true有比玩家大的牌 false没有</returns>
public static bool CheckHaveBigger(PlayOutCardPdkF outCard, TCardInfoPdkF[] shouPai, TCardInfoPdkF[] maxShouPai,
bool aaaIsZhaDan = false)
{
if (shouPai == null || shouPai.Length <= 0) return false;
List<List<TCardInfoPdkF>> cs = null;
List<TCardInfoPdkF> cards = null;
switch (outCard.Type)
{
case CardType1.DanZhang:
if (shouPai.Where(x => x.GameNum > outCard.GameNum).Count() > 0)
{
return true;
}
break;
case CardType1.DuiZi:
cs = PokerLogic.GetCountCard(outCard, shouPai, 2, true);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.SanDai2:
cs = PokerLogic.GetCountCard(outCard, shouPai, 3, true);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.ShunZi:
cs = PokerLogic.GetShunZi(outCard, shouPai);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.LianDui:
cs = PokerLogic.GetLianCount(outCard, shouPai, 2, null);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.FeiJi:
cs = PokerLogic.GetLianCount(outCard, shouPai, 3, maxShouPai);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.ZhaDan:
var b = PokerLogic.GetPlayZhaDan(shouPai, out cards);
if (!b) return false;
foreach (var item in cards)
{
if (item.GameNum > outCard.GameNum) return true;
}
break;
}
if (aaaIsZhaDan)
{
var aaa = GetAAAZhaDan(shouPai);
if (aaa != null && aaa.Count >= 3)
{
return true;
}
}
if (outCard.Type != CardType1.ZhaDan)
{
return PokerLogic.GetPlayZhaDan(shouPai, out cards);
}
return false;
}
/// <summary>
/// 通过选中的牌返回出下去牌的类型 否则选中的牌就不能出下去
/// 一般客户端用
/// </summary>
/// <param name="selectCards">选中的牌</param>
/// <param name="shouPai">玩家手牌,不包含已经出下去的牌</param>
/// <param name="wangfa">规则玩法</param>
/// <param name="paycard">返回出牌内容</param>
/// <returns>true可以出牌 false不能出牌</returns>
public static bool GetOutCard(TCardInfoPdkF[] selectCards, TCardInfoPdkF[] shouPai, PdkRule wangfa,
out PlayOutCardPdkF paycard)
{
paycard = new PlayOutCardPdkF();
if (selectCards == null || selectCards.Length <= 0 || shouPai == null || shouPai.Length <= 0) return false;
var chaCard = shouPai.Except(selectCards); //获取差集如果个数大于0说明牌的张数是够的如果是0说明牌不够
PokerLogic.SortCardByGameNum(ref selectCards);
var bugou = chaCard.Count() <= 0;
byte gameNum = 0;
if (selectCards.Length == 1)
{
//单张可以出
paycard.Ids = new byte[] { selectCards[0].ID };
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.DanZhang;
return true;
}
else if (selectCards.Length == 2)
{
//对子
if (PokerLogic.IsDuiZi(selectCards))
{
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.DuiZi;
return true;
}
}
else if (selectCards.Length == 3)
{
if (wangfa.AAAIsZhaDan && Is3A(selectCards)) //3A是炸弹
{
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.ZhaDan;
return true;
}
else
{
bool xt = selectCards[0].GameNum == selectCards[1].GameNum &&
selectCards[2].GameNum == selectCards[1].GameNum;
if (xt && bugou)
{
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.SanDai2;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
}
}
else
{
if (IsZhaDan(selectCards)) //炸弹
{
paycard.GameNum = selectCards[0].GameNum; //因为该值会根据大小排序
paycard.Type = CardType1.ZhaDan;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (wangfa.SiDai2 && IsSiDai2(selectCards, !bugou, out gameNum))
{
//四带二
paycard.GameNum = gameNum;
paycard.Type = CardType1.SiDai2;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (wangfa.SiDai3 && IsSiDai3(selectCards, !bugou, out gameNum))
{
//四带二
paycard.GameNum = gameNum;
paycard.Type = CardType1.SiDai3;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsShunzi(selectCards))
{
//顺子
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.ShunZi;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsLianDui(selectCards)) //连对
{
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.LianDui;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsSanDaiEr(selectCards, bugou, out gameNum)) //三带二、
{
paycard.GameNum = gameNum;
paycard.Type = CardType1.SanDai2;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsFeiJi(selectCards, bugou, true, out gameNum)) //飞机带翅膀
{
paycard.GameNum = gameNum;
paycard.Type = CardType1.FeiJi;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
}
return false;
}
/// <summary>
/// 是否是3张A
/// </summary>
/// <param name="cards"></param>
/// <returns>true是 false不是</returns>
static bool Is3A(TCardInfoPdkF[] cards)
{
if (cards == null || cards.Length != 3) return false;
return cards[0].GameNum == 14 && cards[1].GameNum == 14 && cards[2].GameNum == 14;
}
/// <summary>
/// 获取3A炸弹
/// </summary>
/// <param name="cards">玩家手里没有打下去的牌</param>
/// <returns></returns>
static List<TCardInfoPdkF> GetAAAZhaDan(TCardInfoPdkF[] cards)
{
if (cards == null || cards.Length < 3) return null;
List<TCardInfoPdkF> result = new List<TCardInfoPdkF>();
for (int i = 0; i < cards.Length; i++)
{
if (cards[i].GameNum == 14)
{
result.Add(cards[i]);
}
}
if (result.Count >= 3)
{
return result;
}
return null;
}
static bool IsSiDai3(TCardInfoPdkF[] selectCards, bool isPaiBuGou, out byte gameNum)
{
gameNum = 0;
if (selectCards == null || selectCards.Length < 5 || selectCards.Length > 7) return false;
if (isPaiBuGou && selectCards.Length != 7) return false;
var b = PokerLogic.GetPlayZhaDan(selectCards, out var cards);
if (!b) return b;
gameNum = cards[0].GameNum;
return true;
}
/// <summary>
/// 是否是四带二
/// </summary>
/// <param name="selectCards"></param>
/// <param name="isPaiBuGou">true牌够false牌不够</param>
/// <returns>true是 false不是</returns>
#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
static bool IsSiDai2(TCardInfoPdkF[] selectCards, bool isPaiBuGou, out byte gameNum)
#pragma warning restore CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
{
gameNum = 0;
if (selectCards == null || selectCards.Length < 5 || selectCards.Length > 6) return false;
if (isPaiBuGou && selectCards.Length != 6) return false;
var b = PokerLogic.GetPlayZhaDan(selectCards, out var cards);
if (!b) return b;
gameNum = cards[0].GameNum;
return true;
}
/// <summary>
/// 判断是否是炸弹
/// </summary>
/// <param name="selectCards"></param>
/// <param name="isCheckPaiCount">是否要校验牌的张数对不对</param>
/// <returns></returns>
static bool IsZhaDan(TCardInfoPdkF[] selectCards, bool isCheckPaiCount = true)
{
if (selectCards == null || selectCards.Length < 4) return false;
int gameNum = 0;
foreach (var item in selectCards)
{
if (gameNum == 0)
{
gameNum = item.GameNum;
continue;
}
if (gameNum != item.GameNum)
{
//炸弹的牌不是一样的牌
return false;
}
}
var b = PokerLogic.GetPlayZhaDan(selectCards, out var cards);
if (!b) return b;
if (isCheckPaiCount)
{
//校验返回的炸弹牌数量和传入的牌数量是不是一样多
return selectCards.Length == cards.Count;
}
return true;
}
/// <summary>
/// 判断是否有炸弹
/// </summary>
/// <param name="selectCards"></param>
/// <param name="aaaIsBomb">AAA是否是炸弹 true是 false不是</param>
/// <returns></returns>
public static bool IsHaveBomb(TCardInfoPdkF[] selectCards, bool aaaIsBomb)
{
if (selectCards == null || selectCards.Length < 3) return false;
if (!aaaIsBomb && selectCards.Length < 4) return false;
Dictionary<int, int> dic = new Dictionary<int, int>();
for (int i = 0; i < selectCards.Length; i++)
{
if (dic.ContainsKey(selectCards[i].GameNum))
{
dic[selectCards[i].GameNum]++;
}
else
{
dic[selectCards[i].GameNum] = 1;
}
}
foreach (var item in dic)
{
if (aaaIsBomb && item.Key == 14 && item.Value == 3) return true;
if (item.Value >= 4) return true;
}
return false;
}
}
}