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
|
||||
205
GameFix/Common/Core/GameDeskUtility.cs
Normal file
205
GameFix/Common/Core/GameDeskUtility.cs
Normal file
@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using GameData;
|
||||
using GameMessage;
|
||||
using UnityGame;
|
||||
|
||||
namespace GameFix
|
||||
{
|
||||
/// <summary>
|
||||
/// int[] Seat
|
||||
/// - 下标索引表示进入桌子的初始位置号,也是服务器原始玩家数组的索引
|
||||
/// - 索引对应的内容是存在打乱之后的位置信息
|
||||
/// </summary>
|
||||
public static class GameDeskUtility
|
||||
{
|
||||
#region GameDeskInfo 扩展
|
||||
|
||||
/// <summary>
|
||||
/// 初始化位置信息
|
||||
/// </summary>
|
||||
public static void InitDeskSeat(this GameDeskInfo deskInfo, int playerCnt)
|
||||
{
|
||||
deskInfo.Seat = new int[playerCnt];
|
||||
for (int i = 0; i < playerCnt; i++)
|
||||
{
|
||||
deskInfo.Seat[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateSeat(this GameDeskInfo deskInfo, int[] seat)
|
||||
{
|
||||
deskInfo.Seat = (int[])seat.Clone();
|
||||
}
|
||||
|
||||
public static int GetServerSeat(this GameDeskInfo deskInfo, int serverSeat)
|
||||
{
|
||||
return GetServerSeat(deskInfo.Seat, serverSeat);
|
||||
}
|
||||
|
||||
public static int GetNextServerSeat(this GameDeskInfo deskInfo, int serverRealSeat)
|
||||
{
|
||||
return GetNextServerSeat(deskInfo.Seat, serverRealSeat);
|
||||
}
|
||||
|
||||
public static int GetNextServerSeat(this GameDeskInfo deskInfo, int serverRealSeat, int n)
|
||||
{
|
||||
return GetNextServerSeat(deskInfo.Seat, serverRealSeat, n);
|
||||
}
|
||||
|
||||
public static void SwitchSeat(this GameDeskInfo deskInfo, int originalSeat, int targetSeat)
|
||||
{
|
||||
SwitchSeat(deskInfo.Seat, originalSeat, targetSeat);
|
||||
}
|
||||
#if !Server
|
||||
public static int ClientToServerSeat(this GameDeskInfo deskInfo, int clientSeat)
|
||||
{
|
||||
return ClientToServerSeat(deskInfo.Seat, clientSeat);
|
||||
}
|
||||
|
||||
public static int ServerToClientSeat(this GameDeskInfo deskInfo, int serverSeat)
|
||||
{
|
||||
return ServerToClientSeat(deskInfo.Seat, serverSeat);
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#if !Server
|
||||
/// <summary>
|
||||
/// 客户端转服务器位置
|
||||
/// </summary>
|
||||
public static int ClientToServerSeat(int[] seat, int clientSeat)
|
||||
{
|
||||
if (UnityGame.hjhaGlobale.Instance.userData == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (seat == null || seat.Length < clientSeat)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (seat.Length <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (clientSeat < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mySeat = UnityGame.hjhaGlobale.Instance.userData.seat;
|
||||
mySeat = Array.IndexOf(seat, mySeat);
|
||||
if (mySeat < 0)
|
||||
{
|
||||
if (hjhaGlobale.Instance.userData.state == (int)PlayerState.Desk
|
||||
|| hjhaGlobale.Instance.userData.state == (int)PlayerState.Ready
|
||||
|| hjhaGlobale.Instance.userData.state == (int)PlayerState.War)
|
||||
{
|
||||
UnityEngine.Debug.LogError($"位置信息错误:MySeat={mySeat}");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
int serverSeat = (mySeat + clientSeat) % seat.Length;
|
||||
return GetServerSeat(seat, serverSeat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 服务器转客户端位置
|
||||
/// </summary>
|
||||
public static int ServerToClientSeat(int[] seat, int serverSeat)
|
||||
{
|
||||
if (UnityGame.hjhaGlobale.Instance.userData == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (seat == null || seat.Length < serverSeat)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int seatCnt = seat.Length;
|
||||
if (seatCnt <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (serverSeat < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mySeat = UnityGame.hjhaGlobale.Instance.userData.seat;
|
||||
mySeat = Array.IndexOf(seat, mySeat);
|
||||
serverSeat = Array.IndexOf(seat, serverSeat);
|
||||
|
||||
if (mySeat < 0 || serverSeat < 0)
|
||||
{
|
||||
UnityEngine.Debug.LogError($"位置信息错误:ServerSeat={serverSeat} MySeat={mySeat}");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (serverSeat - mySeat + seatCnt) % seatCnt;
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// 获取真实的服务器位置
|
||||
/// </summary>
|
||||
public static int GetServerSeat(int[] seat, int serverSeat)
|
||||
{
|
||||
if (seat == null || seat.Length < serverSeat)
|
||||
{
|
||||
#if Server
|
||||
MrWu.Debug.Debug.Error($"位置信息错误:serverSeat={serverSeat}");
|
||||
#endif
|
||||
return serverSeat;
|
||||
}
|
||||
|
||||
return seat[serverSeat];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 [serverSeat] 下N个玩家的服务器的位置
|
||||
/// </summary>
|
||||
public static int GetNextServerSeat(int[] seat, int serverSeat, int n)
|
||||
{
|
||||
if (seat == null || seat.Length < serverSeat)
|
||||
{
|
||||
#if Server
|
||||
MrWu.Debug.Debug.Error($"位置信息错误:serverSeat={serverSeat}");
|
||||
#endif
|
||||
return serverSeat;
|
||||
}
|
||||
|
||||
serverSeat = Array.IndexOf(seat, serverSeat);
|
||||
if (serverSeat < 0)
|
||||
{
|
||||
#if Server
|
||||
MrWu.Debug.Debug.Error($"位置信息错误:serverSeat={serverSeat}");
|
||||
#endif
|
||||
return serverSeat;
|
||||
}
|
||||
var nextSeat = (serverSeat + n) % seat.Length;
|
||||
return GetServerSeat(seat, nextSeat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 [serverSeat] 下一个玩家的服务器的位置
|
||||
/// </summary>
|
||||
public static int GetNextServerSeat(int[] seat, int serverSeat)
|
||||
{
|
||||
return GetNextServerSeat(seat, serverSeat, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 交换位置
|
||||
/// </summary>
|
||||
public static void SwitchSeat(int[] seat, int originalSeat, int targetSeat)
|
||||
{
|
||||
(seat[originalSeat], seat[targetSeat]) = (seat[targetSeat], seat[originalSeat]);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
GameFix/Common/Core/GameOverInfo1.cs
Normal file
40
GameFix/Common/Core/GameOverInfo1.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public abstract class GameOverInfo1<T> where T : ICardInfoType1
|
||||
{
|
||||
public string NickName { get; set; }
|
||||
public int Sex { get; set; }
|
||||
public string avter { get; set; }
|
||||
public int UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 赏的数值
|
||||
/// </summary>
|
||||
public int Shang { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 讨赏分
|
||||
/// </summary>
|
||||
public int ShangScore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 输赢分
|
||||
/// </summary>
|
||||
public int ShuYin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 得分
|
||||
/// </summary>
|
||||
public int DeFen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总得分
|
||||
/// </summary>
|
||||
public int ZongDeFen { get; set; }
|
||||
|
||||
public List<T> ZhaDans { get; set; }
|
||||
}
|
||||
}
|
||||
21
GameFix/Common/Core/LiCardType1.cs
Normal file
21
GameFix/Common/Core/LiCardType1.cs
Normal file
@ -0,0 +1,21 @@
|
||||
#if GameClient
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public abstract class LiCardType1<T> where T : ICardInfoType1
|
||||
{
|
||||
/// <summary>
|
||||
/// 整理的牌内容
|
||||
/// </summary>
|
||||
public List<T> Cards;
|
||||
|
||||
/// <summary>
|
||||
/// 这些牌的背景颜色
|
||||
/// </summary>
|
||||
public Color Color;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
722
GameFix/Common/Core/PokerLogic.cs
Normal file
722
GameFix/Common/Core/PokerLogic.cs
Normal file
@ -0,0 +1,722 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameMessage;
|
||||
|
||||
namespace GameFix.Poker
|
||||
{
|
||||
public static class PokerLogic
|
||||
{
|
||||
public class XY
|
||||
{
|
||||
public int x; //牌面大小
|
||||
public int y; //次数
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的单张
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<T> GetDanZhang<T>(IPlayOutCardType1 outCard, T[] cards, bool chaiDan = false)
|
||||
where T : ICardInfoType1
|
||||
{
|
||||
if (outCard.GameNum <= 0 || cards == null || cards.Length <= 0) return null;
|
||||
Dictionary<byte, byte> dic = new Dictionary<byte, byte>();
|
||||
List<T> result = new List<T>();
|
||||
foreach (var item in cards)
|
||||
{
|
||||
if (item.GameNum <= outCard.GameNum) continue;
|
||||
if (dic.ContainsKey(item.GameNum))
|
||||
{
|
||||
if (dic[item.GameNum] == 1)
|
||||
{
|
||||
dic[item.GameNum]++;
|
||||
if (!chaiDan || (chaiDan && dic[item.GameNum] >= 4))
|
||||
result.RemoveAll(x => x.GameNum == item.GameNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dic[item.GameNum] = 1;
|
||||
result.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取连续的相同大小的张数
|
||||
/// </summary>
|
||||
/// <param name="outCard"></param>
|
||||
/// <param name="cards">手里没有打下去的牌</param>
|
||||
/// <param name="count">几张大小相同的个数</param>
|
||||
/// <param name="shouPai">手里全部的牌</param>
|
||||
/// <returns></returns>
|
||||
public static List<List<T>> GetLianCount<T>(IPlayOutCardType1 outCard, T[] cards, int count,
|
||||
T[] shouPai) where T : ICardInfoType1
|
||||
{
|
||||
if (outCard.GameNum <= 0 || cards == null || cards.Length <= 3) return null;
|
||||
int lian = 0; //连了几下
|
||||
if (outCard.Type == CardType1.LianDui)
|
||||
{
|
||||
lian = outCard.Ids.Length / 2; //是几连对
|
||||
}
|
||||
|
||||
if (outCard.Type == CardType1.FeiJi)
|
||||
{
|
||||
lian = GetFeiJiCount(GetCardByIds(shouPai, outCard.Ids)); //是几连飞机
|
||||
}
|
||||
|
||||
List<List<T>> result = new List<List<T>>();
|
||||
var countCard = GetCountCard(outCard, cards, count, true, true, lian - 2);
|
||||
if (countCard.Count < lian) return result;
|
||||
for (int i = 0; i < countCard.Count - 1; i++)
|
||||
{
|
||||
List<T> temp = new List<T>();
|
||||
int c = 1;
|
||||
int num = countCard[i][0].GameNum;
|
||||
temp.AddRange(countCard[i]);
|
||||
for (int j = i + 1; j < countCard.Count; j++)
|
||||
{
|
||||
if (countCard[j][0].GameNum + 1 == num)
|
||||
{
|
||||
temp.AddRange(countCard[j]);
|
||||
c++;
|
||||
num = countCard[j][0].GameNum;
|
||||
}
|
||||
|
||||
if (c == lian) break;
|
||||
}
|
||||
|
||||
if (c == lian)
|
||||
{
|
||||
result.Add(temp);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据牌的绝对Id返回牌的详细信息
|
||||
/// </summary>
|
||||
/// <param name="wanshouPai">玩家手牌</param>
|
||||
/// <param name="ids">牌的Id集合</param>
|
||||
/// <returns></returns>
|
||||
public static T[] GetCardByIds<T>(T[] wanshouPai, byte[] ids) where T : ICardInfoType1
|
||||
{
|
||||
if (ids == null || ids.Length <= 0) return null;
|
||||
if (wanshouPai == null || wanshouPai.Length <= 0) return null;
|
||||
List<T> result = new List<T>();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
foreach (var item in wanshouPai)
|
||||
{
|
||||
if (item.ID == id)
|
||||
{
|
||||
result.Add(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ids.Length != result.Count)
|
||||
{
|
||||
throw new Exception($"获取玩家的牌张数不对 idslen:{ids.Length} result len:{result.Count} ");
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取飞机的连的个数,长度
|
||||
/// </summary>
|
||||
/// <param name="selectCards"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetFeiJiCount<T>(T[] selectCards) where T : ICardInfoType1
|
||||
{
|
||||
if (selectCards == null || selectCards.Length < 6) return 0;
|
||||
List<XY> list = new List<XY>();
|
||||
foreach (var item in selectCards)
|
||||
{
|
||||
var t = list.Find(x => x.x == item.GameNum);
|
||||
if (t != null)
|
||||
{
|
||||
t.y++;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(new XY { x = item.GameNum, y = 1 });
|
||||
}
|
||||
}
|
||||
|
||||
int num = list.Count(x => x.y >= 3);
|
||||
if (num < 2) return 0;
|
||||
list = list.Where(x => x.y >= 3).ToList();
|
||||
List<int> fj = new List<int>();
|
||||
for (int i = 0; i < list.Count - 1; i++)
|
||||
{
|
||||
if (list[i].x - 1 == list[i + 1].x)
|
||||
{
|
||||
if (!fj.Contains(list[i].x))
|
||||
{
|
||||
fj.Add(list[i].x);
|
||||
}
|
||||
|
||||
if (!fj.Contains(list[i + 1].x))
|
||||
{
|
||||
fj.Add(list[i + 1].x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fj.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取玩家手里几张相同的牌型
|
||||
/// </summary>
|
||||
/// <param name="outCard">玩家出的牌</param>
|
||||
/// <param name="cards">玩家手里没有出下去的牌</param>
|
||||
/// <param name="count">要获取相同大小的张数</param>
|
||||
/// <param name="chai">是否拆牌 false不拆 true拆</param>
|
||||
/// <param name="deng">是否获取跟出牌大小相等的牌 true是 false不是</param>
|
||||
/// <returns></returns>
|
||||
public static List<List<T>> GetCountCard<T>(IPlayOutCardType1 outCard, T[] cards, int count,
|
||||
bool chai = false, bool deng = false, int cha = 0) where T : ICardInfoType1
|
||||
{
|
||||
if (count <= 0 || outCard.GameNum <= 0 || cards == null || cards.Length < count) return null;
|
||||
List<List<T>> result = new List<List<T>>();
|
||||
Dictionary<byte, byte> dic = new Dictionary<byte, byte>();
|
||||
foreach (var item in cards)
|
||||
{
|
||||
if (deng)
|
||||
{
|
||||
if (item.GameNum < outCard.GameNum - cha) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.GameNum <= outCard.GameNum - cha) continue;
|
||||
}
|
||||
|
||||
if (dic.ContainsKey(item.GameNum))
|
||||
{
|
||||
dic[item.GameNum]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dic[item.GameNum] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in dic)
|
||||
{
|
||||
if (item.Value >= 4 && count < 4 && chai) continue; //炸弹就不拆
|
||||
if (!chai)
|
||||
{
|
||||
if (item.Value != count) continue;
|
||||
result.Add(cards.Where(x => x.GameNum == item.Key).ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.Value < count) continue;
|
||||
result.Add(cards.Where(x => x.GameNum == item.Key).Take(count).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否是对子
|
||||
/// 跑得快朋友房使用了
|
||||
/// </summary>
|
||||
/// <param name="selectCards"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsDuiZi<T>(T[] selectCards) where T : ICardInfoType1
|
||||
{
|
||||
if (selectCards == null || selectCards.Length != 2) return false;
|
||||
return selectCards[0].GameNum == selectCards[1].GameNum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取顺子
|
||||
/// </summary>
|
||||
/// <param name="playCard"></param>
|
||||
/// <returns></returns>
|
||||
public static List<List<T>> GetShunZi<T>(T[] playCard) where T : ICardInfoType1
|
||||
{
|
||||
if (playCard == null || playCard.Length < 5) return null;
|
||||
var cards = playCard.ToList();
|
||||
List<List<T>> result = new List<List<T>>();
|
||||
for (int i = 14; i > 6; i--)
|
||||
{
|
||||
List<T> shunzi = new List<T>();
|
||||
for (int j = 0; j < playCard.Length; j++)
|
||||
{
|
||||
T temp = cards.FirstOrDefault(x => x.GameNum == (i - j));
|
||||
if (temp.ID > 0)
|
||||
{
|
||||
shunzi.Add(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shunzi.Count >= 5)
|
||||
{
|
||||
result.Add(shunzi);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取顺子
|
||||
/// </summary>
|
||||
/// <param name="outCard"></param>
|
||||
/// <param name="playCard"></param>
|
||||
/// <returns></returns>
|
||||
public static List<List<T>> GetShunZi<T>(IPlayOutCardType1 outCard, T[] playCard) where T : ICardInfoType1
|
||||
{
|
||||
if (outCard.GameNum <= 0 || outCard.Type != CardType1.ShunZi) return null;
|
||||
if (playCard == null || playCard.Length < outCard.Ids.Length) return null;
|
||||
var cards = playCard.ToList();
|
||||
List<List<T>> result = new List<List<T>>();
|
||||
for (int i = 14; i > outCard.GameNum; i--)
|
||||
{
|
||||
List<T> shunzi = new List<T>();
|
||||
for (int j = 0; j < outCard.Ids.Length; j++)
|
||||
{
|
||||
T temp = cards.FirstOrDefault(x => x.GameNum == (i - j));
|
||||
if (temp.ID > 0)
|
||||
{
|
||||
shunzi.Add(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shunzi.Count == outCard.Ids.Length)
|
||||
{
|
||||
result.Add(shunzi);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否是飞机 跑得快朋友房使用了
|
||||
/// </summary>
|
||||
/// <param name="selectCards">选中的牌</param>
|
||||
/// <param name="isPaiBuGou">true不够 false 够</param>
|
||||
/// <param name="canDaiPia">true可以带牌 false不可以带牌</param>
|
||||
/// <param name="gameNum">返回飞机面值</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsFeiJi<T>(T[] selectCards, bool isPaiBuGou, bool canDaiPia, out byte gameNum)
|
||||
where T : ICardInfoType1
|
||||
{
|
||||
gameNum = 0;
|
||||
if (selectCards == null || selectCards.Length < 6) return false;
|
||||
List<XY> list = new List<XY>();
|
||||
foreach (var item in selectCards)
|
||||
{
|
||||
var t = list.Find(x => x.x == item.GameNum);
|
||||
if (t != null)
|
||||
{
|
||||
t.y++;
|
||||
if (t.y >= 3)
|
||||
{
|
||||
if (gameNum == 0)
|
||||
gameNum = item.GameNum;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(new XY { x = item.GameNum, y = 1 });
|
||||
}
|
||||
}
|
||||
|
||||
int num = list.Count(x => x.y >= 3);
|
||||
if (num < 2)
|
||||
return false; //if (canDaiPia && isPaiBuGou && selectCards.Length < num * 3) return false; //功能相同
|
||||
list = list.Where(x => x.y >= 3).ToList();
|
||||
List<int> fj = new List<int>();
|
||||
for (int i = 0; i < list.Count - 1; i++)
|
||||
{
|
||||
if (list[i].x - 1 == list[i + 1].x)
|
||||
{
|
||||
if (!fj.Contains(list[i].x))
|
||||
{
|
||||
fj.Add(list[i].x);
|
||||
}
|
||||
|
||||
if (!fj.Contains(list[i + 1].x))
|
||||
{
|
||||
fj.Add(list[i + 1].x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
num = fj.Count;
|
||||
if (num < 2) return false;
|
||||
gameNum = (byte)fj[0];
|
||||
if (!canDaiPia && num * 3 != selectCards.Length) return false; //如果不能带牌
|
||||
if (selectCards.Length > num * 3 + num * 2) return false; //带多了
|
||||
if (canDaiPia && !isPaiBuGou && num * 3 + num * 2 != selectCards.Length) return false;
|
||||
num--;
|
||||
for (int i = 0; i < fj.Count; i++)
|
||||
{
|
||||
if (num == 1)
|
||||
{
|
||||
//2连的飞机
|
||||
return fj[i] - num == fj[i + num];
|
||||
}
|
||||
else if (num == 2)
|
||||
{
|
||||
//3连的飞机
|
||||
return fj[i] == fj[i + 1] + 1 && fj[i + 1] == fj[i + 2] + 1;
|
||||
}
|
||||
else if (num == 3)
|
||||
{
|
||||
//4连的飞机
|
||||
return fj[i] == fj[i + 1] + 1 && fj[i + 1] == fj[i + 2] + 1 && fj[i + 2] == fj[i + 3] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fj[i] - num != fj[i + num])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否是顺子,使用该函数前请先排序 跑得快朋友房使用了
|
||||
/// </summary>
|
||||
/// <param name="selectCards"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsShunzi<T>(T[] selectCards) where T : ICardInfoType1
|
||||
{
|
||||
if (selectCards == null || selectCards.Length < 5) return false;
|
||||
T temp = selectCards[0];
|
||||
for (int i = 1; i < selectCards.Length; i++)
|
||||
{
|
||||
if (selectCards[i].GameNum != temp.GameNum - 1) return false; //不是连续的
|
||||
temp = selectCards[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给牌排序 跑得快朋友房使用了
|
||||
/// </summary>
|
||||
/// <param name="cards"></param>
|
||||
public static void SortCardByGameNum<T>(ref T[] cards) where T : ICardInfoType1
|
||||
{
|
||||
if (cards == null || cards.Length < 2) return;
|
||||
Array.Sort(cards, (x, y) => y.GameNum.CompareTo(x.GameNum));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否是连对,,使用该函数前请先排序 跑得快朋友房使用了
|
||||
/// </summary>
|
||||
/// <param name="selectCards"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsLianDui<T>(T[] selectCards) where T : ICardInfoType1
|
||||
{
|
||||
if (selectCards == null || selectCards.Length < 4 || selectCards.Length % 2 != 0) return false;
|
||||
T temp = selectCards[0];
|
||||
for (int i = 0; i < selectCards.Length; i += 2)
|
||||
{
|
||||
if (selectCards[i].GameNum != selectCards[i + 1].GameNum) return false; //不是一对的牌
|
||||
if (i + 2 <= selectCards.Length - 1)
|
||||
{
|
||||
if (temp.GameNum != selectCards[i + 2].GameNum + 1) return false; //不是顺子
|
||||
temp = selectCards[i + 2];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取玩家炸弹,没有炸弹则out就是废王的牌
|
||||
/// 需要先排序才可以运算
|
||||
/// </summary>
|
||||
/// <param name="playCards">玩家手牌</param>
|
||||
/// <param name="cards">炸弹的牌 或者 废王的牌</param>
|
||||
/// <returns>true有炸弹 false没有炸弹</returns>
|
||||
public static bool GetPlayZhaDan<T>(T[] playCards, out List<T> cards) where T : ICardInfoType1
|
||||
{
|
||||
cards = new List<T>();
|
||||
if (playCards == null || playCards.Length <= 0) return false;
|
||||
List<T> result = new List<T>();
|
||||
List<T> temp = new List<T>();
|
||||
List<T> wang = new List<T>();
|
||||
byte count = 0;
|
||||
byte num = 0;
|
||||
foreach (var item in playCards)
|
||||
{
|
||||
if (item.GameNum == 98 || item.GameNum == 100)
|
||||
{
|
||||
wang.Add(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num == 0 && count == 0)
|
||||
{
|
||||
num = item.GameNum;
|
||||
count++;
|
||||
temp.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num == item.GameNum)
|
||||
{
|
||||
count++;
|
||||
temp.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
num = item.GameNum;
|
||||
count = 1;
|
||||
if (temp.Count >= 4)
|
||||
{
|
||||
result.AddRange(temp);
|
||||
}
|
||||
|
||||
temp.Clear();
|
||||
temp.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (temp.Count >= 4) //防止最后一张牌遗漏
|
||||
{
|
||||
result.AddRange(temp);
|
||||
}
|
||||
|
||||
temp.Clear();
|
||||
if (result.Count >= 4)
|
||||
{
|
||||
result.AddRange(wang);
|
||||
cards.AddRange(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
cards = wang;
|
||||
if (wang.Count >= 4)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取玩家的炸弹
|
||||
/// </summary>
|
||||
/// <param name="playCards">玩家手牌</param>
|
||||
/// <param name="cards">炸弹的牌</param>
|
||||
/// <returns>true有炸弹 false没有炸弹</returns>
|
||||
public static bool GetPlayZhaDans<T>(T[] playCards, out List<List<T>> cards) where T : ICardInfoType1
|
||||
{
|
||||
cards = new List<List<T>>();
|
||||
if (playCards == null || playCards.Length <= 0) return false;
|
||||
|
||||
List<T> temp = new List<T>();
|
||||
byte count = 0;
|
||||
byte num = 0;
|
||||
foreach (var item in playCards)
|
||||
{
|
||||
|
||||
if (num == 0 && count == 0)
|
||||
{
|
||||
num = item.GameNum;
|
||||
count++;
|
||||
temp.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num == item.GameNum)
|
||||
{
|
||||
count++;
|
||||
temp.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
num = item.GameNum;
|
||||
count = 1;
|
||||
if (temp.Count >= 4)
|
||||
{
|
||||
cards.Add(temp.ToList());
|
||||
}
|
||||
temp.Clear();
|
||||
temp.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (temp.Count >= 4) //防止最后一张牌遗漏
|
||||
{
|
||||
cards.Add(temp.ToList());
|
||||
}
|
||||
return cards.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否是三带二 跑得快朋友房使用了
|
||||
/// </summary>
|
||||
/// <param name="selectCards">要判断的牌</param>
|
||||
/// <param name="isPaiBuGou">玩家手牌是不是不够张数带牌true不够 false够</param>
|
||||
/// <returns></returns>
|
||||
#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
|
||||
public static bool IsSanDaiEr<T>(T[] selectCards, bool isPaiBuGou, out byte gameNum) where T : ICardInfoType1
|
||||
#pragma warning restore CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
|
||||
{
|
||||
gameNum = 0;
|
||||
if (selectCards == null || selectCards.Length < 4 || selectCards.Length > 5) return false;
|
||||
if (!isPaiBuGou && selectCards.Length != 5) return false;
|
||||
Dictionary<byte, byte> dic = new Dictionary<byte, byte>();
|
||||
foreach (var item in selectCards)
|
||||
{
|
||||
if (dic.ContainsKey(item.GameNum))
|
||||
{
|
||||
dic[item.GameNum]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dic[item.GameNum] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dic.Count > 3 || dic.Count < 2) return false;
|
||||
var b = false;
|
||||
foreach (var item in dic)
|
||||
{
|
||||
if (item.Value >= 3 && item.Key < 90) //大王不能当成3个一起出
|
||||
{
|
||||
gameNum = item.Key;
|
||||
b = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测是否有相同的ID,因为牌的ID是唯一的,不会相同
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns>true有 false没有</returns>
|
||||
public static bool CheckSameId(byte[] ids)
|
||||
{
|
||||
if (ids == null || ids.Length <= 1) return false;
|
||||
Dictionary<byte, int> did = new Dictionary<byte, int>();
|
||||
for (int i = 0; i < ids.Length; i++)
|
||||
{
|
||||
if (did.ContainsKey(ids[i]))
|
||||
{
|
||||
did[ids[i]]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
did[ids[i]] = 1;
|
||||
}
|
||||
}
|
||||
foreach (var id in did)
|
||||
{
|
||||
if (id.Value > 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给牌排序,按照个数从大到小
|
||||
/// </summary>
|
||||
/// <param name="cards"></param>
|
||||
/// <returns></returns>
|
||||
public static T[] SortCardByCount<T>(T[] cards) where T : ICardInfoType1
|
||||
{
|
||||
if (cards == null || cards.Length <= 0) return null;
|
||||
List<T> result = new List<T>();
|
||||
Dictionary<int, List<T>> dics = new Dictionary<int, List<T>>();
|
||||
for (int i = 0; i < cards.Length; i++)
|
||||
{
|
||||
if (cards[i].GameNum > 20)
|
||||
{
|
||||
result.Add(cards[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dics.ContainsKey(cards[i].GameNum))
|
||||
{
|
||||
dics[cards[i].GameNum].Add(cards[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
var temp = new List<T>();
|
||||
temp.Add(cards[i]);
|
||||
dics.Add(cards[i].GameNum, temp);
|
||||
}
|
||||
}
|
||||
|
||||
var newdics = dics.OrderByDescending(x => x.Value.Count);
|
||||
foreach (var item in newdics)
|
||||
{
|
||||
result.AddRange(item.Value);
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public static string GetGameNumToString(byte gameNum)
|
||||
{
|
||||
string result = "";
|
||||
if (gameNum <= 0) return result;
|
||||
if (gameNum >= 3 && gameNum <= 10)
|
||||
{
|
||||
result = gameNum.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (gameNum)
|
||||
{
|
||||
case 11:
|
||||
result = "J";
|
||||
break;
|
||||
case 12:
|
||||
result = "Q";
|
||||
break;
|
||||
case 13:
|
||||
result = "K";
|
||||
break;
|
||||
case 14:
|
||||
result = "A";
|
||||
break;
|
||||
case 16:
|
||||
result = "2";
|
||||
break;
|
||||
//叫牌中不会有大小王
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
GameFix/Common/JsonHelper.cs
Normal file
28
GameFix/Common/JsonHelper.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GameFix
|
||||
{
|
||||
public static class JsonHelper
|
||||
{
|
||||
public static T DeserializeObject<T>(string jsonData)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(jsonData);
|
||||
}
|
||||
|
||||
public static T DeserializeObject<T>(string jsonData, JsonSerializerSettings settings)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(jsonData, settings);
|
||||
}
|
||||
|
||||
public static string SerializeObject(object obj)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj);
|
||||
}
|
||||
|
||||
public static string SerializeObject(object obj, JsonSerializerSettings settings)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj, settings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
32
GameFix/Common/Log.cs
Normal file
32
GameFix/Common/Log.cs
Normal file
@ -0,0 +1,32 @@
|
||||
namespace GameFix
|
||||
{
|
||||
public class Log
|
||||
{
|
||||
public static void Debug(string logStr)
|
||||
{
|
||||
#if GameClient
|
||||
GameFramework.Log.Debug(logStr);
|
||||
#else
|
||||
MrWu.Debug.Debug.Log(logStr);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Warning(string logStr)
|
||||
{
|
||||
#if GameClient
|
||||
GameFramework.Log.Warning(logStr);
|
||||
#else
|
||||
MrWu.Debug.Debug.Warning(logStr);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Error(string logStr)
|
||||
{
|
||||
#if GameClient
|
||||
GameFramework.Log.Error(logStr);
|
||||
#else
|
||||
MrWu.Debug.Debug.Error(logStr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
78
GameFix/Common/Mahjong/ActionType.cs
Normal file
78
GameFix/Common/Mahjong/ActionType.cs
Normal file
@ -0,0 +1,78 @@
|
||||
namespace GameFix.Mahjong
|
||||
{
|
||||
/// <summary>
|
||||
/// 动作类型
|
||||
/// </summary>
|
||||
public enum ActionType
|
||||
{
|
||||
/// <summary>
|
||||
/// 摸牌
|
||||
/// </summary>
|
||||
MoPai = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 出牌
|
||||
/// </summary>
|
||||
ChuPai = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 吃牌
|
||||
/// </summary>
|
||||
ChiPai = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 碰牌
|
||||
/// </summary>
|
||||
PengPai = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 杠牌
|
||||
/// </summary>
|
||||
GangPai = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 胡牌
|
||||
/// </summary>
|
||||
HuPai = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 过牌
|
||||
/// </summary>
|
||||
PassPai = 6,
|
||||
|
||||
/// <summary>
|
||||
/// 补牌
|
||||
/// </summary>
|
||||
BuPai = 7,
|
||||
|
||||
/// <summary>
|
||||
/// 花杠
|
||||
/// </summary>
|
||||
HuaGang = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 出宝牌
|
||||
/// </summary>
|
||||
ChuBao = 9,
|
||||
|
||||
/// <summary>
|
||||
/// 掷骰子
|
||||
/// </summary>
|
||||
ZhiTouZi = 10,
|
||||
|
||||
/// <summary>
|
||||
/// 亮精
|
||||
/// </summary>
|
||||
LiangJing = 11,
|
||||
|
||||
/// <summary>
|
||||
/// 听牌
|
||||
/// </summary>
|
||||
TingPai = 12,
|
||||
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
None = 13,
|
||||
}
|
||||
}
|
||||
217
GameFix/Common/Mahjong/GameDeskMem.cs
Normal file
217
GameFix/Common/Mahjong/GameDeskMem.cs
Normal file
@ -0,0 +1,217 @@
|
||||
using MessagePack;
|
||||
|
||||
namespace GameFix.Mahjong
|
||||
{
|
||||
/// <summary>
|
||||
/// 杠类型
|
||||
/// </summary>
|
||||
public enum GangStyle : byte
|
||||
{
|
||||
GangOther = 0,
|
||||
GangPeng = 1,
|
||||
GangSelf = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 吃类型
|
||||
/// </summary>
|
||||
public enum ChiStyle : byte
|
||||
{
|
||||
Left = 0,
|
||||
Middle = 1,
|
||||
Right = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 杠信息
|
||||
/// </summary>
|
||||
[MessagePackObject]
|
||||
public class GangInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 杠的牌
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public sbyte Pai;
|
||||
|
||||
/// <summary>
|
||||
/// 0杠别人 1杠碰的牌(明杠), 2杠手里的牌(暗杠) 3单牌补杠
|
||||
/// </summary>
|
||||
[Key(1)]
|
||||
public byte Style;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 补牌信息
|
||||
/// </summary>
|
||||
public class BuPaiInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 补的牌
|
||||
/// </summary>
|
||||
public sbyte Pai;
|
||||
|
||||
/// <summary>
|
||||
/// 补牌方式
|
||||
/// </summary>
|
||||
public byte Style;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 吃信息
|
||||
/// </summary>
|
||||
[MessagePackObject]
|
||||
public class ChiInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 吃信息的数量
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public int Cnt;
|
||||
|
||||
/// <summary>
|
||||
/// 吃类型
|
||||
/// </summary>
|
||||
[Key(1)]
|
||||
public int[] Style = new int[3];
|
||||
|
||||
/// <summary>
|
||||
/// 用什么牌可以去吃
|
||||
/// </summary>
|
||||
[Key(2)]
|
||||
public sbyte[,] Pai = new sbyte[3, 2];
|
||||
}
|
||||
|
||||
public enum QueType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 吃
|
||||
/// </summary>
|
||||
Chi = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 碰
|
||||
/// </summary>
|
||||
Peng = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 杠
|
||||
/// </summary>
|
||||
Gang = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 补牌
|
||||
/// </summary>
|
||||
BuPai = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 花杠
|
||||
/// </summary>
|
||||
HuaGang = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 宝牌
|
||||
/// </summary>
|
||||
BaoPai = 6,
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class QueInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 谁提供的牌 -1 表示自己
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public int Supply;
|
||||
|
||||
/// <summary>
|
||||
/// 吃碰杠的牌
|
||||
/// </summary>
|
||||
[Key(1)]
|
||||
public sbyte[] Pai = new sbyte[3];
|
||||
|
||||
/// <summary>
|
||||
/// 吃的牌
|
||||
/// </summary>
|
||||
[Key(2)]
|
||||
public sbyte Cp;
|
||||
|
||||
/// <summary>
|
||||
/// 阙的类型
|
||||
/// </summary>
|
||||
[Key(3)]
|
||||
public byte QueStyle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 麻将游戏状态
|
||||
/// </summary>
|
||||
public enum MahjongGameState : int
|
||||
{
|
||||
/// <summary>
|
||||
/// 抓牌
|
||||
/// </summary>
|
||||
ZhuaPai = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 翻宝 -- 客户端自己处理
|
||||
/// </summary>
|
||||
FanBao = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 打牌状态
|
||||
/// </summary>
|
||||
DaPai = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 流局
|
||||
/// </summary>
|
||||
LiuJu = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 正常结束
|
||||
/// </summary>
|
||||
GameOver = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 加买分
|
||||
/// </summary>
|
||||
MaiScore = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 掷骰子阶段
|
||||
/// </summary>
|
||||
ZhiTouZi = 6,
|
||||
|
||||
/// <summary>
|
||||
/// 亮精阶段
|
||||
/// </summary>
|
||||
LiangJing = 7,
|
||||
|
||||
/// <summary>
|
||||
/// 前翻精阶段
|
||||
/// </summary>
|
||||
QianFanJing = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 后翻精阶段
|
||||
/// </summary>
|
||||
HouFanJing = 9,
|
||||
|
||||
/// <summary>
|
||||
/// 翻宝前阶段
|
||||
/// </summary>
|
||||
FanBaoQian = 10,
|
||||
|
||||
/// <summary>
|
||||
/// 翻宝后阶段
|
||||
/// </summary>
|
||||
FanBaoHou = 11,
|
||||
|
||||
/// <summary>
|
||||
/// 随精阶段
|
||||
/// </summary>
|
||||
SuiJing = 12,
|
||||
}
|
||||
|
||||
}
|
||||
20
GameFix/Common/Mahjong/MahjongStatic.cs
Normal file
20
GameFix/Common/Mahjong/MahjongStatic.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace GameFix.Mahjong
|
||||
{
|
||||
public static class MahjongStatic
|
||||
{
|
||||
/// <summary>
|
||||
/// 最大玩家数量
|
||||
/// </summary>
|
||||
public const int MaxPlayerCnt = 4;
|
||||
|
||||
/// <summary>
|
||||
/// 最大手牌数量
|
||||
/// </summary>
|
||||
public const int MaxShouPaiCnt = 14;
|
||||
|
||||
/// <summary>
|
||||
/// 最大的出牌数量
|
||||
/// </summary>
|
||||
public const int MaxPaiOutCnt = 60;
|
||||
}
|
||||
}
|
||||
105
GameFix/Common/Mahjong/OperationPack.cs
Normal file
105
GameFix/Common/Mahjong/OperationPack.cs
Normal file
@ -0,0 +1,105 @@
|
||||
using MessagePack;
|
||||
|
||||
namespace GameFix.Mahjong
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作类型
|
||||
/// </summary>
|
||||
public enum OperationType
|
||||
{
|
||||
/// <summary>
|
||||
/// 无操作
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 出牌
|
||||
/// </summary>
|
||||
ChuPai = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 过
|
||||
/// </summary>
|
||||
Guo = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 吃牌
|
||||
/// </summary>
|
||||
ChiPai = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 碰牌
|
||||
/// </summary>
|
||||
PengPai = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 杠牌
|
||||
/// </summary>
|
||||
GangPai = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 胡牌
|
||||
/// </summary>
|
||||
HuPai = 6,
|
||||
|
||||
/// <summary>
|
||||
/// 下一张摸的牌
|
||||
/// </summary>
|
||||
NextPai = 7,
|
||||
|
||||
/// <summary>
|
||||
/// 换牌
|
||||
/// </summary>
|
||||
HuanPai = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 保存数据
|
||||
/// </summary>
|
||||
SaveData = 9,
|
||||
|
||||
/// <summary>
|
||||
/// 买分
|
||||
/// </summary>
|
||||
MaiScore = 10,
|
||||
|
||||
/// <summary>
|
||||
/// 杠发财
|
||||
/// </summary>
|
||||
GangFaCai = 11,
|
||||
|
||||
/// <summary>
|
||||
/// 补牌
|
||||
/// </summary>
|
||||
BuPai = 12,
|
||||
|
||||
/// <summary>
|
||||
/// 发牌结束
|
||||
/// </summary>
|
||||
FaPaiOver = 13,
|
||||
|
||||
/// <summary>
|
||||
/// 掷骰子
|
||||
/// </summary>
|
||||
ZhiTouZi = 14,
|
||||
|
||||
/// <summary>
|
||||
/// 亮精
|
||||
/// </summary>
|
||||
LiangJing = 15,
|
||||
|
||||
/// <summary>
|
||||
/// 听牌
|
||||
/// </summary>
|
||||
TingPai = 16,
|
||||
|
||||
/// <summary>
|
||||
/// 选精
|
||||
/// </summary>
|
||||
XuanJing = 17,
|
||||
|
||||
/// <summary>
|
||||
/// 换精
|
||||
/// </summary>
|
||||
HuanJing = 18,
|
||||
}
|
||||
}
|
||||
15
GameFix/Common/Mahjong/OperationValue.cs
Normal file
15
GameFix/Common/Mahjong/OperationValue.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace GameFix.Mahjong
|
||||
{
|
||||
[Flags]
|
||||
public enum OperationValue
|
||||
{
|
||||
None = 0,
|
||||
Chi = 1 << 1,
|
||||
Peng = 1 << 2,
|
||||
Gang = 1 << 3,
|
||||
Hu = 1 << 4,
|
||||
Ting = 1 << 5,
|
||||
}
|
||||
}
|
||||
58
GameFix/GameFix.csproj
Normal file
58
GameFix/GameFix.csproj
Normal file
@ -0,0 +1,58 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>GameFix</RootNamespace>
|
||||
<AssemblyName>GameFix</AssemblyName>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;Server</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;Server</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessagePack" />
|
||||
<PackageReference Include="MessagePack.Annotations" />
|
||||
<PackageReference Include="MessagePackAnalyzer" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
|
||||
<PackageReference Include="Microsoft.NET.StringTools" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
<PackageReference Include="System.Buffers" />
|
||||
<PackageReference Include="System.Collections.Immutable" />
|
||||
<PackageReference Include="System.Memory" />
|
||||
<PackageReference Include="System.Numerics.Vectors" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- <ItemGroup>-->
|
||||
<!-- <Compile Include="..\..\hjha_Client\Assets\ScriptCode\UnityGame\GamePlay\Common\**\*.cs"-->
|
||||
<!-- Link="GameFix\%(RecursiveDir)%(Filename)%(Extension)" />-->
|
||||
<!-- </ItemGroup>-->
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MrWu\MrWu.csproj" />
|
||||
<ProjectReference Include="..\NetWorkMessage\NetWorkMessage.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
35
GameFix/Properties/AssemblyInfo.cs
Normal file
35
GameFix/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("GameFix")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("GameFix")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2025")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("AE8D22EB-254B-446A-9C79-BE13E45AFC45")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
Reference in New Issue
Block a user