斗地主提示牌
获取快速组合牌;
1、取王炸
2、取顺子组合
3、取炸弹飞机三张连对
4、给炸弹飞机三张配料如3带1,3
不过应该是不是先取连对特别的策略
//获取连对4455666 445566 6 44666 55
// 4455666 999 445566 6999 or 44666 55999 rule
// 3个农民
/// </summary>
typedef enum
{
UserFarmer0,//农民
UserFarmer1,//农民
UserFarmer2,//农民
UserPending,//待定
UserMax
}UserType;
/// 卡牌花色
/// </summary>
typedef enum
{
Diamond,//方块
Heart,//红桃
Spade,//黑桃
Club,//梅花
Joker,//王
ColorMax
}ColorType;
/// 卡牌的权值
/// </summary>
typedef enum
{
Three, // 3-9
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack, // J
Queen, // Q
King, // K
One, // A
Two, // 2
SJoker, // 小王
LJoker, // 大王
CardMax
}CardType;
/// <summary>
/// 出牌类型
/// </summary>
typedef enum
{
None,
Single,//单
Double,//对儿
Straight,//顺子3-<A 5
DoubleStraight,//连队3-<A 6
CThree,//三不带333444555
ThreeAndOne,//三带一33334444
ThreeAndTwo,//三代二
FourAndTwo,//四带二33334444 4带2对还是飞机
FourAndFour,//四带二对
Boom,//炸弹
JokerBoom,//王炸
CardTypeMax
}CardsType;
typedef struct CardStruct
{
//牌型
CardType card;
//花色对斗地主规则没有什么关系,只用于显示
ColorType color;
// 发牌存储
UserType shuffle;
//是否3张地主牌
BOOL topbrand;
//被出牌的轮次,0表示没有被出
BYTE order;
//被选中
BOOL bsel;
};
//54扑克牌
#define CardsCount 54
CardStruct mCardsList[CardsCount];
//提示牌结构体
typedef struct TipsStruct
{
//牌数量
BYTE count;
//牌值CardType
BYTE cards[CardsCount];
//关键牌 22444和44555 大小关键在三张4和5
BYTE hcard;
//组牌类型CardsType
BYTE type;
//级别LevelType
BYTE level;
//cards的校验和
INT checksum;
//比自己大牌数量
INT weight;
//比自己小牌数量
INT swatch;
//平行组合
TipsStruct *next;
};
//==========================功能函数
void CardInit(void)
{
//扑克牌初始化 3333 4444 ... ... SJ LJ
BYTE id=0;
for(BYTE i=0;i<SJoker;i++)
{
for(BYTE j=0;j<Joker;j++)
{
mCardsList[id].card=(CardType)i;
mCardsList[id].color=(ColorType)j;
id++;
}
}
mCardsList[id].card=SJoker;
mCardsList[id].color=Joker;
id++;
mCardsList[id].card=LJoker;
mCardsList[id].color=Joker;
}
/*
cards[CardMax]和cards[CardsCount]数组互转
0:CardsCount->CardMax
1:CardMax->CardsCount
*/
BYTE CardsTransform(BYTE *cards,BYTE Count,BYTE *uCards,BYTE uCount,BYTE type)
{
BYTE count=0;
//CardsCount->CardMax
if(type==0)
{
//memset(uCards,0,uCount);
for(BYTE i=0;i<Count;i++)
uCards[cards[i]]++;
}
//CardMax->CardsCount
else
{
for(BYTE i=0;i<uCount;i++)
for(BYTE j=0;j<uCards[i];j++)
{
if(count<Count)
cards[count]=i;
count++;
}
}
return count;
}
/// <summary>
/// 是否是单牌
/// 2
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsSingle(BYTE *cards,BYTE Count,BYTE *hcard)
{
if(Count == 1)
{
*hcard=cards[0];
return TRUE;
}
else return FALSE;
}
/// <summary>
/// 判断是否是对儿
/// 22
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsDouble(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count == 2)
{
if (cards[0] == cards[1])
{
*hcard=cards[0];
return TRUE;
}
}
return FALSE;
}
/// <summary>
/// 是否是顺子
/// 如:23456
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsStraight(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count < 5 || Count > 12)
return FALSE;
for (INT i = 0; i < Count - 1; i++)
{
//不能超过A
if (cards[i] > One || cards[i + 1] > One)
return FALSE;
if (cards[i + 1] - cards[i] != 1)
return FALSE;
}
*hcard=cards[0];
return TRUE;
}
/// <summary>
/// 是否是连对
/// 如:223344
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsDoubleStraight(BYTE *cards,BYTE Count,BYTE *hcard)
{
// 牌数大于6且成对出现
if (Count < 6 || Count % 2 != 0)
return FALSE;
for (INT i = 0; i < Count - 2; i += 2)
{
//对子
if (cards[i] != cards[i + 1])
return FALSE;
if (cards[i + 2] - cards[i] != 1)
return FALSE;
//不能超过A
if (cards[i] > One || cards[i + 2] > One)
return FALSE;
}
//miss last check
if (cards[Count-1] != cards[Count - 2])
return FALSE;
*hcard=cards[0];
return TRUE;
}
/// <summary>
/// 是否是三不带以及飞机
/// 如:222 3,6,9,12,15,18
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsThree(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count < 3 || Count%3 != 0 )
return FALSE;
for(INT i=0;i<Count;i+=3)
{
if ((cards[i] != cards[i+1]) || (cards[i] != cards[i+2]))
return FALSE;
//检测飞机
if(i>0)
{
if(cards[i]==Two)
return FALSE;
if(cards[i-1] != (cards[i]-1))
return FALSE;
}
}
*hcard=cards[0];
return TRUE;
}
/// <summary>
/// 是否是三带一
/// 如:2224 4,8,12,16,19
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsThreeAndOne(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count < 4 || Count%4 != 0 )
return FALSE;
INT nThree=0,card,total;
total=Count/4;
for(INT i=0;i<Count;)
{
if(2+i<Count&&cards[i]==cards[1+i]&&cards[i]==cards[2+i])
{
//222333444555 222
if(nThree==0||card>One||cards[i]>One||card!=(cards[i]-nThree))
{
nThree=1;
card=cards[i];
}
else nThree++;
//333444555666
if(nThree==total)
{
*hcard=card;
return TRUE;
}
i+=3;
}
else i++;
}
return FALSE;
}
/// <summary>
/// 是否是三带二
/// 如:22233 5,10,15,20
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
//333+王炸?
BOOL IsThreeAndTwo(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count < 5 || Count%5 != 0)
return FALSE;
//max 5
INT nThree=0,card,nTwo=0;
for(INT i=0;i<Count;)
{
//4条4444555666
if(3+i<Count&&cards[i]==cards[1+i]&&cards[i]==cards[2+i]&&cards[i]==cards[3+i])
{
nTwo+=2;
i+=4;
}
//3条3334442222
else if(2+i<Count&&cards[i] == cards[1+i]&&cards[i] == cards[2+i])
{
if(nThree==0)card=cards[i];
//大于One或者不连续
else if(card>One||cards[i]>One||card!=(cards[i]-nThree))
return FALSE;
nThree++;
i+=3;
}
//2条
else if(1+i<Count&&cards[i]==cards[1+i])
{
nTwo++;
i+=2;
}
else return FALSE;
}
//三条和对子都不够
if(nThree==nTwo)
{
*hcard=card;
return TRUE;
}
return FALSE;
}
/// <summary>
/// 是否是四带二
/// 如:344445
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsFourAndTwo(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count != 6)
return FALSE;
for(INT i=0;i<3;i++)
{
if(cards[i]==cards[1+i]
&&cards[i]==cards[2+i]
&&cards[i]==cards[3+i])
{
*hcard=cards[i];
return TRUE;
}
}
return FALSE;
}
/// <summary>
/// 是否是四带二对
/// 如:33444455 44446666是否支持
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsFourAndFour(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count != 8)
return FALSE;
// 四对
if( cards[0]==cards[1]
&&cards[2]==cards[3]
&&cards[4]==cards[5]
&&cards[6]==cards[7])
{
//已经排好次序
if(cards[0]==cards[2]&&cards[4]!=cards[6]) // 4个在前面
{
*hcard=cards[0];
return TRUE;
}
else if(cards[2]==cards[4])// 4个在中间
{
*hcard=cards[2];
return TRUE;
}
else if(cards[4]==cards[6]&&cards[0]!=cards[2]) // 4个在后面
{
*hcard=cards[4];
return TRUE;
}
else if(cards[0]==cards[2]&&cards[4]==cards[6]) // 两个炸弹
{
if(cards[0]>cards[4])*hcard=cards[0];
else *hcard=cards[4];
return TRUE;
}
}
return FALSE;
}
/// <summary>
/// 判断是否是炸弹
/// 如:4444
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsBoom(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count != 4)
return FALSE;
if(cards[0]==cards[1]
&&cards[0]==cards[2]
&&cards[0]==cards[3])
{
*hcard=cards[0];
return TRUE;
}
return FALSE;
}
/// <summary>
/// 判断是不是王炸
/// 如:大王小王
/// </summary>
/// <param name="cards">选择的手牌</param>
/// <returns></returns>
BOOL IsJokerBoom(BYTE *cards,BYTE Count,BYTE *hcard)
{
if (Count != 2)
return FALSE;
if (cards[0] == SJoker && cards[1] == LJoker)
{
*hcard=cards[0];
return TRUE;
}
return FALSE;
}
/// <summary>
/// 判断能否出牌
/// </summary>
/// <param name="cards">要出的牌</param>
/// <param name="type">出牌类型</param>
/// <returns>能否出牌</returns>
BYTE CanPop(BYTE *cards,BYTE Count,BYTE *hcard)
{
BYTE type = None;
switch (Count) // 牌数
{
case 1:
if (IsSingle(cards,Count,hcard))
{
type = Single;
}
break;
case 2:
//优先王炸
if (IsJokerBoom(cards,Count,hcard))
{
type = JokerBoom;
}
else if (IsDouble(cards,Count,hcard))
{
type = Double;
}
break;
case 3:
if (IsThree(cards,Count,hcard))
{
type = CThree;
}
break;
case 4:
// 优先考虑炸弹
if (IsBoom(cards,Count,hcard))
{
type = Boom;
}
else if (IsThreeAndOne(cards,Count,hcard))
{
type = ThreeAndOne;
}
break;
case 5:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
else if (IsThreeAndTwo(cards,Count,hcard))
{
type = ThreeAndTwo;
}
break;
case 6:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
else if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
else if(IsFourAndTwo(cards,Count,hcard))
{
type = FourAndTwo;
}
else if (IsThree(cards,Count,hcard))
{
type = CThree;
}
break;
case 7:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
break;
case 8:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
else if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
else if (IsThreeAndOne(cards,Count,hcard))
{
type = ThreeAndOne;
}
else if(IsFourAndFour(cards,Count,hcard))
{
type = FourAndFour;
}
break;
case 9:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
else if (IsThree(cards,Count,hcard))
{
type = CThree;
}
break;
case 10:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
else if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
else if (IsThreeAndTwo(cards,Count,hcard))
{
type = ThreeAndTwo;
}
break;
case 11:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
break;
case 12:
if (IsStraight(cards,Count,hcard))
{
type = Straight;
}
else if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
// 444 555 666 777 > 777 888 999 345
else if (IsThree(cards,Count,hcard))
{
type = CThree;
}
else if (IsThreeAndOne(cards,Count,hcard))
{
type = ThreeAndOne;
}
break;
case 13:
break;
case 14:
if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
break;
case 15:
if (IsThree(cards,Count,hcard))
{
type = CThree;
}
else if(IsThreeAndTwo(cards,Count,hcard))
{
type = ThreeAndTwo;
}
break;
case 16:
if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
else if (IsThreeAndOne(cards,Count,hcard))
{
type = ThreeAndOne;
}
break;
case 17:
break;
case 18:
if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
// 444 555 666 777 888 999
else if (IsThree(cards,Count,hcard))
{
type = CThree;
}
break;
case 19:
break;
case 20:
//33 44 55 66 77 88 99 1010 JJ QQ
if (IsDoubleStraight(cards,Count,hcard))
{
type = DoubleStraight;
}
//3334445556667788991010
else if(IsThreeAndTwo(cards,Count,hcard))
{
type = ThreeAndTwo;
}
//3334445556667778910JQ
else if (IsThreeAndOne(cards,Count,hcard))
{
type = ThreeAndOne;
}
break;
default:
break;
}
return type;
}
void *InitTipsStruct()
{
TipsStruct *p;
p = (TipsStruct *)malloc(sizeof(TipsStruct));
p->level=Level0;
p->count=0;
p->weight=0;
p->swatch=0;
p->checksum=0;
p->next=NULL;
return p;
}
/// <summary>
/// 对cards排序
/// </summary>
/// <param name="cards">对cards排序</param>
/// <returns></returns>
void SortMinToMax(BYTE *cards,BYTE Count)
{
BYTE temp;
for(BYTE i=0;i<Count;i++)
{
for(BYTE j=i+1;j<Count;j++)
{
if(cards[i]>cards[j])
{
temp=cards[i];
cards[i]=cards[j];
cards[j]=temp;
}
}
}
}
/*
检查s是t否相同
*/
BOOL CheckEqual(BYTE *s,BYTE *t,BYTE Count,BOOL bsort)
{
if(bsort)
{
SortMinToMax(s,Count);
SortMinToMax(t,Count);
}
for(BYTE i=0;i<Count;i++)
{
if(s[i]!=t[i])
return FALSE;
}
return TRUE;
}
/*
检查在链表l中有相同的项,没有则添加到末尾;
*/
void *AddTipsStruct(BYTE *cards,BYTE Count,BYTE type,BYTE hcard,TipsStruct *l)
{
TipsStruct *p;
p=l;
while(p)
{
if(p->type==type
&&p->count==Count
&&CheckEqual(cards,p->cards,Count,FALSE))
{
//check same or not
return l;
}
if(p->next == NULL)
{
p->next=(TipsStruct *)InitTipsStruct();
p=p->next;
break;
}
p=p->next;
}
if(p==NULL)
{
p=(TipsStruct *)InitTipsStruct();
l=p;
}
p->count=Count;
p->type=type;
p->hcard=hcard;
memcpy(p->cards,cards,Count);
p->checksum=CheckSum(cards,Count);
return l;
}
/*
把p拼接到l的后面;
*/
void *CombineList(TipsStruct *l,TipsStruct *p)
{
if(p==NULL)return l;
if(l==NULL)return p;
TipsStruct *s=l;
while(s->next)s=s->next;
s->next=p;
return l;
}
/*
比较s的牌是否比c的牌大
*/
BOOL CheckBigCards(TipsStruct *s,TipsStruct *c)
{
if(s==NULL||s->type==None||c==NULL||c->type==None)return FALSE;
//王炸最大,//炸弹
if(s->type==JokerBoom || (s->type==Boom&&s->type>c->type))
return TRUE;
//相同牌型,相同长度,比较关键牌是否够大
else if(s->type==c->type
&&s->count==c->count
&&s->hcard>c->hcard)
return TRUE;
return FALSE;
}
/*
下标是卡牌值,数值是卡牌数量,比较卡牌的连续
*/
BOOL CheckContinuityM(BYTE *cards,BYTE Count,BYTE m)
{
for(BYTE i=0;i<Count;i++)
{
if(cards[i]<m)return FALSE;
}
return TRUE;
}
/*
从card开始填充Count个连续相同的m进入cards
返回填充的数量;
*/
BYTE PadCards(BYTE *cards,BYTE Count,BYTE card,BYTE m)
{
BYTE count=0;
for(BYTE i=0;i<Count;i++)
for(BYTE j=0;j<m;j++)
cards[count++]=card+i;
return count;
}
/*
获取顺子组合
*/
void *GetStraight(BYTE *cards)
{
BYTE temp[CardsCount],count;
TipsStruct *l=NULL;
//单张起步5-12张34567 8910JQ KA
for(INT i=5;i<=Two;i++)
{
for(INT j=Three;j<=(Two-i);j++)
{
if(CheckContinuityM(cards+j,i,1))
{
count=PadCards(temp,i,j,1);
l=(TipsStruct *)AddTipsStruct(temp,count,Straight,temp[0],l);
}
}
}
return l;
}
/*
获取连对组合
*/
void *GetDoubleStraight(BYTE *cards)
{
BYTE temp[CardsCount],count;
TipsStruct *l=NULL;
//起步3对
for(INT i=3;i<=Two;i++)
{
for(INT j=Three;j<=(Two-i);j++)
{
if(CheckContinuityM(cards+j,i,2))
{
count=PadCards(temp,i,j,2);
l=(TipsStruct *)AddTipsStruct(temp,count,DoubleStraight,temp[0],l);
}
}
}
return l;
}
/*
获取飞机组合
*/
void *GetCThree(BYTE *cards)
{
BYTE temp[CardsCount],count;
TipsStruct *l=NULL;
//2个起步
for(INT i=2;i<=Two;i++)
{
for(INT j=Three;j<=(Two-i);j++)
{
if(CheckContinuityM(cards+j,i,3))
{
count=PadCards(temp,i,j,3);
l=(TipsStruct *)AddTipsStruct(temp,count,CThree,temp[0],l);
}
}
}
return l;
}
/*
获取同类数量的个数
*/
BYTE GetTypeCount(BYTE *cards,BYTE Count,BYTE m)
{
BYTE count=0;
for(BYTE i=0;i<Count;i++)
if(cards[i]==m)count++;
return count;
}
/*
删除cards中包含的uCards
*/
BOOL RemoveContain(BYTE *cards,BYTE *uCards,BYTE Count)
{
for(BYTE i=0;i<Count;i++)
{
if(uCards[i]>cards[i])
{
return FALSE;
}
cards[i]-=uCards[i];
}
return TRUE;
}
//检查是否m的相同
BOOL bCheckM(BYTE *cards,BYTE Count,BYTE m)
{
if(m>1)
{
//sortMinToMax(cards,Count);
for(BYTE i=0;i<Count;)
{
for(BYTE j=0;j<m;j++)
{
if(cards[i]!=cards[i+j])
{
return FALSE;
}
}
i+=m;
}
}
return TRUE;
}
/*
获取组合,检查相同数量
*/
void *Combine(BYTE *cards,BYTE Count,BYTE n,BYTE m,BYTE type,BYTE hcard)
{
if(n<1||Count<n||Count>CardsCount)return NULL;
TipsStruct *l=NULL,*p=NULL;
BYTE temp[CardsCount],wei[CardsCount],last=n-1;
//temp = new BYTE[Count];
//wei = new BYTE[Count];
/*
1234556789
方法从1234到6789,末位4逐一移位
遇到5相同
*/
//开始取n张牌开始查找组合
for(INT i=0;i<n;i++)
{
wei[i]=i;
temp[i]=cards[wei[i]];
}
/*
进位直到最后连续组合
遍历末位0123,0124,0125
前位进位0234,0235,判断最后2345结束
*/
while(1)
{
//遍历末位
BOOL bcheck=FALSE;
for(;wei[last]<Count;wei[last]++)
{
//第二次相同继续下一位
if(bcheck && temp[last]==cards[wei[last]])
continue;
bcheck=TRUE;
temp[last]=cards[wei[last]];
//check duizi
if(bCheckM(temp,n,m))
{
if(l==NULL)
{
l=(TipsStruct *)AddTipsStruct(temp,n,type,hcard,NULL);
p=l;
}
else
{
p->next=(TipsStruct *)AddTipsStruct(temp,n,type,hcard,NULL);
p=p->next;
}
}
}
//末位
wei[last]=Count-1;
//从尾到头判断读是否已经连续
BOOL breturn=TRUE;
for(INT j=(last-1);j>=0;j--)
{
if(wei[j]!=(wei[j+1]-1))
{
breturn=FALSE;
wei[j]++;
//进位后复位后面的进入连续
for(INT i=j+1;i<n;i++)
{
wei[i]=wei[i-1]+1;
}
//进位后检测没有变化
BOOL same=TRUE;
for(i=0;i<n;i++)
{
if(i<(n-1) && temp[i]!=cards[wei[i]])
same=FALSE;
temp[i]=cards[wei[i]];
}
//高位都相同继续进位
if(same)
wei[last]=Count;
//继续移位
break;
}
}
//已经移位到最后
if(breturn)break;
}
return l;
}
/*
*/
void *GetCombine(TipsStruct *s,BYTE Count)
{
INT count=Count;
TipsStruct *p=s;
while(p&&count>0)
{
count--;
p=p->next;
}
return p;
}
/*
0->CardMax ALL CARDS
CardMax .. S ID
*/
void UpdateStraightList(TipsStruct *l,TipsStruct *s)
{
TipsStruct *p=l;
while(p)
{
for(INT i=0;i<p->count;i++)
{
p->cards[CardMax+i]=p->cards[i];
}
memset(p->cards,0,CardMax);
for(i=0;i<p->count;i++)
{
TipsStruct *t=(TipsStruct *)GetCombine(s,p->cards[CardMax+i]);
CardsTransform(t->cards,t->count,p->cards,CardMax,0);
}
p=p->next;
}
}
/*
检查cards中是否包含uCards
*/
BOOL CheckContain(BYTE *cards,BYTE *uCards,BYTE Count)
{
for(BYTE i=0;i<Count;i++)
{
if(uCards[i]>cards[i])
{
return FALSE;
}
}
return TRUE;
}
/*
删除无效组合
*/
void *DelValidCombine(BYTE *cards,TipsStruct *l)
{
TipsStruct *p,*pre=NULL;
p=l;
while(p)
{
if(CheckContain(cards,p->cards,Two)==FALSE)
{
//删除
if(pre==NULL)
{
l=p->next;
FreeTipsStruct(p);
p=l;
}
else
{
pre->next=p->next;
FreeTipsStruct(p);
p=pre->next;
}
}
else
{
pre=p;
p=p->next;
}
}
return l;
}
//顺子特别排序,hcard存储了单张数量
//最少的3张,最多三张4个,较少对子
//减少的单张数量
//一个对子,至少2个单张
//减少一个3张至少2个单张
//减少1个炸弹至少3个单张
//综合1234 考虑飞机连对澹?
//评估顺子,连对,还是飞机结果剩余的单张和对子
// 34567 345667 3456667 34566667 对子是用一个多一个单张
// 345666789 3456666789
// 345566778 //消耗对子,保留最长
// 34567 78910JQ 34567 5678910JQ //两个段顺子,一个长顺子
// 3444555666778910QQQQ
// 3444555678 34445556788顺子必须消耗3个单张以上 <2对 <3飞机
//剩余单张是否有顺子
// 34567 8910JQ KA 5-12张
//34567 45678 5 独立对子,重叠对子
//1、王炸
//2、先评估顺子,再评估连对,之后飞机,最后炸弹
//3、之后飞机炸弹配菜,剩余对子和单张
//产生的单张最少,尽量保存炸弹
//去头缩尾,看看有没有对子,3条,炸弹
//如果不要顺子,飞机可不可全部消耗
//单张最小,尽可能多留对子,留大单张
//34556677888999101010 34567 567888999101010 > 556677 34888999 101010
// 3344556667778910 -> 3344556677 678910
// // A A K K K K Q J 10 10 9 8 6 6 6 A A K K K K 10 6 6 6 Q J 10 9 8
// [1] 4 [2] 2 [3] 0 [4] 1
// [1] 1 [2] 1 [3] 0 [4] 1
// K K K Q J J J 10 9 8 6 6 6 6 5 5 4 3 3 3
// [1] 8 [2] 4 [3] 0 [4] 1
// [1] 2 [2] 1 [3] 0 [4] 1
// 2 2 A A K K K K J 5 Q J 10 9 8 7 6 5 4 3
BOOL CmpStraightResult(TipsStruct *t,TipsStruct *p,TipsStruct *pUser)
{
if(t->weight>p->weight)
return TRUE;
else if(t->weight==p->weight
&&t->level<p->level)
return TRUE;
else if(t->weight==p->weight
&&t->level==p->level
&&t->checksum<p->checksum)
return TRUE;
else if(t->weight==p->weight
&&t->level==p->level
&&t->checksum==p->checksum
&&t->hcard>p->hcard)
return TRUE;
else if(t->weight==p->weight
&&t->level==p->level
&&t->checksum==p->checksum
&&t->hcard==p->hcard
&&t->type>p->type)
return TRUE;
return FALSE;
}
/*
获取最好的顺子组合
*/
void *GetBestStraight(BYTE *cards,TipsStruct *pUser)
{
//评估顺子,连对,还是飞机结果剩余的单张和对子
// 345666789 3456666789
// 345566778 //消耗对子,保留最长
// 34567 78910JQ 34567 5678910JQ //两个段顺子,一个长顺子
// 3444555666778910QQQQ
// 3444555678 34445556788顺子必须消耗3个单张以上 <2对 <3飞机
//剩余单张是否有顺子
// 34567 8910JQ KA 5-12张
//34567 45678 5 独立对子,重叠对子
//1、王炸
//2、先评估顺子,再评估连对,之后飞机,最后炸弹
//3、之后飞机炸弹配菜,剩余对子和单张
//产生的单张最少,尽量保存炸弹
//去头缩尾,看看有没有对子,3条,炸弹
//如果不要顺子,飞机可不可全部消耗
TipsStruct *l=NULL,*s=NULL,*p=NULL;
BYTE Cards[CardMax];
memcpy(Cards,cards,CardMax);
//单张最小,尽可能多留对子,留大单张
//34556677888999101010 34567 567888999101010 > 556677 34888999 101010
// 3344556667778910 -> 3344556677 678910
INT Count=GetTypeCount(Cards,CardMax,3)+GetTypeCount(Cards,CardMax,4)*2;
//if(GetTypeCount(Cards,CardMax,1)>Count)
{
//获取所有可能顺子组合
l=(TipsStruct *)GetStraight(Cards);
if(l==NULL)return NULL;
//所有顺子编号0123456
Count=0;
p=l;
while(p)
{
Count++;
p=p->next;
}
BYTE *temp=new BYTE[Count];
for(INT i=0;i<Count;i++)temp[i]=i;
//对编号获取所有组合
for(i=0;i<Count;i++)
{
//最多就4个顺子
if(i<4)
{
s=(TipsStruct *)CombineList(s,(TipsStruct *)Combine(temp,Count,i+1,1,Straight,Three));
}
else break;
}
delete [] temp;
temp=NULL;
if(s)
{
UpdateStraightList(s,l);
s=(TipsStruct *)DelValidCombine(cards,s);
TipsStruct *pBest=NULL,*t;
t=(TipsStruct *)AddTipsStruct(cards,1,Straight,Three,NULL);
UpdateStraightResult(cards,t);
p=s;
while(p)
{
memcpy(Cards,cards,CardMax);
RemoveContain(Cards,p->cards,CardMax);
UpdateStraightResult(Cards,p);
if(pBest==NULL)
{
if(CmpStraightResult(t,p,pUser))
pBest=p;
}
else
{
if(CmpStraightResult(pBest,p,pUser))
pBest=p;
}
p=p->next;
}
if(pBest)
{
l=(TipsStruct *)RetainTips(pBest,l);
}
else
{
FreeTipsList(l);
l=NULL;
}
FreeTipsStruct(t);
FreeTipsList(s);
}
}
return l;
}
/*
检查cards中是否有card存在
*/
BOOL CheckExits(BYTE *cards,BYTE Count,BYTE card)
{
for(BYTE i=0;i<Count;i++)
{
if(cards[i]==card)
{
return TRUE;
}
}
return FALSE;
}
/*
删除小于pUser的牌组合
*/
void *RetainTips(TipsStruct *s,TipsStruct *l)
{
TipsStruct *p,*pre=NULL;
if(s==NULL)return l;
BYTE count=0;
p=l;
while(p)
{
if(CheckExits(s->cards+CardMax,s->count,count)==FALSE)
{
//删除
if(pre==NULL)
{
l=p->next;
FreeTipsStruct(p);
p=l;
}
else
{
pre->next=p->next;
FreeTipsStruct(p);
p=pre->next;
}
}
else
{
pre=p;
p=p->next;
}
count++;
}
return l;
}
/*
从card开始填充Count个连续相同的m进入cards
返回填充的数量;
从cards取多少张牌
n取多少张牌
*/
BYTE CatCards(BYTE *cards,BYTE Count,BYTE *uCards,BYTE uCount,BYTE n)
{
BYTE count=0,m;
for(m=n;m<4;m++)
{
for(BYTE i=0;i<Count;i++)
{
if(cards[i]==m)
{
//对子特殊
if(n==2&&m>n)
{
memset(uCards+count,i,n);
count+=n;
}
else
{
memset(uCards+count,i,m);
count+=m;
}
if(count>=uCount)return uCount;
}
}
}
return count;
}
/*
删除小于pUser的牌组合
*/
void *DelSwatchTips(TipsStruct *l,TipsStruct *pUser)
{
if(pUser==NULL)return l;
TipsStruct *p,*pre=NULL;
p=l;
while(p)
{
if(CheckBigCards(p,pUser)==FALSE)
{
//删除
if(pre==NULL)
{
l=p->next;
FreeTipsStruct(p);
p=l;
}
else
{
pre->next=p->next;
FreeTipsStruct(p);
p=pre->next;
}
}
else
{
pre=p;
p=p->next;
}
}
return l;
}
/*
获取快速组合牌;
1、取王炸
2、取顺子组合
3、取炸弹飞机三张连对
4、给炸弹飞机三张配料
不过应该是不是先取连对特别的策略
//获取连对4455666 445566 6 44666 55
// 4455666 999 445566 6999 or 44666 55999 rule
*/
void *QuickCombine(BYTE *cards,TipsStruct *pUser)
{
BYTE lCards[CardMax],temp[CardsCount],cardstype[CardTypeMax];
BYTE i=0;
memcpy(lCards,cards,CardMax);
memset(cardstype,0,CardTypeMax);
if(pUser==NULL)
{
//牌权检查是否可以一把出完
BYTE hcard,type,Count;
Count=CardsTransform(temp,CardsCount,cards,CardMax,1);
type=CanPop(temp,Count,&hcard);
if(type>None)
{
return AddTipsStruct(temp,Count,type,hcard,NULL);
}
}
TipsStruct *l=NULL,*p=NULL;
//大小2222 AAAA KKKK QQQQ J
//王炸不做单张和配菜,特殊情况需要两次牌权
if(lCards[SJoker]&&lCards[LJoker])
{
temp[0]=SJoker;
temp[1]=LJoker;
p=(TipsStruct *)AddTipsStruct(temp,2,JokerBoom,temp[0],NULL);
p->level=Level9;
l=(TipsStruct *)CombineList(l,p);
cardstype[JokerBoom]++;
lCards[SJoker]=0;
lCards[LJoker]=0;
}
//评估顺子,连对,还是飞机结果剩余的单张和对子
// 345666789 3456666789
// 345566778 //消耗对子,保留最长
// 34567 78910JQ 34567 5678910JQ //两个段顺子,一个长顺子
// 3444555666778910QQQQ
// 3444555678 34445556788顺子必须消耗3个单张以上 <2对 <3飞机
//剩余单张是否有顺子
// 34567 8910JQ KA 5-12张
//34567 45678 5 独立对子,重叠对子
//1、王炸
//2、先评估顺子,再评估连对,之后飞机,最后炸弹
//3、之后飞机炸弹配菜,剩余对子和单张
//产生的单张最少,尽量保存炸弹
//去头缩尾,看看有没有对子,3条,炸弹
//如果不要顺子,飞机可不可全部消耗
//InitCharCard(lCards,CardMax,"2 2 A A K K K K Q J J 10 9 8 7 6 5 5 4 3");
//InitCharCard(lCards,CardMax,"A A K K K K Q J 10 10 9 8 6 6 6");
//InitCharCard(lCards,CardMax,"K K K Q J J J 10 9 8 6 6 6 6 5 5 4 3 3 3");
// A A K K K K Q J 10 10 9 8 6 6 6
// K K K Q J J J 10 9 8 6 6 6 6 5 5 4 3 3 3
// [1] 8 [2] 4 [3] 0 [4] 1
// [1] 2 [2] 1 [3] 0 [4] 1
// 2 2 A A K K K K J 5 Q J 10 9 8 7 6 5 4 3
//排除顺子牌消耗对子最少
p=(TipsStruct *)GetBestStraight(lCards,pUser);
l=(TipsStruct *)CombineList(l,p);
while(p)
{
memset(temp,0,CardMax);
CardsTransform(p->cards,p->count,temp,CardMax,0);
RemoveContain(lCards,temp,CardMax);
p=p->next;
}
// 炸弹
for(i=0;i<SJoker;i++)
{
if(lCards[i]==4)
{
memset(temp,i,4);
p=(TipsStruct *)AddTipsStruct(temp,4,Boom,i,NULL);
p->level=Level8;
l=(TipsStruct *)CombineList(l,p);
cardstype[Boom]++;
lCards[i]=0;
}
}
//飞机
l=(TipsStruct *)CombineList(l,(TipsStruct *)GetCThree(lCards));
// 三张
for(i=0;i<SJoker;i++)
{
if(lCards[i]==3)
{
memset(temp,i,4);
p=(TipsStruct *)AddTipsStruct(temp,3,CThree,i,NULL);
p->level=Level1;
l=(TipsStruct *)CombineList(l,p);
p=(TipsStruct *)AddTipsStruct(temp,1,Single,i,NULL);
p->level=Level7;
l=(TipsStruct *)CombineList(l,p);
p=(TipsStruct *)AddTipsStruct(temp,2,Double,i,NULL);
p->level=Level7;
l=(TipsStruct *)CombineList(l,p);
cardstype[CThree]++;
lCards[i]=0;
}
}
//获取连对4455666 445566 6 44666 55
// 4455666 999 445566 6999 or 44666 55999 rule
p=(TipsStruct *)GetDoubleStraight(lCards);
l=(TipsStruct *)CombineList(l,p);
//排除连对牌
memset(temp,0,CardMax);
while(p)
{
for(BYTE i=0;i<p->count;i++)
{
if(temp[p->cards[i]]==0)
temp[p->cards[i]]=2;
}
p=p->next;
}
RemoveContain(lCards,temp,CardMax);
// 4566678JJJ 45678 66JJJ
//统计剩余的单张和对子
for(i=0;i<CardMax;i++)
{
//单张
if(lCards[i]==1)
cardstype[Single]++;
//对子
if(lCards[i]==2)
cardstype[Double]++;
}
//飞机配菜
p=l;
while(p)
{
if(p->type==CThree)
{
INT count=(p->count/3);
if(CatCards(lCards,CardMax,temp,count,1)>=count)
{
memcpy(temp+count,p->cards,p->count);
count+=p->count;
l=(TipsStruct *)AddTipsStruct(temp,count,ThreeAndOne,p->hcard,l);
//l=(TipsStruct *)CombineList(l,p);
}
count=(p->count*2/3);
if(CatCards(lCards,CardMax,temp,count,2)>=count)
{
memcpy(temp+count,p->cards,p->count);
count+=p->count;
TipsStruct *t;
t=(TipsStruct *)AddTipsStruct(temp,count,ThreeAndTwo,p->hcard,NULL);
t->level=Level1;
l=(TipsStruct *)CombineList(l,t);
}
}
p=p->next;
}
//还有剩余单张
if(cardstype[CThree]>0&&(cardstype[Single]>0||cardstype[Double]>0))
{
//一人一个
p=l;
while(p)
{
if(p->type==CThree&&p->count==3)
{
//先消耗单张
if(cardstype[Single]>0)
{
for(BYTE i=0;i<CardMax;i++)
{
if(lCards[i]==1)
{
memset(temp,i,1);
memcpy(temp+1,p->cards,p->count);
l=(TipsStruct *)AddTipsStruct(temp,4,ThreeAndOne,p->hcard,l);
lCards[i]=0;
cardstype[Single]--;
break;
}
}
}
//再消耗对子
else if(cardstype[Double]>0)
{
for(INT i=0;i<CardMax;i++)
{
if(lCards[i]==2)
{
memset(temp,i,2);
memcpy(temp+2,p->cards,p->count);
l=(TipsStruct *)AddTipsStruct(temp,5,ThreeAndTwo,p->hcard,l);
lCards[i]=0;
cardstype[Double]--;
break;
}
}
}
}
p=p->next;
}
}
//剩下的单张
for(i=0;i<CardMax;i++)
{
if(lCards[i]==1)
{
memset(temp,i,4);
l=(TipsStruct *)AddTipsStruct(temp,1,Single,i,l);
}
}
//剩下的对子
for(i=0;i<CardMax;i++)
{
if(lCards[i]>1)
{
memset(temp,i,4);
p=(TipsStruct *)AddTipsStruct(temp,1,Single,i,NULL);
p->level=Level1;
l=(TipsStruct *)CombineList(l,p);
l=(TipsStruct *)AddTipsStruct(temp,2,Double,i,l);
}
}
if(cardstype[Boom]>0&&(cardstype[Single]>1||cardstype[Double]>0))
{
//一人一个
p=l;
while(p)
{
if(p->type==Boom)
{
//先消耗单张
if(cardstype[Single]>1||cardstype[Double]>0)
{
INT count=4;
memset(temp,p->hcard,count);
for(INT i=0;i<CardMax;i++)
{
if(lCards[i]==1)
{
temp[count++]=i;
lCards[i]=0;
cardstype[Single]--;
if(count==6)
{
TipsStruct * s;
s=(TipsStruct *)AddTipsStruct(temp,6,FourAndTwo,p->hcard,NULL);
s->level=Level1;
l=(TipsStruct *)CombineList(l,s);
break;
}
}
}
if(count<6&&cardstype[Double]>0)
{
for(INT i=0;i<CardMax;i++)
{
if(lCards[i]==2)
{
temp[count++]=i;
temp[count++]=i;
lCards[i]=0;
cardstype[Double]--;
if(count>=6)
{
TipsStruct * s;
s=(TipsStruct *)AddTipsStruct(temp,6,FourAndTwo,p->hcard,NULL);
s->level=Level1;
l=(TipsStruct *)CombineList(l,s);
break;
}
}
}
}
}
//再消耗对子可以有4带2或者优先4带2对尽可能多消耗
if(cardstype[Double]>0)
{
INT count=4;
memset(temp,p->hcard,count);
for(INT i=0;i<CardMax;i++)
{
if(lCards[i]==2)
{
temp[count++]=i;
temp[count++]=i;
lCards[i]=0;
cardstype[Double]--;
if(count==8||cardstype[Double]==0)
{
TipsStruct * s;
if(count==8)
s=(TipsStruct *)AddTipsStruct(temp,8,FourAndFour,p->hcard,NULL);
else
s=(TipsStruct *)AddTipsStruct(temp,6,FourAndTwo,p->hcard,NULL);
s->level=Level1;
l=(TipsStruct *)CombineList(l,s);
break;
}
}
}
}
}
p=p->next;
}
}
//去除小牌
l=(TipsStruct *)DelSwatchTips(l,pUser);
//level 最末尾
UpdateLast(l);
return l;
}
/*
更新根据level排序,后根据拍数量排序
*/
void UpdateLast(TipsStruct *l)
{
TipsStruct *s;
s=l;
while(s)
{
TipsStruct *t=s->next;
while(t)
{
if(t->level<s->level
||(t->level==s->level
&&(s->count<t->count
||(s->count==t->count&&CheckBigCards(s,t)))))
{
ExChange(s,t);
}
t=t->next;
}
s=s->next;
}
}
运行结果:
Tips[0] Alive:D X 2 A K K K Q Q J 10 9 8 7 7 6 5 4 4 3
List:
id,s->count,s->level,s->weight,s->swatch:
1-5-0-0-0:3,4,5,6,7,
2-5-0-0-0:7,8,9,10,J,
3-4-0-1-6:4,K,K,K,
4-2-0-2-9:Q,Q,
5-1-0-1-13:A,
6-1-0-0-15:2,
7-5-1-1-6:Q,Q,K,K,K,
8-3-1-1-6:K,K,K,
9-1-1-4-10:Q,
10-2-7-2-9:K,K,
11-1-7-3-12:K,
12-2-9-0-52:X,D,
END