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
This commit is contained in:
218
GameFix/Common/Card/Card.cs
Normal file
218
GameFix/Common/Card/Card.cs
Normal file
@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 一张牌
|
||||
/// </summary>
|
||||
public class Card
|
||||
{
|
||||
public int Id { get; }
|
||||
|
||||
public byte CardType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 逻辑值
|
||||
/// </summary>
|
||||
public byte Value { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 花色
|
||||
/// </summary>
|
||||
public byte Suit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序数
|
||||
/// </summary>
|
||||
public int SortNum { get;private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始逻辑值
|
||||
/// </summary>
|
||||
public byte OriginValue { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户数据
|
||||
/// </summary>
|
||||
public object UserData { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var suitStr = string.Empty;
|
||||
switch (Suit)
|
||||
{
|
||||
case DataCardConst.SuitSpade:
|
||||
suitStr = "黑";
|
||||
break;
|
||||
case DataCardConst.SuitHeart:
|
||||
suitStr = "红";
|
||||
break;
|
||||
case DataCardConst.SuitClub:
|
||||
suitStr = "梅";
|
||||
break;
|
||||
case DataCardConst.SuitDiamond:
|
||||
suitStr = "方";
|
||||
break;
|
||||
case DataCardConst.SuitJoker:
|
||||
return (Value == DataCardConst.JokerValues[0] ? "小王" : "大王");
|
||||
default:
|
||||
return $"CardErr[{Suit}_{Value}]";
|
||||
}
|
||||
|
||||
var vIndex = Array.IndexOf(DataCardConst.CardValues, Value);
|
||||
if (vIndex<0 || vIndex >= DataCardConst.CardValueText.Length)
|
||||
return $"CardErr[{Suit}_{Value}]";
|
||||
var valueStr = DataCardConst.CardValueText[vIndex];
|
||||
|
||||
return suitStr + valueStr;
|
||||
}
|
||||
|
||||
int? _hashCode = null;
|
||||
|
||||
public override int GetHashCode() =>
|
||||
_hashCode.HasValue ? _hashCode.Value : (_hashCode = Id << 16 | (byte)Suit << 8 | Value).Value;
|
||||
|
||||
public Card()
|
||||
{
|
||||
}
|
||||
|
||||
public Card(int id, byte suit, byte value)
|
||||
{
|
||||
this.Id = id;
|
||||
this.Suit = suit;
|
||||
this.Value = value;
|
||||
this.SortNum = Value * 10 + suit;
|
||||
}
|
||||
|
||||
public void SetSortNum(int num)
|
||||
{
|
||||
this.SortNum = num;
|
||||
}
|
||||
|
||||
public bool IsLz => CardType == DataCardConst.CardTypeLZ;
|
||||
|
||||
public bool IsReplace => OriginValue != 0;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含某个类型
|
||||
/// </summary>
|
||||
public bool IsCardType(byte cardType)
|
||||
{
|
||||
return (CardType & cardType) == cardType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 附加一个牌值类型
|
||||
/// </summary>
|
||||
public void AddOrRmCardType(byte cardType, bool isAdd = true)
|
||||
{
|
||||
if (isAdd)
|
||||
{
|
||||
CardType |= cardType;
|
||||
}
|
||||
else
|
||||
{
|
||||
CardType &= (byte)~cardType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 癞子可以替换任何牌
|
||||
/// </summary>
|
||||
public Card Replace(byte value)
|
||||
{
|
||||
if (CardType == DataCardConst.CardTypeLZ)
|
||||
{
|
||||
var newCard = this.Clone();
|
||||
newCard.OriginValue = Value;
|
||||
newCard.Value = value;
|
||||
newCard.SortNum = Value * 10 + Suit;
|
||||
return newCard;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 浅拷贝
|
||||
/// </summary>
|
||||
public Card Clone() => (Card)MemberwiseClone();
|
||||
}
|
||||
|
||||
public static class CardManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 逻辑数 转 显示数
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static byte LogicValue2UINum(byte value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 14:
|
||||
return 1;
|
||||
case 16:
|
||||
return 2;
|
||||
case 18:
|
||||
return 14;
|
||||
case 19:
|
||||
return 15;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte LogicValue2SoundNum(byte value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 14:
|
||||
return 14;
|
||||
case 16:
|
||||
return 15;
|
||||
case 18:
|
||||
return 16;
|
||||
case 19:
|
||||
return 17;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public static (byte, byte) GetSuitValueFromStr(string cardString)
|
||||
{
|
||||
var chars = cardString.Trim().ToCharArray();
|
||||
var pos = 0;
|
||||
if (char.IsNumber(chars[0])) {
|
||||
pos++;
|
||||
}
|
||||
byte suit = DataCardConst.SuitJoker;
|
||||
switch (chars[pos]) {
|
||||
case '小': return (DataCardConst.SuitJoker, 18);
|
||||
case '大': return (DataCardConst.SuitJoker, 19);
|
||||
case '黑': suit = DataCardConst.SuitSpade; break;
|
||||
case '梅': suit = DataCardConst.SuitClub; break;
|
||||
case '红': suit = DataCardConst.SuitHeart; break;
|
||||
case '方': suit = DataCardConst.SuitDiamond; break;
|
||||
default: throw new NotSupportedException($"不支持的花色:{chars[0]}");
|
||||
}
|
||||
pos++;
|
||||
var value = byte.MinValue;
|
||||
var str = new string(chars.Skip(pos).ToArray()).TrimStart('0').TrimEnd(' ');
|
||||
var index = Array.IndexOf(DataCardConst.CardValueText, str);
|
||||
if (index >= 0)
|
||||
{
|
||||
value = DataCardConst.CardValues[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
value = byte.Parse(str);
|
||||
}
|
||||
return (suit, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
219
GameFix/Common/Card/CardBaseGroup.cs
Normal file
219
GameFix/Common/Card/CardBaseGroup.cs
Normal file
@ -0,0 +1,219 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public abstract class CardBaseGroup
|
||||
{
|
||||
// key-牌值 value-牌组信息 (不含癞子)
|
||||
protected List<CardGroupList> mCardGroupList = new List<CardGroupList>(20); // 大王19 (按照牌值合并的牌组)
|
||||
// key-牌数量 value-这个数量对应的所有牌组 (不含癞子)
|
||||
protected Dictionary<int, List<CardGroupList>> mCardGroupDic;
|
||||
|
||||
protected List<Card> mCards; // 原始的牌数据
|
||||
protected List<Card> mLZCards; // 癞子牌
|
||||
protected List<Card> mNoLZCards;// 除去癞子的牌列表
|
||||
|
||||
internal IStyleComparer mStyleComparer;
|
||||
internal Deck mDeck;
|
||||
protected List<CardStyleBaseHelper> mCardStyleBaseHelpers = new List<CardStyleBaseHelper>();
|
||||
|
||||
public List<Card> SelfCards => mCards;
|
||||
public List<CardGroupList> SelfCardGroupList => mCardGroupList;
|
||||
public Dictionary<int, List<CardGroupList>> SelfCardGroupDic => mCardGroupDic;
|
||||
|
||||
public List<Card> Cards
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果是手牌对象
|
||||
if (this is CardHandGroup cardHandGroup)
|
||||
{
|
||||
// 并且有需要检测得牌,就取CheckCardGroup得牌
|
||||
if (cardHandGroup.CheckCardGroup?.mCards.Count > 0)
|
||||
return cardHandGroup.CheckCardGroup.mCards;
|
||||
}
|
||||
return mCards;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Card> LZCards
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果是手牌对象
|
||||
if (this is CardHandGroup cardHandGroup)
|
||||
{
|
||||
// 并且有需要检测得牌,就取CheckCardGroup得牌
|
||||
if (cardHandGroup.CheckCardGroup?.mLZCards.Count > 0)
|
||||
return cardHandGroup.CheckCardGroup.mLZCards;
|
||||
}
|
||||
return mLZCards;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Card> NoLZCards
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果是手牌对象
|
||||
if (this is CardHandGroup cardHandGroup)
|
||||
{
|
||||
// 并且有需要检测得牌,就取CheckCardGroup得牌
|
||||
if (cardHandGroup.CheckCardGroup?.mNoLZCards.Count > 0)
|
||||
return cardHandGroup.CheckCardGroup.mNoLZCards;
|
||||
}
|
||||
return mNoLZCards;
|
||||
}
|
||||
}
|
||||
|
||||
public List<CardGroupList> CardGroupList
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果是手牌对象
|
||||
if (this is CardHandGroup cardHandGroup)
|
||||
{
|
||||
// 并且有需要检测得牌,就取CheckCardGroup得牌
|
||||
if (cardHandGroup.CheckCardGroup?.mCardGroupList.Count > 0)
|
||||
return cardHandGroup.CheckCardGroup.mCardGroupList;
|
||||
}
|
||||
return mCardGroupList;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<int, List<CardGroupList>> CardGroupDic
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果是手牌对象
|
||||
if (this is CardHandGroup cardHandGroup)
|
||||
{
|
||||
// 并且有需要检测得牌,就取CheckCardGroup得牌
|
||||
if (cardHandGroup.CheckCardGroup?.mCardGroupDic.Count > 0)
|
||||
return cardHandGroup.CheckCardGroup.mCardGroupDic;
|
||||
}
|
||||
return mCardGroupDic;
|
||||
}
|
||||
}
|
||||
|
||||
protected CardBaseGroup(IEnumerable<Card> cards, Deck deck)
|
||||
{
|
||||
mDeck = deck;
|
||||
mCards = new List<Card>(cards);
|
||||
mCards.Sort(new CardDefaultComparer(true));
|
||||
mLZCards = new List<Card>(mCards.Count);
|
||||
mNoLZCards = new List<Card>(mCards.Count);
|
||||
InitPreData();
|
||||
}
|
||||
|
||||
void InitPreData()
|
||||
{
|
||||
mCardGroupList.Clear();
|
||||
mLZCards.Clear();
|
||||
mNoLZCards.Clear();
|
||||
for (int i = 0; i < mCardGroupList.Capacity; i++)
|
||||
{
|
||||
mCardGroupList.Add(new CardGroupList());
|
||||
}
|
||||
|
||||
for (int i = 0; i < mCards.Count; i++)
|
||||
{
|
||||
if (mCards[i].CardType == DataCardConst.CardTypeLZ)
|
||||
{
|
||||
mLZCards.Add(mCards[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
mCardGroupList[mCards[i].Value].Add(mCards[i]);
|
||||
mNoLZCards.Add(mCards[i]);
|
||||
}
|
||||
|
||||
mCardGroupDic = mCardGroupList
|
||||
.GroupBy(g=>g.Count)
|
||||
.Where(g=>g.Key != 0)
|
||||
.ToDictionary(g=>g.Key, g=>g.ToList());
|
||||
}
|
||||
|
||||
internal CardBaseGroup RegisterHelper(List<CardStyleBaseHelper> helpers)
|
||||
{
|
||||
mCardStyleBaseHelpers.AddRange(helpers);
|
||||
return this;
|
||||
}
|
||||
|
||||
internal CardBaseGroup RegisterStyleComparer(IStyleComparer comparer)
|
||||
{
|
||||
mStyleComparer = comparer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CardBaseGroup RemoveCards(IEnumerable<Card> cards)
|
||||
{
|
||||
mCards.RemoveAll(cards.Contains);
|
||||
InitPreData();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CardBaseGroup RemoveCards(IEnumerable<CardGroupList> cardGroups)
|
||||
{
|
||||
var cards = cardGroups.SelectMany(x => x).ToList();
|
||||
RemoveCards(cards);
|
||||
return this;
|
||||
}
|
||||
|
||||
public CardBaseGroup AddHelper(CardStyleBaseHelper helper)
|
||||
{
|
||||
mCardStyleBaseHelpers.Add(helper);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一种牌型的数量
|
||||
/// </summary>
|
||||
/// <returns>数量</returns>
|
||||
public int GetSingleCardStyleCount(int cardValue)
|
||||
{
|
||||
if (cardValue >= mCardGroupList.Capacity)
|
||||
return 0;
|
||||
return mCardGroupList[cardValue].Count;
|
||||
}
|
||||
|
||||
public CardGroupList GetAllJoker()
|
||||
{
|
||||
CardGroupList list = new CardGroupList();
|
||||
list.AddRange(mCardGroupList[DataCardConst.CardValueBigJoker]);
|
||||
list.AddRange(mCardGroupList[DataCardConst.CardValueSmallJoker]);
|
||||
return list;
|
||||
}
|
||||
|
||||
public bool HaveJoker()
|
||||
{
|
||||
return mCards.Any(x => DataCardConst.JokerValues.Contains(x.Value));
|
||||
}
|
||||
|
||||
public int GetJokerCount()
|
||||
{
|
||||
return mCards.Count(x => DataCardConst.JokerValues.Contains(x.Value));
|
||||
}
|
||||
|
||||
public bool IsAllJoker()
|
||||
{
|
||||
return CardFunc.IsAllJoker(mCards);
|
||||
}
|
||||
|
||||
public bool IsAllSuitSame()
|
||||
{
|
||||
return CardFunc.IsAllSuitSame(mCards);
|
||||
}
|
||||
|
||||
public bool IsAllValueSame()
|
||||
{
|
||||
return CardFunc.IsAllValueSame(mCards);
|
||||
}
|
||||
|
||||
protected CardStyleBaseHelper GetHelper(int cardStyle)
|
||||
{
|
||||
return mCardStyleBaseHelpers.Find(x => x.CardStyle == cardStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
111
GameFix/Common/Card/CardComparer.cs
Normal file
111
GameFix/Common/Card/CardComparer.cs
Normal file
@ -0,0 +1,111 @@
|
||||
using System.Collections.Generic;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
// 默认降序比较器
|
||||
public class CardDefaultComparer :IComparer<Card>
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否升序
|
||||
/// </summary>
|
||||
bool mIsAscending;
|
||||
public CardDefaultComparer(bool isAscending = false)
|
||||
{
|
||||
mIsAscending = isAscending;
|
||||
}
|
||||
|
||||
public int Compare(Card x, Card y)
|
||||
{
|
||||
if (x == null && y == null) return 0;
|
||||
if (x == null) return 1; // 空值放后面
|
||||
if (y == null) return -1;
|
||||
if (x.CardType == DataCardConst.CardTypeLZ && y.CardType != DataCardConst.CardTypeLZ) return -1;
|
||||
if (y.CardType == DataCardConst.CardTypeLZ && x.CardType != DataCardConst.CardTypeLZ) return 1;
|
||||
|
||||
return mIsAscending ? -y.SortNum.CompareTo(x.SortNum) : y.SortNum.CompareTo(x.SortNum);
|
||||
}
|
||||
}
|
||||
|
||||
public class CardStyleComparer : IComparer<Card>
|
||||
{
|
||||
private CardStyleInfo mCardStyleInfo;
|
||||
public CardStyleComparer(CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
mCardStyleInfo = cardStyleInfo;
|
||||
}
|
||||
|
||||
public int Compare(Card x, Card y)
|
||||
{
|
||||
if (x == null && y == null) return 0;
|
||||
if (x == null) return 1; // 空值放后面
|
||||
if (y == null) return -1;
|
||||
if (x.Value < mCardStyleInfo.CardValue && y.Value >= mCardStyleInfo.CardValue) return 1;
|
||||
if (x.Value >= mCardStyleInfo.CardValue && y.Value < mCardStyleInfo.CardValue) return 1;
|
||||
|
||||
return x.SortNum.CompareTo(y.SortNum);
|
||||
}
|
||||
}
|
||||
|
||||
public class CardIdComparer : IComparer<Card>
|
||||
{
|
||||
public int Compare(Card x, Card y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return 0;
|
||||
if (y is null) return 1;
|
||||
if (x is null) return -1;
|
||||
return x.Id.CompareTo(y.Id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 相同牌值放一起
|
||||
/// </summary>
|
||||
public class CardColorSuitComparer : IComparer<Card>
|
||||
{
|
||||
private List<int> mColorSuitList = new List<int>()
|
||||
{ DataCardConst.SuitSpade, DataCardConst.SuitClub, DataCardConst.SuitHeart, DataCardConst.SuitDiamond };
|
||||
|
||||
public int Compare(Card x, Card y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return 0;
|
||||
if (y is null) return 1;
|
||||
if (x is null) return -1;
|
||||
|
||||
// 先按牌值排序(降序)
|
||||
int result = y.Value.CompareTo(x.Value);
|
||||
if (result != 0) return result;
|
||||
|
||||
// 相同牌值按花色排序
|
||||
int xIndex = mColorSuitList.IndexOf(x.Suit);
|
||||
int yIndex = mColorSuitList.IndexOf(y.Suit);
|
||||
if (xIndex == -1) xIndex = int.MaxValue;
|
||||
if (yIndex == -1) yIndex = int.MaxValue;
|
||||
|
||||
result = xIndex.CompareTo(yIndex);
|
||||
return result != 0 ? result : y.SortNum.CompareTo(x.SortNum);
|
||||
}
|
||||
}
|
||||
|
||||
public class CardValueEqualityComparer : IEqualityComparer<Card>
|
||||
{
|
||||
public bool Equals(Card x, Card y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (x is null) return false;
|
||||
if (y is null) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.Value == y.Value && x.Suit == y.Suit;
|
||||
}
|
||||
|
||||
public int GetHashCode(Card obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = obj.Value.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ obj.Suit.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
168
GameFix/Common/Card/CardFunc.cs
Normal file
168
GameFix/Common/Card/CardFunc.cs
Normal file
@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public static class CardFunc
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取牌值分数 (5 10 K)
|
||||
/// </summary>
|
||||
public static int GetCard510KScore(List<Card> cards)
|
||||
{
|
||||
int score = 0;
|
||||
for (int i = 0; i < cards.Count; i++)
|
||||
{
|
||||
if (cards[i].Value == DataCardConst.CardValue5)
|
||||
score += 5;
|
||||
if (cards[i].Value == DataCardConst.CardValue10)
|
||||
score += 10;
|
||||
if (cards[i].Value == DataCardConst.CardValueK)
|
||||
score += 10;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取cards 中所有510k的集合
|
||||
/// </summary>
|
||||
public static List<List<Card>> Get510KList(List<Card> cards, int lessNumber)
|
||||
{
|
||||
var result = new List<List<Card>>();
|
||||
|
||||
var valueCardDict = cards.GroupBy(x => x.Value)
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
|
||||
valueCardDict.TryGetValue(DataCardConst.CardValue5, out var cards5);
|
||||
valueCardDict.TryGetValue(DataCardConst.CardValue10, out var cards10);
|
||||
valueCardDict.TryGetValue(DataCardConst.CardValueK, out var cardsK);
|
||||
|
||||
if (cards5?.Count >= lessNumber && cards10?.Count >= lessNumber && cardsK?.Count >= lessNumber)
|
||||
{
|
||||
var min = Math.Min(Math.Min(cards5.Count, cards10.Count), cardsK.Count);
|
||||
|
||||
for (int i = 0; i < min; i++)
|
||||
{
|
||||
var list = new List<Card>
|
||||
{
|
||||
cards5[i],
|
||||
cards10[i],
|
||||
cardsK[i]
|
||||
};
|
||||
result.Add(list);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int GetJokerCount(List<Card> cards)
|
||||
{
|
||||
return cards.Count(DataCardConst.IsJoker);
|
||||
}
|
||||
|
||||
public static bool IsAllJoker(List<Card> cards)
|
||||
{
|
||||
if (cards.Count == 0) return false;
|
||||
if (cards.Count == 1) return true;
|
||||
|
||||
for (int i = 1; i < cards.Count; i++)
|
||||
{
|
||||
if (!DataCardConst.IsJoker(cards[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最大得同色数量
|
||||
/// </summary>
|
||||
/// <param name="cards"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetMaxSameColorCount(List<Card> cards)
|
||||
{
|
||||
return cards.Select(x => GetSuitColorType(x.Suit))
|
||||
.GroupBy(x => x).Select(g => g.Count()).DefaultIfEmpty(0).Max();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最大同牌值数量
|
||||
/// </summary>
|
||||
public static int GetMaxSameValueCount(List<Card> cards)
|
||||
{
|
||||
return cards.Select(x => x.Value)
|
||||
.GroupBy(x => x).Select(g => g.Count()).DefaultIfEmpty(0).Max();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有颜色是否相同 (红色/黑色)
|
||||
/// </summary>
|
||||
public static bool IsAllColorSame(List<Card> cards)
|
||||
{
|
||||
if (cards.Count == 0) return false;
|
||||
if (cards.Count == 1) return true;
|
||||
|
||||
for (int i = 1; i < cards.Count; i++)
|
||||
{
|
||||
if (GetSuitColorType(cards[i].Suit) != GetSuitColorType(cards[i-1].Suit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int GetSuitColorType(int suit)
|
||||
{
|
||||
if (suit == DataCardConst.SuitSpade || suit == DataCardConst.SuitClub)
|
||||
return 1;
|
||||
if (suit == DataCardConst.SuitHeart || suit == DataCardConst.SuitDiamond)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有花色是否相同
|
||||
/// </summary>
|
||||
public static bool IsAllSuitSame(List<Card> cards)
|
||||
{
|
||||
if (cards.Count == 0) return false;
|
||||
if (cards.Count == 1) return true;
|
||||
|
||||
for (int i = 1; i < cards.Count; i++)
|
||||
{
|
||||
if (cards[i].Suit != cards[i-1].Suit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有牌值是否相同
|
||||
/// </summary>
|
||||
public static bool IsAllValueSame(List<Card> cards)
|
||||
{
|
||||
if (cards.Count == 0) return false;
|
||||
if (cards.Count == 1) return true;
|
||||
|
||||
for (int i = 1; i < cards.Count; i++)
|
||||
{
|
||||
if (cards[i].Value != cards[i-1].Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
219
GameFix/Common/Card/CardGroup.cs
Normal file
219
GameFix/Common/Card/CardGroup.cs
Normal file
@ -0,0 +1,219 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 手牌组相关逻辑
|
||||
/// </summary>
|
||||
public class CardGroup : CardBaseGroup
|
||||
{
|
||||
public CardGroup(IEnumerable<Card> cards, Deck deck) : base(cards, deck)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拆解牌组
|
||||
/// </summary>
|
||||
public List<CardGroupList> Decompose()
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var cardGroup = mDeck.CreateCardGroup(mCards);
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
var styleCards = helper.GetAllStyleCards(cardGroup, false);
|
||||
ret.AddRange(styleCards);
|
||||
cardGroup.RemoveCards(styleCards);
|
||||
}
|
||||
|
||||
if (cardGroup.mCards.Count > 0)
|
||||
{ // 还有未知牌型没有拆解完? (理论不存在)
|
||||
ret.Add(new CardGroupList(cardGroup.mCards));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取吃牌提示
|
||||
/// </summary>
|
||||
public List<CardGroupList> GetEatTip(CardStyleInfo targetStyle)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
if (targetStyle == null)
|
||||
{
|
||||
// 没有提供对方牌型,先判断自己手牌是否符合一种牌型可以一次性出完
|
||||
var styleInfo = GetCardStyleInfo();
|
||||
bool isCanOutImmediate = false;
|
||||
if (styleInfo.CardStyle != DataCardConst.CardStyle0)
|
||||
{
|
||||
var cardGroupList = new CardGroupList(mCards);
|
||||
cardGroupList.CardStyleInfo = styleInfo;
|
||||
ret.Add(cardGroupList);
|
||||
isCanOutImmediate = true;
|
||||
}
|
||||
|
||||
if (!isCanOutImmediate)
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroup(this, null));
|
||||
if (ret.Count > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (mStyleComparer.Greater(helper.CardStyle, targetStyle.CardStyle))
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroup(this, targetStyle));
|
||||
}
|
||||
}
|
||||
|
||||
// 没找到再尝试有用癞子去匹配
|
||||
if (ret.Count == 0 && mLZCards.Count > 0)
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (mStyleComparer.Greater(helper.CardStyle, targetStyle.CardStyle))
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroupWithLZ(this, targetStyle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 牌类型赋值
|
||||
foreach (var cardList in ret)
|
||||
{
|
||||
if (cardList.CardStyleInfo != null) continue;
|
||||
var group = mDeck.CreateCardGroup(cardList);
|
||||
cardList.CardStyleInfo = group.GetCardStyleInfo();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<CardGroupList> GetShunTip(CardStyleInfo targetStyle, byte[] tipHelpers)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
for (int i = 0; i < tipHelpers.Length; i++)
|
||||
{
|
||||
var helper = GetHelper(tipHelpers[i]);
|
||||
var tipCardList = helper?.GetAllEatTipGroup(this, targetStyle);
|
||||
if (tipCardList != null && tipCardList.Count > 0)
|
||||
{
|
||||
ret.AddRange(tipCardList.OrderByDescending(x=>x.Count));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<CardGroupList> GetEatTip(int styleId)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var helper = GetHelper(styleId);
|
||||
if (helper != null)
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroup(this, null));
|
||||
|
||||
if (ret.Count == 0 && mLZCards.Count > 0)
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroupWithLZ(this, null));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前牌组得牌型
|
||||
/// </summary>
|
||||
public CardStyleInfo GetCardStyleInfo()
|
||||
{
|
||||
if (this.mLZCards.Count > 0)
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CheckStyleWithLZ(this, out var chekStyleInfo))
|
||||
{
|
||||
return chekStyleInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CheckStyleNormal(this, out var chekStyleInfo))
|
||||
{
|
||||
return chekStyleInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
CardStyleInfo cardStyleInfo = new CardStyleInfo();
|
||||
cardStyleInfo.CardStyle = DataCardConst.CardStyle0;
|
||||
return cardStyleInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前牌组得所有符合条件牌型
|
||||
/// </summary>
|
||||
public List<CardStyleInfo> GetCardStyleInfos()
|
||||
{
|
||||
List<CardStyleInfo> cardStyleInfos = new List<CardStyleInfo>();
|
||||
if (this.mLZCards.Count > 0)
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CheckStyleWithLZ(this, out var chekStyleInfo))
|
||||
{
|
||||
cardStyleInfos.Add(chekStyleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CheckStyleNormal(this, out var chekStyleInfo))
|
||||
{
|
||||
cardStyleInfos.Add(chekStyleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return cardStyleInfos;
|
||||
}
|
||||
|
||||
public bool CheckCardStyleInfoValidate(CardStyleInfo cardStyleInfo, out CardStyleInfo chkStyleInfo)
|
||||
{
|
||||
chkStyleInfo = new CardStyleInfo();
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CardStyle == cardStyleInfo.CardStyle)
|
||||
{
|
||||
// 先检测是否符合普通牌型
|
||||
if (helper.CheckStyleNormal(this, out chkStyleInfo))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.mLZCards.Count > 0)
|
||||
{
|
||||
return helper.CheckStyleWithLZ(this, out chkStyleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
GameFix/Common/Card/CardGroupList.cs
Normal file
21
GameFix/Common/Card/CardGroupList.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 一个牌型的列表
|
||||
/// </summary>
|
||||
public class CardGroupList : List<Card>
|
||||
{
|
||||
public CardStyleInfo CardStyleInfo { get; set; }
|
||||
|
||||
public CardGroupList()
|
||||
{
|
||||
}
|
||||
|
||||
public CardGroupList(IEnumerable<Card> cards) : base(cards)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
219
GameFix/Common/Card/CardHandGroup.cs
Normal file
219
GameFix/Common/Card/CardHandGroup.cs
Normal file
@ -0,0 +1,219 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 手牌组
|
||||
/// 有些逻辑需要校验手牌,用这个组
|
||||
/// 目前不包含癞子逻辑得判断
|
||||
/// </summary>
|
||||
public class CardHandGroup : CardBaseGroup
|
||||
{
|
||||
public CardBaseGroup CheckCardGroup { get; private set;}
|
||||
|
||||
public CardHandGroup(IEnumerable<Card> cards, Deck deck) : base(cards, deck)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拆解部分牌组
|
||||
/// </summary>
|
||||
public List<CardGroupList> DecomposePart(List<int> styles)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var cardGroup = mDeck.CreateCardGroup(mCards);
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (!styles.Contains(helper.CardStyle)) continue;
|
||||
|
||||
var styleCards = helper.GetAllStyleCards(cardGroup, false);
|
||||
foreach (var cardList in styleCards)
|
||||
{
|
||||
if (cardList.CardStyleInfo == null)
|
||||
cardList.CardStyleInfo = GetCardStyleInfo(cardList);
|
||||
}
|
||||
ret.AddRange(styleCards);
|
||||
cardGroup.RemoveCards(styleCards);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拆解牌组
|
||||
/// </summary>
|
||||
public List<CardGroupList> Decompose()
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var cardGroup = mDeck.CreateCardGroup(mCards);
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
var styleCards = helper.GetAllStyleCards(cardGroup, false);
|
||||
foreach (var cardList in styleCards)
|
||||
{
|
||||
if (cardList.CardStyleInfo == null)
|
||||
cardList.CardStyleInfo = GetCardStyleInfo(cardList);
|
||||
}
|
||||
ret.AddRange(styleCards);
|
||||
cardGroup.RemoveCards(styleCards);
|
||||
}
|
||||
|
||||
if (cardGroup.Cards.Count > 0)
|
||||
{ // 还有未知牌型没有拆解完? (理论不存在)
|
||||
ret.Add(new CardGroupList(cardGroup.Cards));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<CardGroupList> GetShunTip(CardStyleInfo targetStyle, byte[] tipHelpers)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
for (int i = 0; i < tipHelpers.Length; i++)
|
||||
{
|
||||
var helper = GetHelper(tipHelpers[i]);
|
||||
var tipCardList = helper?.GetAllEatTipGroup(this, targetStyle);
|
||||
if (tipCardList != null && tipCardList.Count > 0)
|
||||
{
|
||||
ret.AddRange(tipCardList.OrderByDescending(x=>x.Count));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<CardGroupList> GetEatTip(int styleId)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var helper = GetHelper(styleId);
|
||||
if (helper != null)
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroup(this, null));
|
||||
|
||||
if (ret.Count == 0 && mLZCards.Count > 0)
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroupWithLZ(this, null));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取吃牌提示
|
||||
/// </summary>
|
||||
public List<CardGroupList> GetEatTip(CardStyleInfo targetStyle)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
if (targetStyle == null)
|
||||
{
|
||||
// 没有提供对方牌型,先判断自己手牌是否符合一种牌型可以一次性出完
|
||||
var styleInfo = GetCardStyleInfo(mCards);
|
||||
bool isCanOutImmediate = false;
|
||||
if (styleInfo.CardStyle != DataCardConst.CardStyle0)
|
||||
{
|
||||
var cardGroupList = new CardGroupList(mCards);
|
||||
cardGroupList.CardStyleInfo = styleInfo;
|
||||
ret.Add(cardGroupList);
|
||||
isCanOutImmediate = true;
|
||||
}
|
||||
|
||||
if (!isCanOutImmediate)
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroup(this, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (mStyleComparer.Greater(helper.CardStyle, targetStyle.CardStyle))
|
||||
{
|
||||
ret.AddRange(helper.GetAllEatTipGroup(this, targetStyle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 牌类型赋值
|
||||
var filterRet = new List<CardGroupList>();
|
||||
foreach (var cardList in ret)
|
||||
{
|
||||
if (cardList.Count == 0) continue;
|
||||
if (cardList.CardStyleInfo == null)
|
||||
cardList.CardStyleInfo = GetCardStyleInfo(cardList);
|
||||
if (mStyleComparer.Greater(cardList.CardStyleInfo, targetStyle))
|
||||
{
|
||||
filterRet.Add(cardList);
|
||||
}
|
||||
}
|
||||
|
||||
return filterRet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取cards符合条件牌型
|
||||
/// </summary>
|
||||
public CardStyleInfo GetCardStyleInfo(IEnumerable<Card> cards)
|
||||
{
|
||||
CheckCardGroup = mDeck.CreateCardGroup(cards);
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CheckStyleNormal(this, out var chekStyleInfo))
|
||||
{
|
||||
return chekStyleInfo;
|
||||
}
|
||||
}
|
||||
|
||||
CheckCardGroup = null;
|
||||
CardStyleInfo cardStyleInfo = new CardStyleInfo();
|
||||
cardStyleInfo.CardStyle = DataCardConst.CardStyle0;
|
||||
return cardStyleInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取cards符合条件牌型
|
||||
/// </summary>
|
||||
public List<CardStyleInfo> GetCardStyleInfos(IEnumerable<Card> cards)
|
||||
{
|
||||
CheckCardGroup = mDeck.CreateCardGroup(cards);
|
||||
List<CardStyleInfo> cardStyleInfos = new List<CardStyleInfo>();
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CheckStyleNormal(this, out var chekStyleInfo))
|
||||
{
|
||||
cardStyleInfos.Add(chekStyleInfo);
|
||||
}
|
||||
}
|
||||
CheckCardGroup = null;
|
||||
return cardStyleInfos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测cards牌型是否符合条件
|
||||
/// </summary>
|
||||
public bool CheckCardStyleInfoValidate(IEnumerable<Card> cards, CardStyleInfo cardStyleInfo, out CardStyleInfo chkStyleInfo)
|
||||
{
|
||||
chkStyleInfo = new CardStyleInfo();
|
||||
CheckCardGroup = mDeck.CreateCardGroup(cards);
|
||||
foreach (var helper in mCardStyleBaseHelpers)
|
||||
{
|
||||
if (helper.CardStyle == cardStyleInfo.CardStyle)
|
||||
{
|
||||
// 先检测是否符合普通牌型
|
||||
if (helper.CheckStyleNormal(this, out chkStyleInfo))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
75
GameFix/Common/Card/CardIdJsonConverter.cs
Normal file
75
GameFix/Common/Card/CardIdJsonConverter.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardIdJsonConverter : JsonConverter
|
||||
{
|
||||
ICardIdResolver mResolver;
|
||||
public CardIdJsonConverter(ICardIdResolver resolver)
|
||||
{
|
||||
mResolver = resolver;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is IList<Card> cards)
|
||||
{
|
||||
writer.WriteStartArray();
|
||||
foreach (var card in cards)
|
||||
{
|
||||
if (card != null)
|
||||
writer.WriteValue(card.Id + 1);
|
||||
else
|
||||
{
|
||||
writer.WriteValue(0);
|
||||
}
|
||||
}
|
||||
writer.WriteEndArray();;
|
||||
} else if (value is Card card)
|
||||
{
|
||||
writer.WriteValue(card.Id + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return null;
|
||||
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
List<Card> cards = new List<Card>();
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonToken.EndArray)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonToken.Integer)
|
||||
{
|
||||
int id = Convert.ToInt32(reader.Value); // 读取 ID 值
|
||||
cards.Add(mResolver.GetById(id - 1));
|
||||
}
|
||||
}
|
||||
|
||||
return cards;
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonToken.Integer)
|
||||
{
|
||||
int id = Convert.ToInt32(reader.Value); // 读取 ID 值
|
||||
return mResolver.GetById(id - 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(IList<Card>).IsAssignableFrom(objectType) || typeof(Card).IsAssignableFrom(objectType);
|
||||
}
|
||||
}
|
||||
}
|
||||
160
GameFix/Common/Card/CardListExtensions.cs
Normal file
160
GameFix/Common/Card/CardListExtensions.cs
Normal file
@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public static class CardListExtensions
|
||||
{
|
||||
public static void Sort(this List<Card> cards, CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
if (cardStyleInfo == null) return;
|
||||
if (cardStyleInfo.CardStyle == DataCardConst.CardStyle331
|
||||
|| cardStyleInfo.CardStyle == DataCardConst.CardStyle332
|
||||
|| cardStyleInfo.CardStyle == DataCardConst.CardStyle3311)
|
||||
{
|
||||
var sortCards = cards.GroupBy(c => c.Value)
|
||||
.OrderBy(x => x.Key).Select(g => g.ToList()).ToList();
|
||||
var tmpCards = new List<Card>();
|
||||
cards.Clear();
|
||||
for (int i = 0; i < sortCards.Count; i++)
|
||||
{
|
||||
if (sortCards[i].Count >= 3)
|
||||
{
|
||||
cards.AddRange(sortCards[i].GetRange(0, 3));
|
||||
sortCards[i].RemoveRange(0,3);
|
||||
}
|
||||
tmpCards.AddRange(sortCards[i]);
|
||||
}
|
||||
cards.AddRange(tmpCards);
|
||||
}
|
||||
else
|
||||
{
|
||||
cards.Sort(new CardStyleComparer(cardStyleInfo));
|
||||
}
|
||||
}
|
||||
|
||||
public static string PrintCards(this IEnumerable<Card> cards)
|
||||
{
|
||||
var str = string.Join(",", cards);
|
||||
return str;
|
||||
}
|
||||
|
||||
#if Server || UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 字符转成Card数组 (主要调试用)
|
||||
/// </summary>
|
||||
///
|
||||
public static List<Card> ToCardList(this string cardString, Deck deck) {
|
||||
var segment = cardString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var list = new List<Card>();
|
||||
foreach (var item in segment)
|
||||
{
|
||||
var (suit, value) = CardManager.GetSuitValueFromStr(item);
|
||||
var card = deck.GetCard(suit, value);
|
||||
if (card != null)
|
||||
list.Add(card);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void RandomList<T>(this List<T> list)
|
||||
{
|
||||
Random rd = new Random();
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
int idx = rd.Next(0, list.Count);
|
||||
if (idx != i)
|
||||
(list[i],list[idx]) = (list[idx], list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断元素是否都一致
|
||||
/// </summary>
|
||||
public static bool AllElementsSame<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
if (enumerable == null)
|
||||
throw new ArgumentNullException(nameof(enumerable));
|
||||
|
||||
// 如果集合为空,直接返回 true
|
||||
using (var enumerator = enumerable.GetEnumerator())
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
return true;
|
||||
|
||||
// 获取第一个元素作为参照
|
||||
T first = enumerator.Current;
|
||||
var comparer = EqualityComparer<T>.Default;
|
||||
// 遍历后续元素进行比较
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
if (!comparer.Equals(first, enumerator.Current))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 交换两个列表中的元素(按索引交换)
|
||||
/// </summary>
|
||||
/// <typeparam name="T">元素类型</typeparam>
|
||||
/// <param name="list1">第一个列表</param>
|
||||
/// <param name="list2">第二个列表</param>
|
||||
/// <param name="count">交换数量,不传则交换 min(list1.Count, list2.Count)</param>
|
||||
public static void Switch<T>(this List<T> list1, List<T> list2, int count = -1)
|
||||
{
|
||||
if (list1 == null || list2 == null) return;
|
||||
|
||||
if (count < 0)
|
||||
count = Math.Min(list1.Count, list2.Count);
|
||||
|
||||
for (int i = 0; i < count && i < list1.Count && i < list2.Count; i++)
|
||||
{
|
||||
(list1[i], list2[i]) = (list2[i], list1[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 交换两个列表中指定的元素
|
||||
/// </summary>
|
||||
/// <typeparam name="T">元素类型</typeparam>
|
||||
/// <param name="list1">第一个列表</param>
|
||||
/// <param name="list2">第二个列表</param>
|
||||
/// <param name="items1">要从list1交换出去的元素</param>
|
||||
/// <param name="items2">要从list2交换出去的元素(可选,不传则从list2前部取items1.Count个元素)</param>
|
||||
public static void Switch<T>(this List<T> list1, List<T> list2, List<T> items1, List<T> items2 = null)
|
||||
{
|
||||
if (list1 == null || list2 == null) return;
|
||||
if (items1 == null) return;
|
||||
|
||||
// 如果items2为空,从list2前部取与items1数量相同的元素
|
||||
if (items2 == null)
|
||||
{
|
||||
int count = Math.Min(items1.Count, list2.Count);
|
||||
items2 = list2.GetRange(0, count);
|
||||
}
|
||||
|
||||
// 从list1移除items1,添加items2
|
||||
foreach (var item in items1)
|
||||
{
|
||||
list1.Remove(item);
|
||||
}
|
||||
list1.AddRange(items2);
|
||||
|
||||
// 从list2移除items2,添加items1
|
||||
foreach (var item in items2)
|
||||
{
|
||||
list2.Remove(item);
|
||||
}
|
||||
list2.AddRange(items1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
38
GameFix/Common/Card/CardMessagePackFormatter.cs
Normal file
38
GameFix/Common/Card/CardMessagePackFormatter.cs
Normal file
@ -0,0 +1,38 @@
|
||||
#if Server
|
||||
using MessagePack;
|
||||
using MessagePack.Formatters;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardMessagePackFormatter : IMessagePackFormatter<Card>
|
||||
{
|
||||
ICardIdResolver mResolver;
|
||||
|
||||
public CardMessagePackFormatter(ICardIdResolver resolver)
|
||||
{
|
||||
mResolver = resolver;
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Card value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
writer.WriteInt32(value.Id);
|
||||
}
|
||||
|
||||
public Card Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return mResolver.GetById(reader.ReadInt32());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
202
GameFix/Common/Card/CardStyleBaseHelper.cs
Normal file
202
GameFix/Common/Card/CardStyleBaseHelper.cs
Normal file
@ -0,0 +1,202 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public abstract class CardStyleBaseHelper
|
||||
{
|
||||
public virtual int CardStyle => DataCardConst.CardStyle0;
|
||||
public virtual int CardCnt => 0;
|
||||
|
||||
protected readonly int MaxShunLogicNum = 14; // 顺子所能到达得最大值
|
||||
|
||||
// 检测普通牌型
|
||||
internal abstract bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo);
|
||||
|
||||
// 检测癞子牌型 (有癞子的检测方法)
|
||||
internal virtual bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
return CheckStyleNormal(group, out cardStyleInfo);
|
||||
}
|
||||
|
||||
// 获取group中所有符合牌型的组合
|
||||
internal abstract List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo);
|
||||
|
||||
// 获取group中所有符合牌型的组合(带癞子的手牌)
|
||||
internal virtual List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
return GetAllEatTipGroup(group, eatStyleInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有符合条件得牌型
|
||||
/// </summary>
|
||||
internal virtual List<CardGroupList> GetAllStyleCards(CardBaseGroup group, bool isSplitCard) { return new List<CardGroupList>(); }
|
||||
|
||||
// 是否都相同
|
||||
protected bool IsAllSame(List<Card> cards)
|
||||
{
|
||||
if (cards.Count == 0) return false;
|
||||
if (cards.Count == 1) return true;
|
||||
|
||||
for (int i = 1; i < cards.Count; i++)
|
||||
{
|
||||
if (cards[i].Value != cards[i-1].Value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否连续
|
||||
/// </summary>
|
||||
protected bool IsContinuous(List<int> continuousValues)
|
||||
{
|
||||
if (continuousValues.Count == 1) return false;
|
||||
continuousValues.Sort();
|
||||
for (int i = 1; i < continuousValues.Count; i++)
|
||||
{
|
||||
if (continuousValues[i] - continuousValues[i-1] != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 是否连续
|
||||
protected bool IsContinuous(List<CardGroupList> cardValueCnt, int sameCnt, out List<int> shunValueList)
|
||||
{
|
||||
shunValueList = new List<int>();
|
||||
for (int i = 0; i < cardValueCnt.Count; i++)
|
||||
{
|
||||
//顺子中断
|
||||
if (cardValueCnt[i].Count < 1 && shunValueList.Count > 0)
|
||||
break;
|
||||
|
||||
if (cardValueCnt[i].Count > sameCnt)
|
||||
break;
|
||||
|
||||
if (cardValueCnt[i].Count == sameCnt)
|
||||
{
|
||||
shunValueList.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
return shunValueList.Count > 0;
|
||||
}
|
||||
|
||||
// 是否最大的连续
|
||||
protected bool IsMaxContinuous(List<CardGroupList> cardValueCnt, int sameCnt, out List<int> shunValueList)
|
||||
{
|
||||
List<int> maxShunValueList = new List<int>();
|
||||
shunValueList = new List<int>();
|
||||
for (int i = 0; i < cardValueCnt.Count; i++)
|
||||
{
|
||||
if (cardValueCnt[i].Count >= sameCnt)
|
||||
{
|
||||
shunValueList.Add(i);
|
||||
}
|
||||
else if(shunValueList.Count >= maxShunValueList.Count)
|
||||
{
|
||||
maxShunValueList.Clear();
|
||||
maxShunValueList.AddRange(shunValueList);
|
||||
shunValueList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (maxShunValueList.Count > shunValueList.Count)
|
||||
{
|
||||
shunValueList.Clear();
|
||||
shunValueList.AddRange(maxShunValueList);
|
||||
}
|
||||
|
||||
return shunValueList.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断带癞子的最大连顺
|
||||
/// </summary>
|
||||
protected bool IsMaxContinuousByLZ(List<CardGroupList> cardValueCnt, int sameCnt, int lzCount,
|
||||
out List<int> shunValueList, out List<int> lackValueList)
|
||||
{
|
||||
shunValueList = new List<int>();
|
||||
lackValueList = new List<int>(lzCount);
|
||||
List<int> maxShunCards = new List<int>();
|
||||
List<int> maxLackValues = new List<int>(lzCount);
|
||||
int tmpLzCount = lzCount;
|
||||
for (int i = 0; i <= MaxShunLogicNum; i++)
|
||||
{
|
||||
int count = cardValueCnt[i].Count;
|
||||
int needCnt = sameCnt - count;
|
||||
if (cardValueCnt[i].Count == sameCnt)
|
||||
{
|
||||
shunValueList.Add(i);
|
||||
} else if (needCnt <= tmpLzCount
|
||||
&& needCnt >= 0
|
||||
&& (shunValueList.Count > 0 || count > 0))
|
||||
{ // 用癞子补充
|
||||
tmpLzCount -= needCnt;
|
||||
shunValueList.Add(i);
|
||||
lackValueList.AddRange(Enumerable.Repeat(i, needCnt));
|
||||
}
|
||||
else
|
||||
{ // 中断(记录这一次得连顺)
|
||||
if (shunValueList.Count > maxShunCards.Count)
|
||||
{
|
||||
maxShunCards.Clear();
|
||||
maxShunCards.AddRange(shunValueList);
|
||||
maxLackValues.Clear();
|
||||
maxLackValues.AddRange(lackValueList);
|
||||
}
|
||||
// 重置癞子
|
||||
tmpLzCount = lzCount;
|
||||
shunValueList.Clear();
|
||||
lackValueList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (maxShunCards.Count > shunValueList.Count)
|
||||
{
|
||||
shunValueList.Clear();
|
||||
shunValueList.AddRange(maxShunCards);
|
||||
lackValueList.Clear();
|
||||
lackValueList.AddRange(maxLackValues);
|
||||
}
|
||||
|
||||
shunValueList.Sort();
|
||||
return shunValueList.Count > 0;
|
||||
}
|
||||
|
||||
// 相同牌组的值是否更大
|
||||
protected bool IsSameGroupGreater(CardGroupList group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
if (group.Count == 0) return false;
|
||||
|
||||
if (eatStyleInfo != null && CardStyle == eatStyleInfo.CardStyle)
|
||||
return group[0].Value > eatStyleInfo.CardValue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected bool IsJoker(CardGroupList group)
|
||||
{
|
||||
return IsContainJoker(group);
|
||||
}
|
||||
|
||||
protected bool IsContainJoker(List<Card> cards)
|
||||
{
|
||||
for (int i = 0; i < cards.Count(); i++)
|
||||
{
|
||||
if (DataCardConst.JokerValues.Contains(cards[i].Value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
GameFix/Common/Card/CardStyleHelper.cs
Normal file
31
GameFix/Common/Card/CardStyleHelper.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using GameMessage;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public static class CardStyleHelper
|
||||
{
|
||||
public static CardStyleInfo CreateCardStyleInfo(int cardStyle,List<Card> cards)
|
||||
{
|
||||
CardStyleInfo cardStyleInfo = new CardStyleInfo();
|
||||
cardStyleInfo.CardStyle = cardStyle;
|
||||
cardStyleInfo.CardValue = cards.First().Value;
|
||||
cardStyleInfo.CardCnt = cards.Count;
|
||||
return cardStyleInfo;
|
||||
}
|
||||
|
||||
public static CardStyleInfoExtend CreateCardStyleInfoExtend(int cardStyle, List<Card> cards)
|
||||
{
|
||||
CardStyleInfoExtend cardStyleInfo = new CardStyleInfoExtend();
|
||||
cardStyleInfo.CardStyle = cardStyle;
|
||||
cardStyleInfo.CardValue = cards.First().Value;
|
||||
cardStyleInfo.CardCnt = cards.Count;
|
||||
cardStyleInfo.SetCardId(cards.First().Id);
|
||||
return cardStyleInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
17
GameFix/Common/Card/CardStyleInfoExt.cs
Normal file
17
GameFix/Common/Card/CardStyleInfoExt.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public static class CardStyleInfoExt
|
||||
{
|
||||
public static string PrintStyleText(this CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
if (DataCardConst.CardStyleReadableText.TryGetValue(cardStyleInfo.CardStyle, out string cardStyleText))
|
||||
{
|
||||
return $"{cardStyleText}_{cardStyleInfo.CardValue}_{cardStyleInfo.CardCnt}";
|
||||
}
|
||||
|
||||
return $"{cardStyleInfo.CardStyle}_{cardStyleInfo.CardValue}_{cardStyleInfo.CardCnt}";
|
||||
}
|
||||
}
|
||||
}
|
||||
254
GameFix/Common/Card/DataCardConst.cs
Normal file
254
GameFix/Common/Card/DataCardConst.cs
Normal file
@ -0,0 +1,254 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class DataCardConst
|
||||
{
|
||||
public const byte CardTypeNormal = 1; // 普通牌
|
||||
public const byte CardTypeLZ = 2; // 癞子牌
|
||||
public const byte CardTypeMain = 1 << 2; // 主牌
|
||||
public const byte CardTypeSecond = 1 << 3; // 副牌
|
||||
|
||||
/// <summary>
|
||||
/// 黑桃
|
||||
/// </summary>
|
||||
public const byte SuitSpade = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 红桃
|
||||
/// </summary>
|
||||
public const byte SuitHeart = 2;
|
||||
|
||||
/// <summary>
|
||||
/// 梅花
|
||||
/// </summary>
|
||||
public const byte SuitClub = 3;
|
||||
|
||||
/// <summary>
|
||||
/// 方块
|
||||
/// </summary>
|
||||
public const byte SuitDiamond = 4;
|
||||
|
||||
/// <summary>
|
||||
/// 王
|
||||
/// </summary>
|
||||
public const byte SuitJoker = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 无牌型
|
||||
/// </summary>
|
||||
public const byte CardStyle0 = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 单张
|
||||
/// </summary>
|
||||
public const byte CardStyle1 = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 对子
|
||||
/// </summary>
|
||||
public const byte CardStyle2 = 2;
|
||||
|
||||
/// <summary>
|
||||
/// 三张
|
||||
/// </summary>
|
||||
public const byte CardStyle3 = 3;
|
||||
|
||||
/// <summary>
|
||||
/// 炸弹 (四张以上)
|
||||
/// </summary>
|
||||
public const byte CardStyleBomb = 4;
|
||||
|
||||
/// <summary>
|
||||
/// 火箭
|
||||
/// </summary>
|
||||
public const byte CardStyle5 = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 顺子
|
||||
/// </summary>
|
||||
public const byte CardStyle123 = 6;
|
||||
|
||||
/// <summary>
|
||||
/// 双顺 (3个起)
|
||||
/// </summary>
|
||||
public const byte CardStyle112233 = 7;
|
||||
|
||||
/// <summary>
|
||||
/// 三顺
|
||||
/// </summary>
|
||||
public const byte CardStyle111222 = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 三带一
|
||||
/// </summary>
|
||||
public const byte CardStyle31 = 9;
|
||||
|
||||
/// <summary>
|
||||
/// 三带对
|
||||
/// </summary>
|
||||
public const byte CardStyle32 = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 四带两张或者一对
|
||||
/// </summary>
|
||||
public const byte CardStyle41 = 11;
|
||||
|
||||
/// <summary>
|
||||
/// 四带两对
|
||||
/// </summary>
|
||||
public const byte CardStyle42 = 12;
|
||||
|
||||
/// <summary>
|
||||
/// 飞机带单张
|
||||
/// </summary>
|
||||
public const byte CardStyle331 = 13;
|
||||
|
||||
/// <summary>
|
||||
/// 飞机带对子
|
||||
/// </summary>
|
||||
public const byte CardStyle332 = 14;
|
||||
|
||||
/// <summary>
|
||||
/// 双顺 (2个起)
|
||||
/// </summary>
|
||||
public const byte CardStyle1122 = 15;
|
||||
|
||||
/// <summary>
|
||||
/// 510K
|
||||
/// </summary>
|
||||
public const byte CardStyle510K = 16;
|
||||
|
||||
/// <summary>
|
||||
/// 正510K
|
||||
/// </summary>
|
||||
public const byte CardStyle510KPlus = 17;
|
||||
|
||||
/// <summary>
|
||||
/// 三带两张
|
||||
/// </summary>
|
||||
public const byte CardStyle311 = 18;
|
||||
|
||||
/// <summary>
|
||||
/// 飞机带两张
|
||||
/// </summary>
|
||||
public const byte CardStyle3311 = 19;
|
||||
|
||||
/// <summary>
|
||||
/// 带王炸弹 (四张以上)
|
||||
/// </summary>
|
||||
public const byte CardStyleJokerBomb = 20;
|
||||
|
||||
/// <summary>
|
||||
/// 甩牌牌型
|
||||
/// </summary>
|
||||
public const byte CardStylePutCards = 21;
|
||||
|
||||
/// <summary>
|
||||
/// 三顺 (3个起)
|
||||
/// </summary>
|
||||
public const byte CardStyle111222333 = 22;
|
||||
|
||||
/// <summary>
|
||||
/// 全王炸弹
|
||||
/// </summary>
|
||||
public const byte CardStyleAllJokerBomb = 23;
|
||||
|
||||
/// <summary>
|
||||
/// 连炸 (3连以上)
|
||||
/// </summary>
|
||||
public const byte CardStyleBomb123 = 24;
|
||||
|
||||
/// <summary>
|
||||
/// 连炸 (2连以上)
|
||||
/// </summary>
|
||||
public const byte CardStyleBomb12 = 25;
|
||||
|
||||
/// <summary>
|
||||
/// 单牌炸弹
|
||||
/// </summary>
|
||||
public const byte CardStyleBomb1 = 26;
|
||||
|
||||
/// <summary>
|
||||
/// 对子炸弹
|
||||
/// </summary>
|
||||
public const byte CardStyleBomb2 = 27;
|
||||
|
||||
/// <summary>
|
||||
/// 多副510K
|
||||
/// </summary>
|
||||
public const byte CardStyle510KMult = 28;
|
||||
|
||||
|
||||
#region 牌值
|
||||
|
||||
public const byte CardValue2 = 16;
|
||||
public const byte CardValue3 = 3;
|
||||
public const byte CardValue5 = 5;
|
||||
public const byte CardValue10 = 10;
|
||||
public const byte CardValueK = 13;
|
||||
public const byte CardValueSmallJoker = 18;
|
||||
public const byte CardValueBigJoker = 19;
|
||||
|
||||
#endregion
|
||||
|
||||
// 花色
|
||||
public static readonly byte[] CardSuits = new byte[]
|
||||
{
|
||||
SuitSpade, SuitHeart, SuitClub, SuitDiamond,
|
||||
};
|
||||
|
||||
// A-K
|
||||
public static readonly byte[] CardValues = new byte[]
|
||||
{
|
||||
14, 16, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
|
||||
};
|
||||
|
||||
public static readonly string[] CardValueText = new string[]
|
||||
{
|
||||
"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
|
||||
};
|
||||
|
||||
// 小王 大王
|
||||
public static readonly byte[] JokerValues = new byte[]
|
||||
{
|
||||
18, 19
|
||||
};
|
||||
|
||||
public static readonly Dictionary<int, string> CardStyleReadableText = new Dictionary<int, string>()
|
||||
{
|
||||
{CardStyle0, "无牌型" },
|
||||
{CardStyle1, "单张" },
|
||||
{CardStyle2, "对子" },
|
||||
{CardStyle3, "三张" },
|
||||
{CardStyleBomb, "炸弹" },
|
||||
{CardStyleJokerBomb, "炸弹" },
|
||||
{CardStyle5, "火箭" },
|
||||
{CardStyle31, "三带一" },
|
||||
{CardStyle311, "三带两张" },
|
||||
{CardStyle32, "三带二" },
|
||||
{CardStyle41, "四带两张或者一对" },
|
||||
{CardStyle42, "四带两对" },
|
||||
{CardStyle331, "飞机带单张" },
|
||||
{CardStyle3311, "飞机带两张" },
|
||||
{CardStyle332, "飞机带对子" },
|
||||
{CardStyle123, "顺子" },
|
||||
{CardStyle112233, "双顺" },
|
||||
{CardStyle111222, "三顺" },
|
||||
{CardStyle1122, "双顺" },
|
||||
{CardStyle510K, "副510K" },
|
||||
{CardStyle510KPlus, "正510K" },
|
||||
{CardStylePutCards, "甩牌" },
|
||||
{CardStyleAllJokerBomb, "王炸" },
|
||||
{CardStyleBomb1, "单牌炸" },
|
||||
{CardStyleBomb2, "对子炸" },
|
||||
{CardStyle510KMult, "多510K"}
|
||||
};
|
||||
|
||||
public static bool IsJoker(Card card)
|
||||
{
|
||||
return JokerValues.Contains(card.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
145
GameFix/Common/Card/Deck.cs
Normal file
145
GameFix/Common/Card/Deck.cs
Normal file
@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 桌面牌组管理
|
||||
/// </summary>
|
||||
public class Deck : List<Card>, ICardIdResolver
|
||||
{
|
||||
public static readonly Random Random = new Random();
|
||||
|
||||
public new Card this[int index] => (Card)base[index];
|
||||
|
||||
public IStyleComparer StyleComparer => mBaseLogic.GetStyleComparer();
|
||||
|
||||
public DeckSerializer Serializer {get; private set;}
|
||||
|
||||
private DeckBaseLogic mBaseLogic;
|
||||
|
||||
internal Deck(DeckBaseLogic baseLogic) : base(baseLogic.Create())
|
||||
{
|
||||
mBaseLogic = baseLogic;
|
||||
Serializer = new DeckSerializer(this);
|
||||
}
|
||||
|
||||
public T GetDeckLogic<T>()
|
||||
{
|
||||
if (mBaseLogic is T logic)
|
||||
return logic;
|
||||
return default;
|
||||
}
|
||||
|
||||
public IEnumerable<Card> GetCards(Func<Card, bool> predicate)
|
||||
{
|
||||
return this.Where(predicate);
|
||||
}
|
||||
|
||||
public List<Card> GetCards(IEnumerable<int> ids)
|
||||
{
|
||||
List<Card> cards = new List<Card>();
|
||||
var enumerable = ids.ToList();
|
||||
for (int i = 0; i < enumerable.Count(); i++)
|
||||
{
|
||||
var card = GetById(enumerable.ElementAt(i));
|
||||
if (card != null)
|
||||
cards.Add(card);
|
||||
}
|
||||
|
||||
return cards;
|
||||
}
|
||||
|
||||
public Card GetCard(byte suit, int value)
|
||||
{
|
||||
return GetCards(p=>p.Suit == suit && p.Value == value).FirstOrDefault();
|
||||
}
|
||||
|
||||
public Card GetCard(byte suit, int value, Func<Card, bool> condition)
|
||||
{
|
||||
return GetCards(p=>p.Suit == suit && p.Value == value)
|
||||
.Where(condition).FirstOrDefault();
|
||||
}
|
||||
|
||||
public Card GetById(int id)
|
||||
{
|
||||
if (id < 0 || id >= Count) return null;
|
||||
return this[id];
|
||||
}
|
||||
|
||||
public void RevertAllCardType()
|
||||
{
|
||||
for (int i = 0; i < this.Count; i++)
|
||||
{
|
||||
this[i].CardType = DataCardConst.CardTypeNormal;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新牌类型
|
||||
/// </summary>
|
||||
public void RefreshCardType(byte cardType, List<Card> cards)
|
||||
{
|
||||
RevertAllCardType();
|
||||
for (int i = 0; i < cards.Count; i++)
|
||||
{
|
||||
int index = this.IndexOf(cards[i]);
|
||||
if (index >= 0)
|
||||
this[index].CardType = cardType;
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshCardType(byte cardType, List<int> ids)
|
||||
{
|
||||
RevertAllCardType();
|
||||
for (int i = 0; i < ids.Count; i++)
|
||||
{
|
||||
var card = GetById(ids[i]);
|
||||
if (card != null)
|
||||
card.CardType = cardType;
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshCardType(byte cardType, List<byte> values)
|
||||
{
|
||||
RevertAllCardType();
|
||||
for (int i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (values.Contains(this[i].Value))
|
||||
this[i].CardType = cardType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将牌列表封装成牌组,可用于牌型等判断
|
||||
/// </summary>
|
||||
public CardGroup CreateCardGroup(IEnumerable<Card> cards)
|
||||
{
|
||||
var cardGroup = new CardGroup(cards, this);
|
||||
var styleHelpers = mBaseLogic.GetAllStyleHelper(cardGroup);
|
||||
var styleComparer = mBaseLogic.GetStyleComparer();
|
||||
cardGroup.RegisterHelper(styleHelpers);
|
||||
cardGroup.RegisterStyleComparer(styleComparer);
|
||||
return cardGroup;
|
||||
}
|
||||
|
||||
public CardHandGroup CreateCardHandGroup(IEnumerable<Card> cards)
|
||||
{
|
||||
var cardGroup = new CardHandGroup(cards, this);
|
||||
var styleHelpers = mBaseLogic.GetAllStyleHelper(cardGroup);
|
||||
var styleComparer = mBaseLogic.GetStyleComparer();
|
||||
cardGroup.RegisterHelper(styleHelpers);
|
||||
cardGroup.RegisterStyleComparer(styleComparer);
|
||||
return cardGroup;
|
||||
}
|
||||
|
||||
public static Deck Create(DeckBaseLogic baseLogic)
|
||||
{
|
||||
var deck = new Deck(baseLogic);
|
||||
baseLogic.SetDeck(deck);
|
||||
baseLogic.OnInit();
|
||||
return deck;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
GameFix/Common/Card/DeckBaseLogic.cs
Normal file
28
GameFix/Common/Card/DeckBaseLogic.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public abstract class DeckBaseLogic
|
||||
{
|
||||
protected Deck mDeck;
|
||||
|
||||
public void SetDeck(Deck deck)
|
||||
{
|
||||
mDeck = deck;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化方法
|
||||
/// </summary>
|
||||
public virtual void OnInit() { }
|
||||
|
||||
// 创建牌组
|
||||
public abstract List<Card> Create();
|
||||
|
||||
// 获取牌型检测方法
|
||||
public abstract List<CardStyleBaseHelper> GetAllStyleHelper(CardBaseGroup cardGroup);
|
||||
|
||||
// 获取牌型比较器
|
||||
public abstract IStyleComparer GetStyleComparer();
|
||||
}
|
||||
}
|
||||
77
GameFix/Common/Card/DeckSerializer.cs
Normal file
77
GameFix/Common/Card/DeckSerializer.cs
Normal file
@ -0,0 +1,77 @@
|
||||
#if Server
|
||||
using System;
|
||||
using System.Text;
|
||||
using MessagePack;
|
||||
using MessagePack.Formatters;
|
||||
using MessagePack.Resolvers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class DeckSerializer
|
||||
{
|
||||
private Deck mDeck;
|
||||
private MessagePackSerializerOptions mOptions;
|
||||
private JsonSerializerSettings mMemSaveJsonSet;
|
||||
|
||||
public DeckSerializer(Deck deck)
|
||||
{
|
||||
mDeck = deck;
|
||||
// MessagePack
|
||||
var resolver = CompositeResolver.Create(
|
||||
new IMessagePackFormatter[]
|
||||
{
|
||||
new CardMessagePackFormatter(mDeck),
|
||||
},
|
||||
new IFormatterResolver[]
|
||||
{
|
||||
StandardResolver.Instance
|
||||
}
|
||||
);
|
||||
mOptions = MessagePackSerializerOptions.Standard
|
||||
.WithResolver(resolver);
|
||||
// .WithCompression(MessagePackCompression.Lz4BlockArray);
|
||||
|
||||
// Json
|
||||
mMemSaveJsonSet = new JsonSerializerSettings();
|
||||
mMemSaveJsonSet.DefaultValueHandling = DefaultValueHandling.Ignore;
|
||||
mMemSaveJsonSet.Converters = new JsonConverter[] { new CardIdJsonConverter(mDeck) };
|
||||
}
|
||||
|
||||
public byte[] Serialize<T>(T value, bool isJson = false)
|
||||
{
|
||||
if (isJson)
|
||||
{
|
||||
string jsonData = JsonHelper.SerializeObject(value, mMemSaveJsonSet);
|
||||
return Encoding.UTF8.GetBytes(jsonData);
|
||||
}
|
||||
|
||||
return MessagePackSerializer.Serialize(value, mOptions);
|
||||
}
|
||||
|
||||
public T Deserialize<T>(byte[] data, bool isJson = false)
|
||||
{
|
||||
if (isJson)
|
||||
{
|
||||
string jsondata = Encoding.UTF8.GetString(data);
|
||||
return JsonHelper.DeserializeObject<T>(jsondata, mMemSaveJsonSet);
|
||||
}
|
||||
|
||||
return MessagePackSerializer.Deserialize<T>(data, mOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class DeckSerializer
|
||||
{
|
||||
private Deck mDeck;
|
||||
public DeckSerializer(Deck deck)
|
||||
{
|
||||
mDeck = deck;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
7
GameFix/Common/Card/ICardIdResolver.cs
Normal file
7
GameFix/Common/Card/ICardIdResolver.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public interface ICardIdResolver
|
||||
{
|
||||
Card GetById(int id);
|
||||
}
|
||||
}
|
||||
12
GameFix/Common/Card/IStyleComparer.cs
Normal file
12
GameFix/Common/Card/IStyleComparer.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public interface IStyleComparer
|
||||
{
|
||||
// 比较两个牌型类 (大于等于)
|
||||
bool Greater(CardStyleInfo a, CardStyleInfo b);
|
||||
// 比较两个牌型id (大于等于)
|
||||
bool Greater(int a, int b);
|
||||
}
|
||||
}
|
||||
3
GameFix/Common/Card/StyleChecker/Helper.meta
Normal file
3
GameFix/Common/Card/StyleChecker/Helper.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cce19ec85cde409c8ba213a878216016
|
||||
timeCreated: 1741678598
|
||||
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 三顺 (3个起)
|
||||
/// </summary>
|
||||
public class CardStyle111222333Helper : CardStyle111222Helper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle111222333;
|
||||
public override int CardCnt => 9;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a48ff248eb6640c9817ac501c87c11cb
|
||||
timeCreated: 1748935610
|
||||
@ -0,0 +1,88 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle111222Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle111222;
|
||||
public override int CardCnt => 6;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % 3 == 0)
|
||||
{
|
||||
if (IsContinuous(group.CardGroupList, 3, out var shunCnt)
|
||||
&& shunCnt.Count * 3 == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % 3 == 0)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false;
|
||||
|
||||
if (IsMaxContinuousByLZ(group.CardGroupList, 3, group.LZCards.Count,
|
||||
out var shunValueList, out var lackValueList))
|
||||
{
|
||||
if (shunValueList.Count * 3 == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], shunValueList.Count * 3);
|
||||
cardStyleInfo.CardLackValues = lackValueList.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
|
||||
var minValue = eatStyleInfo != null ? eatStyleInfo.CardValue + 1 : 3;
|
||||
var continuousCnt = eatStyleInfo?.CardCnt ?? -1;
|
||||
List<Card> continuousList = new List<Card>();
|
||||
for (int i = minValue; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
continuousList.Clear();
|
||||
for (int j = 0; j < group.CardGroupList.Count; j++)
|
||||
{
|
||||
if (i + j >= group.CardGroupList.Count)
|
||||
break;
|
||||
if (group.CardGroupList[i + j].Count <= 2)
|
||||
break;
|
||||
|
||||
continuousList.AddRange(group.CardGroupList[i + j].GetRange(0, 3));
|
||||
|
||||
if (continuousList.Count >= CardCnt && continuousList.Count % 3 == 0)
|
||||
{
|
||||
if (continuousCnt == -1 || continuousCnt == continuousList.Count)
|
||||
{
|
||||
groupList.Add(new CardGroupList(continuousList));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{// 这里不处理直接找炸弹
|
||||
return new List<CardGroupList>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c80edd1dc98428c973c5a3a193aa748
|
||||
timeCreated: 1741684811
|
||||
123
GameFix/Common/Card/StyleChecker/Helper/CardStyle112233Helper.cs
Normal file
123
GameFix/Common/Card/StyleChecker/Helper/CardStyle112233Helper.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle112233Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle112233;
|
||||
public override int CardCnt => 6;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % 2 == 0)
|
||||
{
|
||||
if (IsContinuous(group.CardGroupList, 2, out var shunCnt)
|
||||
&& shunCnt.Count * 2 == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % 2 == 0)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false;
|
||||
|
||||
if (IsMaxContinuousByLZ(group.CardGroupList, 2, group.LZCards.Count,
|
||||
out var shunValueList, out var lackValueList))
|
||||
{
|
||||
if (shunValueList.Count * 2 == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], shunValueList.Count * 2);
|
||||
cardStyleInfo.CardLackValues = lackValueList.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
|
||||
var minValue = eatStyleInfo != null ? eatStyleInfo.CardValue + 1 : 3;
|
||||
var continuousCnt = eatStyleInfo?.CardCnt ?? -1;
|
||||
List<Card> continuousList = new List<Card>();
|
||||
for (int i = minValue; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
continuousList.Clear();
|
||||
for (int j = 0; j < group.CardGroupList.Count; j++)
|
||||
{
|
||||
if (i + j >= group.CardGroupList.Count)
|
||||
break;
|
||||
if (group.CardGroupList[i + j].Count <= 1)
|
||||
break;
|
||||
|
||||
continuousList.AddRange(group.CardGroupList[i + j].GetRange(0, 2));
|
||||
|
||||
if (continuousList.Count >= CardCnt && continuousList.Count % 2 == 0)
|
||||
{
|
||||
if (continuousCnt == -1 || continuousCnt == continuousList.Count)
|
||||
{
|
||||
groupList.Add(new CardGroupList(continuousList));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var minValue = eatStyleInfo != null ? eatStyleInfo.CardValue + 1 : 3;
|
||||
var continuousCnt = eatStyleInfo?.CardCnt ?? -1;
|
||||
var groupList = new List<CardGroupList>();
|
||||
List<Card> continuousList = new List<Card>();
|
||||
List<int> lackValueList = new List<int>();
|
||||
int needCnt = 0;
|
||||
for (int i = minValue; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
var count = group.CardGroupList[i].Count;
|
||||
if (count >= 2)
|
||||
{
|
||||
continuousList.AddRange(group.CardGroupList[i].GetRange(0, 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
needCnt += (2 - count);
|
||||
lackValueList.AddRange(Enumerable.Repeat(i, (2 - count)));
|
||||
}
|
||||
bool isBreak = group.CardGroupList[i].Count < 2 && needCnt > group.LZCards.Count;
|
||||
|
||||
if (continuousList.Count + needCnt >= CardCnt && needCnt <= group.LZCards.Count)
|
||||
{
|
||||
if (continuousCnt == -1 || continuousCnt == continuousList.Count + needCnt)
|
||||
{
|
||||
continuousList.AddRange(group.LZCards.GetRange(0, needCnt));
|
||||
groupList.Add(new CardGroupList(continuousList));
|
||||
break;
|
||||
}
|
||||
} else if (isBreak)
|
||||
{
|
||||
continuousList.Clear();
|
||||
needCnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a1287609db44ab2a55656eb154266d4
|
||||
timeCreated: 1741684811
|
||||
@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle1122Helper : CardStyle112233Helper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle1122;
|
||||
public override int CardCnt => 4;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57d250baed484c6ca90c588c01bc11f0
|
||||
timeCreated: 1741763235
|
||||
123
GameFix/Common/Card/StyleChecker/Helper/CardStyle123Helper.cs
Normal file
123
GameFix/Common/Card/StyleChecker/Helper/CardStyle123Helper.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle123Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle123;
|
||||
public override int CardCnt => 5;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt)
|
||||
{
|
||||
if (IsContinuous(group.CardGroupList, 1, out var shunCnt)
|
||||
&& shunCnt.Count == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false; // 直接组成炸弹
|
||||
|
||||
if (IsMaxContinuousByLZ(group.CardGroupList, 1, group.LZCards.Count,
|
||||
out var shunValueList, out var lackValueList))
|
||||
{
|
||||
if (shunValueList.Count == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], shunValueList.Count);
|
||||
cardStyleInfo.CardLackValues = lackValueList.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
|
||||
var minValue = eatStyleInfo != null ? eatStyleInfo.CardValue + 1 : 3;
|
||||
var continuousCnt = eatStyleInfo?.CardCnt ?? -1;
|
||||
List<Card> continuousList = new List<Card>();
|
||||
for (int i = minValue; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
continuousList.Clear();
|
||||
for (int j = 0; j < group.CardGroupList.Count; j++)
|
||||
{
|
||||
if (i + j >= group.CardGroupList.Count)
|
||||
break;
|
||||
if (group.CardGroupList[i + j].Count == 0)
|
||||
break;
|
||||
|
||||
continuousList.Add(group.CardGroupList[i + j].First());
|
||||
|
||||
if (continuousList.Count >= 5)
|
||||
{
|
||||
if (continuousCnt == -1 || continuousCnt == continuousList.Count)
|
||||
{
|
||||
groupList.Add(new CardGroupList(continuousList));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var minValue = eatStyleInfo != null ? eatStyleInfo.CardValue + 1 : 3;
|
||||
var continuousCnt = eatStyleInfo?.CardCnt ?? -1;
|
||||
var groupList = new List<CardGroupList>();
|
||||
List<Card> continuousList = new List<Card>();
|
||||
List<int> lackValues = new List<int>();
|
||||
int needCnt = 0;
|
||||
for (int i = minValue; i < MaxShunLogicNum; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count > 0)
|
||||
{
|
||||
continuousList.Add(group.CardGroupList[i].First());
|
||||
}
|
||||
else
|
||||
{
|
||||
needCnt++;
|
||||
lackValues.Add(i);
|
||||
}
|
||||
bool isBreak = group.CardGroupList[i].Count < 1 && needCnt > group.LZCards.Count;
|
||||
|
||||
if (continuousList.Count + needCnt >= CardCnt && needCnt <= group.LZCards.Count)
|
||||
{
|
||||
if (continuousCnt == -1 || continuousCnt == continuousList.Count + needCnt)
|
||||
{
|
||||
continuousList.AddRange(group.LZCards.GetRange(0, needCnt));
|
||||
groupList.Add(new CardGroupList(continuousList));
|
||||
break;
|
||||
}
|
||||
} else if (isBreak)
|
||||
{
|
||||
lackValues.Clear();
|
||||
continuousList.Clear();
|
||||
needCnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b1e3edc09a540b587d0f0b36cbf4f2d
|
||||
timeCreated: 1741684811
|
||||
79
GameFix/Common/Card/StyleChecker/Helper/CardStyle1Helper.cs
Normal file
79
GameFix/Common/Card/StyleChecker/Helper/CardStyle1Helper.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle1Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle1;
|
||||
public override int CardCnt => 1;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count != CardCnt) return false;
|
||||
// 单张癞子只能当普通牌
|
||||
if (group.LZCards.Count == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.LZCards);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
for (int i = 0; i < groupCnt; i++)
|
||||
{
|
||||
var cardGroup = group.CardGroupList[i];
|
||||
if (cardGroup.Count >= CardCnt && cardGroup.Count < 4 && IsSameGroupGreater(cardGroup, eatStyleInfo))
|
||||
{
|
||||
groupList.Add(new CardGroupList(cardGroup));
|
||||
}
|
||||
}
|
||||
|
||||
// 从单牌到三张排序,优先不拆组合牌
|
||||
if (groupList.Count > 0)
|
||||
{
|
||||
groupList = groupList.OrderBy(x=>x.Count).ToList();
|
||||
groupList.ForEach(x => x.RemoveRange(1, x.Count - 1));
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
// 在常规情况下没有找到单牌可以出 (说明只剩下癞子)
|
||||
// 单牌也只能按原始牌值出
|
||||
var groupList = new List<CardGroupList>(group.LZCards.Count);
|
||||
for (int i = 0; i < group.LZCards.Count; i++)
|
||||
{
|
||||
var lzCard = group.LZCards[i];
|
||||
if (lzCard.Value > eatStyleInfo.CardValue)
|
||||
{
|
||||
var lzCards = new CardGroupList();
|
||||
lzCards.Add(lzCard);
|
||||
groupList.Add(lzCards);
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a22e938dae646c8bf2d19ddf7fc9456
|
||||
timeCreated: 1741678606
|
||||
98
GameFix/Common/Card/StyleChecker/Helper/CardStyle2Helper.cs
Normal file
98
GameFix/Common/Card/StyleChecker/Helper/CardStyle2Helper.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle2Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle2;
|
||||
public override int CardCnt => 2;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt && IsAllSame(group.Cards))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count != CardCnt) return false;
|
||||
if (IsContainJoker(group.NoLZCards)) return false;
|
||||
if (group.LZCards.Count == group.Cards.Count && IsAllSame(group.LZCards))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.LZCards);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAllSame(group.NoLZCards))
|
||||
{
|
||||
var cardV = group.NoLZCards[0].Value;
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, cardV, CardCnt);
|
||||
cardStyleInfo.CardLackValues = Enumerable.Repeat((int)cardV, group.LZCards.Count).ToArray();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
for (int i = 0; i < groupCnt; i++)
|
||||
{
|
||||
var cardGroup = group.CardGroupList[i];
|
||||
if (cardGroup.Count >= CardCnt && cardGroup.Count < 4 && IsSameGroupGreater(cardGroup, eatStyleInfo))
|
||||
{
|
||||
groupList.Add(new CardGroupList(cardGroup));
|
||||
}
|
||||
}
|
||||
|
||||
// 从两张牌到三张排序,优先不拆组合牌
|
||||
if (groupList.Count > 0)
|
||||
{
|
||||
groupList = groupList.OrderBy(x=>x.Count).ToList();
|
||||
groupList.ForEach(x => x.RemoveRange(2, x.Count - 2));
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var cardGroupList = group.CardGroupDic.Where(kv => kv.Key >= 1).SelectMany(kv => kv.Value).ToList();
|
||||
var groupList = new List<CardGroupList>();
|
||||
foreach (var cardGroup in cardGroupList)
|
||||
{
|
||||
if (cardGroup.Count > 0
|
||||
&& cardGroup.First().Value > eatStyleInfo.CardValue
|
||||
&& !IsJoker(cardGroup))
|
||||
{
|
||||
List<Card> tmpList = new List<Card>();
|
||||
tmpList.Add(cardGroup.First());
|
||||
tmpList.Add(group.LZCards.First());
|
||||
groupList.Add(new CardGroupList(tmpList));
|
||||
}
|
||||
}
|
||||
|
||||
if (groupList.Count == 0
|
||||
&& group.LZCards.Count >= CardCnt
|
||||
&& IsAllSame(group.LZCards)
|
||||
&& group.LZCards.First().Value > eatStyleInfo.CardValue)
|
||||
{
|
||||
var cardList = group.LZCards.GetRange(0, CardCnt);
|
||||
groupList.Add(new CardGroupList(cardList));
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbbf72f272f140c2bf88d78ca167115b
|
||||
timeCreated: 1741678606
|
||||
@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle311Helper : CardStyle31Helper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle311;
|
||||
public override int CardCnt => 5;
|
||||
|
||||
// 4个相同得带一个是否能够出
|
||||
private bool _isSame4Enable = true;
|
||||
|
||||
public CardStyle311Helper(){}
|
||||
|
||||
public CardStyle311Helper(bool isSame4Enable){ _isSame4Enable = isSame4Enable; }
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count == 3 || (_isSame4Enable && group.CardGroupList[i].Count == 4))
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, i, group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f30f25213583439d8ee4b70ecc0b0a32
|
||||
timeCreated: 1741833322
|
||||
@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 3带2张 特殊牌型
|
||||
/// 最后一手牌可以带一张或者不带
|
||||
/// </summary>
|
||||
public class CardStyle311SpecialHelper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle311;
|
||||
public override int CardCnt => 5;
|
||||
|
||||
private readonly CardStyle311Helper _cardStyle311 = new();
|
||||
private readonly CardStyle31Helper _cardStyle31 = new();
|
||||
private readonly CardStyle3Helper _cardStyle3 = new();
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group is not CardHandGroup) return false;
|
||||
bool isStyle = false;
|
||||
if (group.SelfCards.Count == _cardStyle3.CardCnt)
|
||||
isStyle = _cardStyle3.CheckStyleNormal(group, out cardStyleInfo);
|
||||
else if (group.SelfCards.Count == _cardStyle31.CardCnt)
|
||||
isStyle = _cardStyle31.CheckStyleNormal(group, out cardStyleInfo);
|
||||
else
|
||||
isStyle = _cardStyle311.CheckStyleNormal(group, out cardStyleInfo);
|
||||
if (isStyle)
|
||||
cardStyleInfo.CardStyle = CardStyle;
|
||||
return isStyle;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
if (group is not CardHandGroup) return new List<CardGroupList>();
|
||||
if (group.SelfCards.Count == _cardStyle3.CardCnt)
|
||||
return _cardStyle3.GetAllEatTipGroup(group, eatStyleInfo);
|
||||
if (group.SelfCards.Count == _cardStyle31.CardCnt)
|
||||
return _cardStyle31.GetAllEatTipGroup(group, eatStyleInfo);
|
||||
var allEatTipGroup = _cardStyle311.GetAllEatTipGroup(group, eatStyleInfo);
|
||||
return allEatTipGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd25a8723adf4b9cb658aef67a327ea2
|
||||
timeCreated: 1779153231
|
||||
127
GameFix/Common/Card/StyleChecker/Helper/CardStyle31Helper.cs
Normal file
127
GameFix/Common/Card/StyleChecker/Helper/CardStyle31Helper.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle31Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle31;
|
||||
public override int CardCnt => 4;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count == 3)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, i, group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false; // 直接组成炸弹
|
||||
|
||||
int maxCV = 0;
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count + group.LZCards.Count == 3 && i>maxCV)
|
||||
{
|
||||
maxCV = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxCV != 0)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, maxCV, CardCnt);
|
||||
cardStyleInfo.CardLackValues = Enumerable.Repeat(maxCV, group.LZCards.Count).ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
var sortGroupList = group.CardGroupList.OrderBy((x) => x.Count).ToList();
|
||||
for (int i = 0; i < groupCnt; i++)
|
||||
{
|
||||
var cardGroup = group.CardGroupList[i];
|
||||
if (cardGroup.Count == 3 && IsSameGroupGreater(cardGroup, eatStyleInfo))
|
||||
{
|
||||
// 从其他组中找牌
|
||||
var newCardGroup = new CardGroupList(cardGroup);
|
||||
for (int j = 0; j < groupCnt; j++)
|
||||
{
|
||||
if (sortGroupList[j] != cardGroup && sortGroupList[j].Count >= 1)
|
||||
{
|
||||
int needCnt = CardCnt - newCardGroup.Count;
|
||||
needCnt = needCnt > sortGroupList[j].Count ? sortGroupList[j].Count : needCnt;
|
||||
newCardGroup.AddRange(sortGroupList[j].GetRange(0, needCnt));
|
||||
|
||||
if (newCardGroup.Count == CardCnt)
|
||||
{
|
||||
groupList.Add(newCardGroup);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var cardGroupList = group.CardGroupDic.Where(kv => kv.Key >= 1)
|
||||
.SelectMany(kv => kv.Value).OrderByDescending(x=>x.Count).ToList();
|
||||
var groupList = new List<CardGroupList>();
|
||||
foreach (var cardGroup in cardGroupList)
|
||||
{
|
||||
if (cardGroup.Count > 0
|
||||
&& cardGroup.First().Value > eatStyleInfo.CardValue
|
||||
&& !IsJoker(cardGroup))
|
||||
{
|
||||
var needCnt = CardCnt - cardGroup.Count - 1;
|
||||
if (needCnt <= group.LZCards.Count)
|
||||
{
|
||||
List<Card> tmpList = new List<Card>();
|
||||
tmpList.AddRange(cardGroup);
|
||||
tmpList.AddRange(group.LZCards.GetRange(0, needCnt));
|
||||
for (int i = cardGroupList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (cardGroupList[i] != cardGroup)
|
||||
{
|
||||
int wingNeedCnt = CardCnt - tmpList.Count;
|
||||
wingNeedCnt = wingNeedCnt > cardGroupList[i].Count ? cardGroupList[i].Count : wingNeedCnt;
|
||||
tmpList.AddRange(cardGroupList[i].GetRange(0, wingNeedCnt));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpList.Count == CardCnt)
|
||||
{
|
||||
groupList.Add(new CardGroupList(tmpList));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d6a6678f5c6491fb155a6900558fc47
|
||||
timeCreated: 1741684811
|
||||
156
GameFix/Common/Card/StyleChecker/Helper/CardStyle32Helper.cs
Normal file
156
GameFix/Common/Card/StyleChecker/Helper/CardStyle32Helper.cs
Normal file
@ -0,0 +1,156 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle32Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle32;
|
||||
public override int CardCnt => 5;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
int mainValue = 0, withValue = 0;
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count == 3)
|
||||
{
|
||||
mainValue = i;
|
||||
}
|
||||
|
||||
if (group.CardGroupList[i].Count == 2)
|
||||
{
|
||||
withValue = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainValue > 0 && withValue > 0)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, mainValue, group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false; // 直接组成炸弹
|
||||
|
||||
int lzCount = group.LZCards.Count;
|
||||
int threeCV = 0, pairCV = 0;
|
||||
List<int> lackValues = new List<int>(group.LZCards.Count);
|
||||
for (int i = group.CardGroupList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
int cardV = i;
|
||||
int count = group.CardGroupList[i].Count;
|
||||
if (count == 0) continue;
|
||||
int needCnt = 0;
|
||||
if ((3 - count) <= lzCount)
|
||||
{
|
||||
// 找到三张相同的牌
|
||||
needCnt = 3 - count;
|
||||
threeCV = cardV;
|
||||
}
|
||||
else if ((2 - count) <= lzCount)
|
||||
{
|
||||
// 找到两张相同的牌
|
||||
needCnt = 2 - count;
|
||||
pairCV = cardV;
|
||||
}
|
||||
lzCount -= needCnt;
|
||||
lackValues.AddRange(Enumerable.Repeat(cardV, needCnt));
|
||||
}
|
||||
|
||||
if (threeCV != 0 && pairCV != 0 && lzCount == 0)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, threeCV, CardCnt);
|
||||
cardStyleInfo.CardLackValues = lackValues.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
var sortGroupList = group.CardGroupList.OrderBy((x) => x.Count).ToList();
|
||||
for (int i = 0; i < groupCnt; i++)
|
||||
{
|
||||
var cardGroup = group.CardGroupList[i];
|
||||
if (cardGroup.Count == 3 && IsSameGroupGreater(cardGroup, eatStyleInfo))
|
||||
{
|
||||
// 从其他组中找一对
|
||||
for (int j = 0; j < groupCnt; j++)
|
||||
{
|
||||
if (sortGroupList[j] != cardGroup && sortGroupList[j].Count >= 2)
|
||||
{
|
||||
var newCardGroup = new CardGroupList(cardGroup);
|
||||
newCardGroup.AddRange(sortGroupList[j].GetRange(0, 2));
|
||||
groupList.Add(newCardGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var cardGroupList = group.CardGroupDic.Where(kv => kv.Key >= 1)
|
||||
.SelectMany(kv => kv.Value).OrderByDescending(x=>x.Count).ToList();
|
||||
var groupList = new List<CardGroupList>();
|
||||
foreach (var cardGroup in cardGroupList)
|
||||
{
|
||||
if (cardGroup.Count > 0
|
||||
&& cardGroup.First().Value > eatStyleInfo.CardValue
|
||||
&& !IsJoker(cardGroup))
|
||||
{
|
||||
var needCnt = CardCnt - cardGroup.Count - 2;
|
||||
if (needCnt <= group.LZCards.Count)
|
||||
{
|
||||
List<Card> tmpList = new List<Card>();
|
||||
tmpList.AddRange(cardGroup);
|
||||
|
||||
// 获取一个对子,不够用癞子补充
|
||||
for (int i = cardGroupList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (cardGroupList[i] != cardGroup && !IsJoker(cardGroupList[i]))
|
||||
{
|
||||
if (cardGroupList[i].Count >= 2)
|
||||
{
|
||||
tmpList.AddRange(cardGroupList[i].GetRange(0, 2));
|
||||
break;
|
||||
}
|
||||
else if (2 - cardGroupList[i].Count <= group.LZCards.Count - needCnt)
|
||||
{
|
||||
tmpList.AddRange(cardGroupList[i]);
|
||||
needCnt += (2 - cardGroupList[i].Count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmpList.AddRange(group.LZCards.GetRange(0, needCnt));
|
||||
if (tmpList.Count == CardCnt)
|
||||
{
|
||||
groupList.Add(new CardGroupList(tmpList));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0e6ce2f17c14aeeb059d36fd28bdb71
|
||||
timeCreated: 1741684811
|
||||
@ -0,0 +1,9 @@
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle3311Helper : CardStyle331Helper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle3311;
|
||||
public override int CardCnt => 10;
|
||||
protected override int GroupCnt => 5;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b880249d8307412788972a6c10632d88
|
||||
timeCreated: 1741844953
|
||||
@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 飞机 带 4张
|
||||
/// 最后一手牌可以少带或者不带
|
||||
/// </summary>
|
||||
public class CardStyle3311SpecialHelper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle3311;
|
||||
public override int CardCnt => 10;
|
||||
private readonly CardStyle3311Helper _cardStyle3311 = new();
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
// 手牌对象才检测
|
||||
if (group is not CardHandGroup) return false;
|
||||
|
||||
// 只要是飞机就可以带剩下得牌
|
||||
// 先过滤是否看有三个得牌
|
||||
var cardList = new List<CardGroupList>();
|
||||
foreach (var cardGroup in group.SelfCardGroupDic)
|
||||
{
|
||||
if (cardGroup.Key >= 3)
|
||||
cardList.AddRange(cardGroup.Value);
|
||||
}
|
||||
if (cardList.Count >= 2)
|
||||
{
|
||||
if (group.SelfCards.Count == group.Cards.Count)
|
||||
{
|
||||
// 剩下得牌都出完
|
||||
if (IsMaxContinuous(group.CardGroupList, 3, out var shunValueList)
|
||||
&& shunValueList.Count >= 2
|
||||
&& shunValueList.Count * 5 >= group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return _cardStyle3311.CheckStyleNormal(group, out cardStyleInfo);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
// 一定要检测手牌
|
||||
var ret = new List<CardGroupList>();
|
||||
if (group is not CardHandGroup handGroup) return ret;
|
||||
if (group.SelfCardGroupDic.TryGetValue(3, out var cardList)
|
||||
&& cardList.Count >= 2)
|
||||
{
|
||||
// 手上得牌是否可以成为飞机
|
||||
var cardStyle = handGroup.GetCardStyleInfo(group.SelfCards);
|
||||
if (cardStyle.CardStyle == CardStyle)
|
||||
{
|
||||
ret.Add(new CardGroupList(group.SelfCards));
|
||||
return ret;
|
||||
}
|
||||
return _cardStyle3311.GetAllEatTipGroup(group, eatStyleInfo);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1590d41252e54faa99b790979e1bbef5
|
||||
timeCreated: 1779156320
|
||||
105
GameFix/Common/Card/StyleChecker/Helper/CardStyle331Helper.cs
Normal file
105
GameFix/Common/Card/StyleChecker/Helper/CardStyle331Helper.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle331Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle331;
|
||||
public override int CardCnt => 8;
|
||||
|
||||
protected virtual int GroupCnt => 4;
|
||||
|
||||
// 特殊情况
|
||||
// 333444 666777888999101010JJJ (理论不存在)
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % GroupCnt == 0)
|
||||
{
|
||||
if (IsMaxContinuous(group.CardGroupList, 3, out var shunValueList)
|
||||
&& shunValueList.Count * GroupCnt == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % GroupCnt == 0)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false; // 直接组成炸弹
|
||||
|
||||
if (IsMaxContinuousByLZ(group.CardGroupList, 3, group.LZCards.Count,
|
||||
out var shunValueList, out var lackValueList))
|
||||
{
|
||||
if (shunValueList.Count * GroupCnt == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], shunValueList.Count * 4);
|
||||
cardStyleInfo.CardLackValues = lackValueList.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 333444555 888
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
|
||||
var planeHelper = new CardStyle111222Helper();
|
||||
// 先找到所有的飞机
|
||||
CardStyleInfo tmpEatStyleInfo = null;
|
||||
if (eatStyleInfo != null)
|
||||
tmpEatStyleInfo = new CardStyleInfo(
|
||||
eatStyleInfo.CardStyle,
|
||||
eatStyleInfo.CardValue,
|
||||
eatStyleInfo.CardCnt / GroupCnt * 3);
|
||||
var allPlaneList = planeHelper.GetAllEatTipGroup(group, tmpEatStyleInfo);
|
||||
List<Card> wingCards = new List<Card>();
|
||||
foreach (var plane in allPlaneList)
|
||||
{
|
||||
var singleCnt = (plane.Count / 3) * (GroupCnt - 3); // 需要单牌得数量
|
||||
|
||||
// 找到符合条件得所有翅膀
|
||||
var wingGroupList = group.CardGroupDic
|
||||
.Where(kv => kv.Key >= 1).SelectMany(kv=>kv.Value).ToList();
|
||||
wingCards.Clear();
|
||||
foreach (var wingGroup in wingGroupList)
|
||||
{
|
||||
if (wingGroup.Count >= 3 && plane.Intersect(wingGroup).Any()) // 翅膀不应该来源于飞机
|
||||
continue;
|
||||
|
||||
// 将翅膀加入列表中
|
||||
var needCnt = singleCnt - wingCards.Count;
|
||||
needCnt = needCnt > wingGroup.Count ? wingGroup.Count : needCnt;
|
||||
wingCards.AddRange(wingGroup.GetRange(0, needCnt));
|
||||
if (wingCards.Count == singleCnt)
|
||||
{
|
||||
plane.AddRange(wingCards);
|
||||
groupList.Add(new CardGroupList(plane));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{// 这里不处理直接找炸弹
|
||||
return new List<CardGroupList>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2b52aa3f44a4eb792d5f2e8c0137f79
|
||||
timeCreated: 1741684811
|
||||
152
GameFix/Common/Card/StyleChecker/Helper/CardStyle332Helper.cs
Normal file
152
GameFix/Common/Card/StyleChecker/Helper/CardStyle332Helper.cs
Normal file
@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle332Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle332;
|
||||
public override int CardCnt => 10;
|
||||
|
||||
// 特殊牌型
|
||||
// 888999 7777
|
||||
// 666777888999 33334444
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % 5 == 0)
|
||||
{
|
||||
if (IsMaxContinuous(group.CardGroupList, 3, out var shunValueList))
|
||||
{
|
||||
// 检测剩下的是否都是都是一对
|
||||
int doubleNum = 0;
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
var cnt = group.CardGroupList[i].Count;
|
||||
if (shunValueList.Contains(i))
|
||||
{ // 超出部分可以组成对子
|
||||
if (cnt <= 3) continue;
|
||||
if (cnt % 2 == 0)
|
||||
{ // 拆了这个组合
|
||||
doubleNum += cnt / 2;
|
||||
shunValueList.Remove(i);
|
||||
} else if ((cnt - 3) % 2 == 0)
|
||||
{
|
||||
doubleNum += (cnt - 3) / 2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (group.CardGroupList[i].Count % 2 == 0)
|
||||
doubleNum += group.CardGroupList[i].Count / 2;
|
||||
}
|
||||
|
||||
if (IsContinuous(shunValueList)
|
||||
&& doubleNum == shunValueList.Count
|
||||
&& shunValueList.Count * 5 == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && group.Cards.Count % 5 == 0)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false; // 直接组成炸弹
|
||||
|
||||
if (IsMaxContinuousByLZ(group.CardGroupList, 3, group.LZCards.Count,
|
||||
out var shunValueList, out var lackValueList))
|
||||
{
|
||||
// 判断剩下得牌是否都是一对
|
||||
int doubleNum = 0;
|
||||
int lzCount = group.LZCards.Count - lackValueList.Count;
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
int count = group.CardGroupList[i].Count;
|
||||
if (shunValueList.Contains(i) || count == 0) continue;
|
||||
if (count == 2 || ((2 - count) <= lzCount && (2 - count) > 0))
|
||||
{
|
||||
doubleNum++;
|
||||
lzCount -= (2 - count);
|
||||
shunValueList.AddRange(Enumerable.Repeat(i, (2 - count)));
|
||||
} else if (count == 4 || ((4 - count) <= lzCount && (4 - count) > 0))
|
||||
{
|
||||
doubleNum += 2;
|
||||
lzCount -= (4 - count);
|
||||
shunValueList.AddRange(Enumerable.Repeat(i, (4 - count)));
|
||||
}
|
||||
}
|
||||
|
||||
if (doubleNum == shunValueList.Count
|
||||
&& shunValueList.Count * 5 == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], shunValueList.Count * 5);
|
||||
cardStyleInfo.CardLackValues = lackValueList.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
|
||||
var planeHelper = new CardStyle111222Helper();
|
||||
// 先找到所有的飞机
|
||||
CardStyleInfo tmpEatStyleInfo = null;
|
||||
if (eatStyleInfo != null)
|
||||
tmpEatStyleInfo = new CardStyleInfo(
|
||||
eatStyleInfo.CardStyle,
|
||||
eatStyleInfo.CardValue,
|
||||
eatStyleInfo.CardCnt / 5 * 3);
|
||||
var allPlaneList= planeHelper.GetAllEatTipGroup(group, tmpEatStyleInfo);
|
||||
List<Card> wingCards = new List<Card>();
|
||||
foreach (var plane in allPlaneList)
|
||||
{
|
||||
var doubleCnt = plane.Count / 3; // 需要对子得数量
|
||||
|
||||
// 找到符合条件得所有翅膀
|
||||
var wingGroupList = group.CardGroupDic
|
||||
.Where(kv => kv.Key >= 2).SelectMany(kv=>kv.Value).ToList();
|
||||
wingCards.Clear();
|
||||
foreach (var wingGroup in wingGroupList)
|
||||
{
|
||||
if (wingGroup.Count >= 3 && plane.Intersect(wingGroup).Any()) // 翅膀不应该来源于飞机
|
||||
continue;
|
||||
|
||||
// 将翅膀加入列表中
|
||||
var needCnt = doubleCnt * 2 - wingCards.Count;
|
||||
needCnt = needCnt > wingGroup.Count ? wingGroup.Count : needCnt;
|
||||
needCnt = needCnt % 2 == 0 ? needCnt : needCnt - 1; // 不能为奇数
|
||||
wingCards.AddRange(wingGroup.GetRange(0, needCnt));
|
||||
if (wingCards.Count == doubleCnt * 2)
|
||||
{
|
||||
plane.AddRange(wingCards);
|
||||
groupList.Add(new CardGroupList(plane));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{// 这里不处理直接找炸弹
|
||||
return new List<CardGroupList>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eac176f1d3544cdb9160610fe6353bc1
|
||||
timeCreated: 1741684811
|
||||
96
GameFix/Common/Card/StyleChecker/Helper/CardStyle3Helper.cs
Normal file
96
GameFix/Common/Card/StyleChecker/Helper/CardStyle3Helper.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle3Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle3;
|
||||
public override int CardCnt => 3;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt && IsAllSame(group.Cards))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count != CardCnt) return false;
|
||||
if (IsContainJoker(group.NoLZCards)) return false;
|
||||
if (group.LZCards.Count == group.Cards.Count && IsAllSame(group.LZCards))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.LZCards);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAllSame(group.NoLZCards))
|
||||
{
|
||||
var cardV = group.NoLZCards[0].Value;
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, cardV, CardCnt);
|
||||
cardStyleInfo.CardLackValues = Enumerable.Repeat((int)cardV, group.LZCards.Count).ToArray();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
for (int i = 0; i < groupCnt; i++)
|
||||
{
|
||||
var cardGroup = group.CardGroupList[i];
|
||||
if (cardGroup.Count == CardCnt && IsSameGroupGreater(cardGroup, eatStyleInfo))
|
||||
{
|
||||
groupList.Add(new CardGroupList(cardGroup));
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var cardGroupList = group.CardGroupDic.Where(kv => kv.Key >= 1)
|
||||
.SelectMany(kv => kv.Value).OrderByDescending(x=>x.Count).ToList();
|
||||
var groupList = new List<CardGroupList>();
|
||||
foreach (var cardGroup in cardGroupList)
|
||||
{
|
||||
if (cardGroup.Count > 0
|
||||
&& cardGroup.First().Value > eatStyleInfo.CardValue
|
||||
&& !IsJoker(cardGroup))
|
||||
{
|
||||
var needCnt = CardCnt - cardGroup.Count;
|
||||
if (needCnt < group.LZCards.Count)
|
||||
{
|
||||
List<Card> tmpList = new List<Card>();
|
||||
tmpList.AddRange(cardGroup);
|
||||
tmpList.AddRange(group.LZCards.GetRange(0, needCnt));
|
||||
groupList.Add(new CardGroupList(tmpList));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groupList.Count == 0
|
||||
&& group.LZCards.Count >= CardCnt
|
||||
&& IsAllSame(group.LZCards)
|
||||
&& group.LZCards.First().Value > eatStyleInfo.CardValue)
|
||||
{
|
||||
var cardList = group.LZCards.GetRange(0, CardCnt);
|
||||
groupList.Add(new CardGroupList(cardList));
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5e550c003fb4dc2ad87fd3fd0be483f
|
||||
timeCreated: 1741684811
|
||||
105
GameFix/Common/Card/StyleChecker/Helper/CardStyle41Helper.cs
Normal file
105
GameFix/Common/Card/StyleChecker/Helper/CardStyle41Helper.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle41Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle41;
|
||||
public override int CardCnt => 6;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count == 4)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, i, group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false; // 直接组成炸弹
|
||||
|
||||
int lzCount = group.LZCards.Count;
|
||||
int fourCV = 0;
|
||||
List<int> lackValues = new List<int>(group.LZCards.Count);
|
||||
for (int i = group.CardGroupList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
int cardV = i;
|
||||
int count = group.CardGroupList[i].Count;
|
||||
int needCnt = 0;
|
||||
if ((4 - count) <= lzCount)
|
||||
{
|
||||
// 找到4张相同的牌
|
||||
needCnt = 4 - count;
|
||||
fourCV = cardV;
|
||||
}
|
||||
lzCount -= needCnt;
|
||||
lackValues.AddRange(Enumerable.Repeat(cardV, needCnt));
|
||||
}
|
||||
|
||||
if (lzCount > 0)
|
||||
{
|
||||
// 可能还会剩下癞子 (剩下得癞子当成普通牌)
|
||||
// 也可以处理成替代剩下得牌
|
||||
lzCount = 0;
|
||||
}
|
||||
|
||||
if (fourCV != 0 && lzCount == 0)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, fourCV, CardCnt);
|
||||
cardStyleInfo.CardLackValues = lackValues.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
if (!group.CardGroupDic.ContainsKey(4)) return groupList;
|
||||
//所有得四张牌组
|
||||
foreach (var fourCardGroup in group.CardGroupDic[4])
|
||||
{
|
||||
if (!IsSameGroupGreater(fourCardGroup, eatStyleInfo)) continue;
|
||||
|
||||
// 找两个单张 (不拆牌)
|
||||
if (group.CardGroupDic.ContainsKey(1) && group.CardGroupDic[1].Count >= 2)
|
||||
{
|
||||
var cardGroup42 = new CardGroupList(fourCardGroup);
|
||||
cardGroup42.AddRange(group.CardGroupDic[1][0]);
|
||||
cardGroup42.AddRange(group.CardGroupDic[1][1]);
|
||||
groupList.Add(cardGroup42);
|
||||
} else if (group.CardGroupDic.ContainsKey(2) && group.CardGroupDic[2].Count >= 1)
|
||||
{
|
||||
var cardGroup42 = new CardGroupList(fourCardGroup);
|
||||
cardGroup42.AddRange(group.CardGroupDic[2][0]);
|
||||
groupList.Add(cardGroup42);
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{// 这里不处理直接找炸弹
|
||||
return new List<CardGroupList>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7ace734247b43a3b13487dc54d7359d
|
||||
timeCreated: 1741684811
|
||||
111
GameFix/Common/Card/StyleChecker/Helper/CardStyle42Helper.cs
Normal file
111
GameFix/Common/Card/StyleChecker/Helper/CardStyle42Helper.cs
Normal file
@ -0,0 +1,111 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle42Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle42;
|
||||
public override int CardCnt => 8;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
int mainValue = 0, withValue = 0, withNum = 0;
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count == 4)
|
||||
{
|
||||
mainValue = i;
|
||||
}
|
||||
|
||||
if (group.CardGroupList[i].Count == 2)
|
||||
{
|
||||
withValue = i;
|
||||
withNum++;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainValue > 0 && withNum == 2)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, mainValue, group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
if (IsAllSame(group.NoLZCards)) return false; // 直接组成炸弹
|
||||
|
||||
int lzCount = group.LZCards.Count;
|
||||
int fourCV = 0;
|
||||
int pairCnt = 0;
|
||||
List<int> lackValues = new List<int>(group.LZCards.Count);
|
||||
for (int i = group.CardGroupList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
int cardV = i;
|
||||
int count = group.CardGroupList[i].Count;
|
||||
int needCnt = 0;
|
||||
if ((4 - count) <= lzCount)
|
||||
{
|
||||
// 找到4张相同的牌
|
||||
needCnt = 4 - count;
|
||||
fourCV = cardV;
|
||||
} else if ((2 - count) <= lzCount && (2 - count) >= 0)
|
||||
{
|
||||
// 两对
|
||||
needCnt = 2 - count;
|
||||
pairCnt++;
|
||||
}
|
||||
lzCount -= needCnt;
|
||||
lackValues.AddRange(Enumerable.Repeat(cardV, needCnt));
|
||||
}
|
||||
|
||||
if (fourCV != 0 && lzCount == 0 && pairCnt == 2)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, fourCV, CardCnt);
|
||||
cardStyleInfo.CardLackValues = lackValues.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
if (!group.CardGroupDic.ContainsKey(4)) return groupList;
|
||||
//所有得四张牌组
|
||||
foreach (var fourCardGroup in group.CardGroupDic[4])
|
||||
{
|
||||
if (!IsSameGroupGreater(fourCardGroup, eatStyleInfo)) continue;
|
||||
|
||||
// 找两个单张 (不拆牌)
|
||||
if (group.CardGroupDic.ContainsKey(2) && group.CardGroupDic[2].Count >= 2)
|
||||
{
|
||||
var cardGroup42 = new CardGroupList(fourCardGroup);
|
||||
cardGroup42.AddRange(group.CardGroupDic[2][0]);
|
||||
cardGroup42.AddRange(group.CardGroupDic[2][1]);
|
||||
groupList.Add(cardGroup42);
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{// 这里不处理直接找炸弹
|
||||
return new List<CardGroupList>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89f4eda5352c47999ae95ed5cfc018bc
|
||||
timeCreated: 1741684811
|
||||
@ -0,0 +1,82 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle510KHelper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle510K;
|
||||
public override int CardCnt => 3;
|
||||
|
||||
protected List<int> V_510K = new List<int>(){DataCardConst.CardValue5, DataCardConst.CardValue10, DataCardConst.CardValueK};
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt)
|
||||
{
|
||||
var values = group.Cards.Select(x=>(int)x.Value).ToList();
|
||||
values.Sort();
|
||||
if (V_510K.SequenceEqual(values))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt && group.LZCards.Count == 1)
|
||||
{ // 只有一个癞子,不然会被当成三个相同
|
||||
var values = group.Cards.Select(x=>(int)x.Value).ToList();
|
||||
var exceptV = values.Except(V_510K).ToList();
|
||||
if (exceptV.Count == 1)
|
||||
{ // 只有一个不同
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
cardStyleInfo.CardLackValues = new[] { exceptV.First() };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupList = new List<CardGroupList>(1);
|
||||
CardGroupList cardGroupList = new CardGroupList();
|
||||
for (int i = 0; i < V_510K.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[V_510K[i]].Count > 0)
|
||||
cardGroupList.Add(group.CardGroupList[V_510K[i]].First());
|
||||
}
|
||||
if (cardGroupList.Count == CardCnt)
|
||||
groupList.Add(cardGroupList);
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupList = new List<CardGroupList>(1);
|
||||
CardGroupList cardGroupList = new CardGroupList();
|
||||
for (int i = 0; i < V_510K.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[V_510K[i]].Count > 0)
|
||||
cardGroupList.Add(group.CardGroupList[V_510K[i]].First());
|
||||
}
|
||||
|
||||
if (cardGroupList.Count == 2)
|
||||
{
|
||||
cardGroupList.Add(group.LZCards.First());
|
||||
groupList.Add(cardGroupList);
|
||||
}
|
||||
return new List<CardGroupList>(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c9da57bc34c4c26a04ccdecd95fa88b
|
||||
timeCreated: 1741784659
|
||||
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 多副510K (可带 5,10,k单牌)
|
||||
/// </summary>
|
||||
public class CardStyle510KMultExtendHelper : CardStyle510KMultHelper
|
||||
{
|
||||
public CardStyle510KMultExtendHelper(int mult) : base(mult)
|
||||
{
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllStyleCards(CardBaseGroup group, bool isSplitCard)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var c510KList = CardFunc.Get510KList(group.SelfCards, _mult);
|
||||
if (c510KList.Count > 0)
|
||||
{
|
||||
// 剩下得 5 10 k也添加上
|
||||
var c510KGroup = new CardGroupList(c510KList.SelectMany(x => x));
|
||||
var c510KCards = group.SelfCards.Where(x => V_510K.Contains(x.Value)).ToList();
|
||||
c510KGroup.AddRange(c510KCards);
|
||||
ret.Add(c510KGroup);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt)
|
||||
{
|
||||
var c510KList = CardFunc.Get510KList(group.Cards, _mult);
|
||||
var c510KListLong = c510KList.SelectMany(x => x).ToList();
|
||||
var remainCardList = group.Cards.Where(x => !c510KListLong.Contains(x) && V_510K.Contains(x.Value)).ToList();
|
||||
|
||||
if (remainCardList.Count + c510KListLong.Count == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, 0, c510KList.Count);
|
||||
cardStyleInfo.CustomInt = c510KList.Count; // 510K的个数
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ea53d109ec74ae794ff0f676067516c
|
||||
timeCreated: 1779787226
|
||||
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 多副510K
|
||||
/// </summary>
|
||||
public class CardStyle510KMultHelper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle510KMult;
|
||||
public override int CardCnt { get; } = 0;
|
||||
protected int _mult;
|
||||
protected List<int> V_510K = new List<int>(){DataCardConst.CardValue5, DataCardConst.CardValue10, DataCardConst.CardValueK};
|
||||
|
||||
/// <summary>
|
||||
/// 几幅起算
|
||||
/// </summary>
|
||||
public CardStyle510KMultHelper(int mult)
|
||||
{
|
||||
CardCnt = mult * 3;
|
||||
_mult = mult;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt)
|
||||
{
|
||||
var c510KList = CardFunc.Get510KList(group.Cards, _mult);
|
||||
|
||||
if (c510KList.Count * 3 == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, 0, c510KList.Count);
|
||||
cardStyleInfo.CustomInt = c510KList.Count; // 510K的个数
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
return GetAllStyleCards(group, false);
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllStyleCards(CardBaseGroup group, bool isSplitCard)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var c510KList = CardFunc.Get510KList(group.SelfCards, _mult);
|
||||
if (c510KList.Count > 0)
|
||||
ret.Add(new CardGroupList(c510KList.SelectMany(x=>x)));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 871d6a388b274cd9acb178bdf5637f0d
|
||||
timeCreated: 1779076036
|
||||
@ -0,0 +1,78 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 正510K
|
||||
/// </summary>
|
||||
public class CardStyle510KPlusHelper : CardStyle510KHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle510KPlus;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
var isRight = base.CheckStyleNormal(group, out cardStyleInfo);
|
||||
if (isRight)
|
||||
return group.Cards.Select(x => x.Suit).AllElementsSame();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
var isRight = base.CheckStyleNormal(group, out cardStyleInfo);
|
||||
if (isRight)
|
||||
return group.Cards.Select(x => x.Suit).AllElementsSame();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{// 只提示一个
|
||||
var groupList = new List<CardGroupList>(1);
|
||||
List<Card> cards = new List<Card>();
|
||||
foreach (var v in V_510K)
|
||||
{
|
||||
if (group.CardGroupList[v].Count > 0)
|
||||
cards.AddRange(group.CardGroupList[v]);
|
||||
}
|
||||
// 按照花色分组
|
||||
var suitCardDict = cards.GroupBy(x => x.Suit)
|
||||
.ToDictionary(g => g.Key, g => g.Distinct(new CardValueEqualityComparer()).ToList());
|
||||
foreach (var suitCards in suitCardDict.Values)
|
||||
{
|
||||
if (suitCards.Count != CardCnt) continue;
|
||||
groupList.Add(new CardGroupList(suitCards));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupList = new List<CardGroupList>(1);
|
||||
List<Card> cards = new List<Card>();
|
||||
foreach (var v in V_510K)
|
||||
{
|
||||
if (group.CardGroupList[v].Count > 0)
|
||||
cards.AddRange(group.CardGroupList[v]);
|
||||
}
|
||||
// 按照花色分组
|
||||
var suitCardDict = cards.GroupBy(x => x.Suit)
|
||||
.ToDictionary(g => g.Key, g => g.Distinct().ToList());
|
||||
foreach (var suitCards in suitCardDict.Values)
|
||||
{
|
||||
if (suitCards.Count != 2) continue;
|
||||
var cardGroupList = new CardGroupList(suitCards);
|
||||
cardGroupList.Add(group.LZCards.First());
|
||||
groupList.Add(cardGroupList);
|
||||
break;
|
||||
}
|
||||
return new List<CardGroupList>(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec36b04d78bd4e08808ff6ecfa8fe62c
|
||||
timeCreated: 1741828989
|
||||
51
GameFix/Common/Card/StyleChecker/Helper/CardStyle5Helper.cs
Normal file
51
GameFix/Common/Card/StyleChecker/Helper/CardStyle5Helper.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public class CardStyle5Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyle5;
|
||||
public override int CardCnt => 2;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count == CardCnt
|
||||
&& group.Cards.Count(x=>DataCardConst.JokerValues.Contains(x.Value)) == CardCnt
|
||||
&& group.Cards[0].Value != group.Cards[1].Value)
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupList = new List<CardGroupList>(1);
|
||||
if (group.CardGroupList[18].Count>0 && group.CardGroupList[19].Count>0)
|
||||
{
|
||||
var cardGroup = new CardGroupList();
|
||||
cardGroup.AddRange(group.CardGroupList[18]);
|
||||
cardGroup.AddRange(group.CardGroupList[19]);
|
||||
groupList.Add(cardGroup);
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
return new List<CardGroupList>(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14e95f3c416848eab6ef7899c7b535f6
|
||||
timeCreated: 1741684811
|
||||
@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 全王炸弹
|
||||
/// </summary>
|
||||
public class CardStyleAllJokerBombHelper: CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyleAllJokerBomb;
|
||||
public override int CardCnt => mCardCnt;
|
||||
|
||||
private int mCardCnt = 4;
|
||||
|
||||
public CardStyleAllJokerBombHelper() { }
|
||||
|
||||
/// <summary>
|
||||
/// 构造
|
||||
/// </summary>
|
||||
/// <param name="cardCnt">几个王起算炸</param>
|
||||
public CardStyleAllJokerBombHelper(int cardCnt)
|
||||
{
|
||||
mCardCnt = cardCnt;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt)
|
||||
{
|
||||
var isOtherCards = group.Cards.Any(x=>!DataCardConst.JokerValues.Contains(x.Value));
|
||||
if (isOtherCards) return false;
|
||||
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
// 癞子不当王
|
||||
cardStyleInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllStyleCards(CardBaseGroup group, bool isSplitCard)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var jokerCards = group.SelfCards.Where(x=>DataCardConst.JokerValues.Contains(x.Value)).ToList();
|
||||
if (jokerCards.Count < CardCnt) return ret;
|
||||
CardGroupList cardGroupList = new CardGroupList();
|
||||
cardGroupList.AddRange(jokerCards);
|
||||
ret.Add(cardGroupList);
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
return GetAllStyleCards(group, false);
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
// 癞子不当王
|
||||
return new List<CardGroupList>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d6cb6966142468396f4d242cd41eab0
|
||||
timeCreated: 1748936998
|
||||
@ -0,0 +1,219 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 连炸 (3连以上)
|
||||
/// CardStyleInfo.CustomInt: 表示几个相同炸弹组成
|
||||
/// </summary>
|
||||
public class CardStyleBomb123Helper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyleBomb123;
|
||||
public override int CardCnt => 12;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt)
|
||||
{
|
||||
var keysCnt = group.CardGroupDic.Keys.Count;
|
||||
if (keysCnt != 1) return false;
|
||||
var bombSize = group.CardGroupDic.Keys.First(); // 单个炸弹的大小
|
||||
if (bombSize < 4) return false;
|
||||
|
||||
// 判断是否连续
|
||||
if (IsContinuous(group.CardGroupList, bombSize, out var shunCnt)
|
||||
&& shunCnt.Count * bombSize == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
cardStyleInfo.CustomInt = group.Cards.Count / bombSize;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count < CardCnt) return false;
|
||||
var lzCnt = group.LZCards.Count;
|
||||
var bombSize = group.CardGroupDic.Keys.Max(); // 最大的数量作为单个炸弹的大小
|
||||
if (bombSize < 4) lzCnt -= (bombSize - 4);
|
||||
if (lzCnt < 0) return false;
|
||||
|
||||
for (int i = 0; i < group.CardGroupDic.Keys.Count; i++)
|
||||
{
|
||||
var key = group.CardGroupDic.Keys.ElementAt(i);
|
||||
var vList = group.CardGroupDic[key];
|
||||
var diffSize = bombSize - key;
|
||||
lzCnt -= diffSize * vList.Count;
|
||||
|
||||
if (lzCnt < 0) return false;
|
||||
}
|
||||
|
||||
// 判断是否连续
|
||||
if (IsMaxContinuousByLZ(group.CardGroupList, bombSize, group.LZCards.Count,
|
||||
out var shunValueList, out var lackValueList)
|
||||
&& shunValueList.Count * bombSize == group.Cards.Count)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], shunValueList.Count * bombSize);
|
||||
cardStyleInfo.CardLackValues = lackValueList.ToArray();
|
||||
cardStyleInfo.CustomInt = group.Cards.Count / bombSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
|
||||
// 找最大的连炸
|
||||
List<Card> continuousList = new List<Card>();
|
||||
int minBombSize = Int32.MaxValue;
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
if (group.CardGroupList[i].Count >= 4)
|
||||
{
|
||||
minBombSize = Math.Min(minBombSize, group.CardGroupList[i].Count);
|
||||
continuousList.AddRange(group.CardGroupList[i]);
|
||||
} else if (continuousList.Count >= CardCnt)
|
||||
{
|
||||
// 把一些多余的牌删除
|
||||
var filterList = continuousList.GroupBy(c=>c.Value)
|
||||
.Select(g=>
|
||||
Tuple.Create(g.Key,g.ToList().GetRange(0, minBombSize)))
|
||||
.SelectMany(g=>g.Item2)
|
||||
.ToList();
|
||||
|
||||
// 判断是否属于连炸
|
||||
var targetGroup = group.mDeck.CreateCardGroup(filterList);
|
||||
if (targetGroup.GetCardStyleInfo().CardStyle == CardStyle)
|
||||
{
|
||||
groupList.Add(new CardGroupList(filterList));
|
||||
}
|
||||
|
||||
minBombSize = Int32.MaxValue;
|
||||
continuousList.Clear();
|
||||
}
|
||||
else if (continuousList.Count > 0)
|
||||
{
|
||||
minBombSize = Int32.MaxValue;
|
||||
continuousList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupList = new List<CardGroupList>();
|
||||
|
||||
// 找最大的连炸
|
||||
List<Card> continuousList = new List<Card>();
|
||||
int lzCnt = group.LZCards.Count;
|
||||
int continuousCnt = 0;
|
||||
// 2233344444555
|
||||
for (int i = 0; i < group.CardGroupList.Count; i++)
|
||||
{
|
||||
continuousList.Clear();
|
||||
continuousCnt = 0;
|
||||
for (int j = 0; j < group.CardGroupList.Count; j++)
|
||||
{
|
||||
var index = i + j;
|
||||
if (index >= group.CardGroupList.Count) break;
|
||||
if (group.CardGroupList[index].Count == 0) break;
|
||||
|
||||
if (group.CardGroupList[index].Count >= 4
|
||||
|| group.CardGroupList[index].Count + lzCnt >= 4)
|
||||
{
|
||||
continuousList.AddRange(group.CardGroupList[index]);
|
||||
continuousCnt++;
|
||||
if (continuousCnt >= 3)
|
||||
{
|
||||
groupList.Add(new CardGroupList(continuousList));
|
||||
}
|
||||
} else
|
||||
{
|
||||
continuousList.Clear();
|
||||
continuousCnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 继续检查每个连炸是否符合要求
|
||||
for (int i = groupList.Count - 1; i >= 0 ; i--)
|
||||
{
|
||||
var bomb = groupList[i];
|
||||
var bombDict = bomb.GroupBy(c => c.Value)
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
var bombLine = bombDict.Values.Select(g => g.Count).ToList();
|
||||
var bombMax = bombLine.Max();
|
||||
int needCnt = 0;
|
||||
if (bombMax >= 4)
|
||||
{
|
||||
int oldBomMax = bombMax;
|
||||
while (bombMax >= 4)
|
||||
{
|
||||
needCnt = 0;
|
||||
for (int j = 0; j < bombLine.Count; j++)
|
||||
{
|
||||
needCnt += bombMax - bombLine[j];
|
||||
}
|
||||
|
||||
if (needCnt <= lzCnt) break;
|
||||
bombMax--;
|
||||
}
|
||||
|
||||
if (needCnt > lzCnt)
|
||||
{
|
||||
groupList.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 删除多余得牌
|
||||
foreach (var bd in bombDict)
|
||||
{
|
||||
var rmCards = bd.Value.GetRange(0, oldBomMax - bombMax);
|
||||
for (int j = rmCards.Count - 1; j >= 0 ; j--)
|
||||
{
|
||||
bomb.Remove(rmCards[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < bombLine.Count; j++)
|
||||
{
|
||||
needCnt += 4 - bombLine[j];
|
||||
}
|
||||
|
||||
if (needCnt > lzCnt)
|
||||
{
|
||||
groupList.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 再检验一次
|
||||
bomb.AddRange(group.LZCards.GetRange(0, needCnt));
|
||||
var bombGroup = group.mDeck.CreateCardGroup(bomb);
|
||||
if (bombGroup.GetCardStyleInfo().CardStyle != CardStyle)
|
||||
{
|
||||
groupList.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b2b8f2ee2ed48f2991a8c65d46732fa
|
||||
timeCreated: 1749020659
|
||||
@ -0,0 +1,12 @@
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 连炸 (2连以上)
|
||||
/// CardStyleInfo.CustomInt: 表示几个相同炸弹组成
|
||||
/// </summary>
|
||||
public class CardStyleBomb12Helper : CardStyleBomb123Helper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyleBomb12;
|
||||
public override int CardCnt => 8;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b58721a51e0b4276a356d4e7b914c66d
|
||||
timeCreated: 1765874379
|
||||
120
GameFix/Common/Card/StyleChecker/Helper/CardStyleBombHelper.cs
Normal file
120
GameFix/Common/Card/StyleChecker/Helper/CardStyleBombHelper.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 炸弹 (四张以上)
|
||||
/// </summary>
|
||||
public class CardStyleBombHelper : CardStyleBaseHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyleBomb;
|
||||
public override int CardCnt => 4;
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt && IsAllSame(group.Cards))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count < CardCnt) return false;
|
||||
if (group.LZCards.Count == group.Cards.Count && IsAllSame(group.LZCards))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.LZCards);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAllSame(group.NoLZCards))
|
||||
{
|
||||
var cardV = group.NoLZCards[0].Value;
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, cardV, group.Cards.Count);
|
||||
cardStyleInfo.CardLackValues = Enumerable.Repeat((int)cardV, group.LZCards.Count).ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllStyleCards(CardBaseGroup group, bool isSplitCard)
|
||||
{
|
||||
List<CardGroupList> ret = new List<CardGroupList>();
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
for (int i = 0; i < groupCnt; i++)
|
||||
{
|
||||
var cardGroup = group.CardGroupList[i];
|
||||
if (cardGroup.Count >= CardCnt)
|
||||
{
|
||||
ret.Add(new CardGroupList(cardGroup));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
for (int i = 0; i < groupCnt; i++)
|
||||
{
|
||||
var cardGroup = group.CardGroupList[i];
|
||||
if (cardGroup.Count >= CardCnt)
|
||||
{
|
||||
var cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, cardGroup);
|
||||
if (eatStyleInfo == null || group.mStyleComparer.Greater(cardStyleInfo, eatStyleInfo))
|
||||
{
|
||||
groupList.Add(new CardGroupList(cardGroup));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var cardGroupList = group.CardGroupDic.Where(kv => kv.Key >= 1)
|
||||
.SelectMany(kv => kv.Value).OrderByDescending(x=>x.Count).ToList();
|
||||
var groupList = new List<CardGroupList>();
|
||||
if (eatStyleInfo == null)
|
||||
eatStyleInfo = new CardStyleInfo(CardStyle, 0, CardCnt);
|
||||
foreach (var cardGroup in cardGroupList)
|
||||
{
|
||||
if (cardGroup.Count == 0 || IsJoker(cardGroup)) continue;
|
||||
var totalCnt = cardGroup.Count + group.LZCards.Count;
|
||||
if (totalCnt < CardCnt) continue;
|
||||
|
||||
var tmpStyleInfo = new CardStyleInfo(CardStyle, cardGroup.First().Value, totalCnt);
|
||||
int needCnt = 0;
|
||||
if (group.mStyleComparer.Greater(tmpStyleInfo, eatStyleInfo))
|
||||
{
|
||||
needCnt = tmpStyleInfo.CardCnt - cardGroup.Count;
|
||||
List<Card> tmpList = new List<Card>();
|
||||
tmpList.AddRange(cardGroup);
|
||||
tmpList.AddRange(group.LZCards.GetRange(0, needCnt));
|
||||
groupList.Add(new CardGroupList(tmpList));
|
||||
}
|
||||
}
|
||||
|
||||
if (groupList.Count == 0)
|
||||
{ // 癞子是否可以组成炸弹
|
||||
var tmpStyleInfo = new CardStyleInfo(CardStyle, group.LZCards.First().Value, group.LZCards.Count);
|
||||
if (group.mStyleComparer.Greater(tmpStyleInfo, eatStyleInfo))
|
||||
groupList.Add(new CardGroupList(group.LZCards));
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee5d4c36a107495aa91cf175575de0d5
|
||||
timeCreated: 1741848881
|
||||
@ -0,0 +1,168 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
/// <summary>
|
||||
/// 带王炸弹 (四张以上)
|
||||
/// </summary>
|
||||
public class CardStyleJokerBombHelper : CardStyleBombHelper
|
||||
{
|
||||
public override int CardStyle => DataCardConst.CardStyleJokerBomb;
|
||||
public override int CardCnt => 4;
|
||||
|
||||
private bool isAllJoker = true; // 是否可以组成全王炸弹
|
||||
|
||||
public CardStyleJokerBombHelper()
|
||||
{
|
||||
}
|
||||
|
||||
public CardStyleJokerBombHelper(bool allJoker)
|
||||
{
|
||||
isAllJoker = allJoker;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count >= CardCnt)
|
||||
{
|
||||
// 先排除王
|
||||
var bombCards = group.Cards.Where(x=>!DataCardConst.JokerValues.Contains(x.Value)).ToList();
|
||||
// 判断是否都是王
|
||||
if (isAllJoker && bombCards.Count == 0)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, DataCardConst.JokerValues[0], group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAllSame(bombCards) && bombCards.Count >= CardCnt)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, bombCards.First().Value, group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
|
||||
{
|
||||
cardStyleInfo = null;
|
||||
if (group.Cards.Count < CardCnt) return false;
|
||||
if (group.LZCards.Count == group.Cards.Count && IsAllSame(group.LZCards))
|
||||
{
|
||||
cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.LZCards);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 先排除王
|
||||
var bombCards = group.NoLZCards.Where(x=>!DataCardConst.JokerValues.Contains(x.Value)).ToList();
|
||||
// 判断是否都是王
|
||||
if (isAllJoker && bombCards.Count == 0)
|
||||
{
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, DataCardConst.JokerValues[0], group.Cards.Count);
|
||||
return true;
|
||||
}
|
||||
if (IsAllSame(bombCards) && bombCards.Count + group.LZCards.Count >= CardCnt)
|
||||
{
|
||||
var cardV = bombCards[0].Value;
|
||||
cardStyleInfo = new CardStyleInfo(CardStyle, cardV, group.Cards.Count);
|
||||
cardStyleInfo.CardLackValues = Enumerable.Repeat((int)cardV, group.LZCards.Count).ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
|
||||
{
|
||||
var groupCnt = group.CardGroupList.Count;
|
||||
var groupList = new List<CardGroupList>(groupCnt);
|
||||
var jokerList = group.Cards.Where(x=>DataCardConst.JokerValues.Contains(x.Value)).ToList();
|
||||
if (eatStyleInfo == null)
|
||||
eatStyleInfo = new CardStyleInfo(CardStyle, 0, CardCnt);
|
||||
|
||||
if (isAllJoker && jokerList.Count >= CardCnt)
|
||||
{ // 先提示全王
|
||||
var tmpStyleInfo = new CardStyleInfo(CardStyle, DataCardConst.JokerValues[0], jokerList.Count);
|
||||
if (group.mStyleComparer.Greater(tmpStyleInfo, eatStyleInfo))
|
||||
{
|
||||
groupList.Add(new CardGroupList(jokerList));
|
||||
}
|
||||
}
|
||||
|
||||
var filterGroupList = group.CardGroupList.Where(x => x.Count >= CardCnt).ToList();
|
||||
for (int i = 0; i < filterGroupList.Count; i++)
|
||||
{
|
||||
var cardGroup = filterGroupList[i];
|
||||
if (IsJoker(cardGroup)) continue;
|
||||
var tmpStyleInfo = new CardStyleInfo(CardStyle, cardGroup.First().Value, cardGroup.Count);
|
||||
if (group.mStyleComparer.Greater(tmpStyleInfo, eatStyleInfo) && filterGroupList.Count > 1)
|
||||
{
|
||||
groupList.Add(new CardGroupList(cardGroup));
|
||||
} else {
|
||||
tmpStyleInfo = new CardStyleInfo(CardStyle, cardGroup.First().Value, cardGroup.Count + jokerList.Count);
|
||||
if (group.mStyleComparer.Greater(tmpStyleInfo, eatStyleInfo))
|
||||
{
|
||||
var cardGroupList = new CardGroupList(cardGroup);
|
||||
cardGroupList.AddRange(jokerList);
|
||||
groupList.Add(cardGroupList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有得炸弹
|
||||
/// </summary>
|
||||
public List<CardGroupList> GetAllBombs(CardBaseGroup group)
|
||||
{
|
||||
List<CardGroupList> groupList = new List<CardGroupList>();
|
||||
var jokerList = group.Cards
|
||||
.Where(x => DataCardConst.JokerValues.Contains(x.Value) && x.CardType != DataCardConst.CardTypeLZ)
|
||||
.ToList();
|
||||
var descCardGroupList = group.CardGroupList.Select(x => x).OrderByDescending(x => x.Count).ToList();
|
||||
var lzCnt = group.LZCards.Count;
|
||||
for (int i = 0; i < descCardGroupList.Count; i++)
|
||||
{
|
||||
if (IsJoker(descCardGroupList[i]) ||descCardGroupList[i].Count + lzCnt < CardCnt) continue;
|
||||
CardGroupList cardGroupList = new CardGroupList();
|
||||
cardGroupList.AddRange(descCardGroupList[i]);
|
||||
if (lzCnt > 0)
|
||||
{
|
||||
cardGroupList.AddRange(group.LZCards);
|
||||
lzCnt = 0;
|
||||
}
|
||||
|
||||
if (jokerList.Count > 0)
|
||||
{
|
||||
cardGroupList.AddRange(jokerList);
|
||||
jokerList.Clear();
|
||||
}
|
||||
|
||||
CardStyleInfo styleInfo =
|
||||
new CardStyleInfo(CardStyle, descCardGroupList[i].First().Value, cardGroupList.Count);
|
||||
cardGroupList.CardStyleInfo = styleInfo;
|
||||
groupList.Add(cardGroupList);
|
||||
}
|
||||
|
||||
if (jokerList.Count > CardCnt && isAllJoker)
|
||||
{
|
||||
CardGroupList cardGroupList = new CardGroupList();
|
||||
cardGroupList.AddRange(jokerList);
|
||||
jokerList.Clear();
|
||||
CardStyleInfo styleInfo =
|
||||
new CardStyleInfo(CardStyle, jokerList.First().Value, cardGroupList.Count);
|
||||
cardGroupList.CardStyleInfo = styleInfo;
|
||||
groupList.Add(cardGroupList);
|
||||
}
|
||||
|
||||
return groupList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4ef4d49fafc4db09cc09e3d471c45c5
|
||||
timeCreated: 1741850722
|
||||
Reference in New Issue
Block a user